From f3403971efbfd72c8a59eb1957292cf534f1233b Mon Sep 17 00:00:00 2001 From: craig Date: Thu, 12 Apr 2012 21:33:03 +0000 Subject: Add hunspell based spell checker - not enabled, backup only for now, not enabled in the build git-svn-id: svn://scribus.net/branches/Version14x/Scribus@17437 11d20701-8431-0410-a711-e3c959e3b870 --- scribus/plugins/tools/CMakeLists.txt | 3 + scribus/plugins/tools/hunspellcheck/CMakeLists.txt | 46 ++++ .../plugins/tools/hunspellcheck/hunspelldialog.cpp | 143 ++++++++++++ .../plugins/tools/hunspellcheck/hunspelldialog.h | 47 ++++ .../tools/hunspellcheck/hunspelldialogbase.ui | 205 +++++++++++++++++ .../plugins/tools/hunspellcheck/hunspellplugin.cpp | 95 ++++++++ .../plugins/tools/hunspellcheck/hunspellplugin.h | 40 ++++ .../tools/hunspellcheck/hunspellpluginimpl.cpp | 251 +++++++++++++++++++++ .../tools/hunspellcheck/hunspellpluginimpl.h | 48 ++++ .../tools/hunspellcheck/hunspellpluginstructs.h | 16 ++ 10 files changed, 894 insertions(+) create mode 100644 scribus/plugins/tools/hunspellcheck/CMakeLists.txt create mode 100644 scribus/plugins/tools/hunspellcheck/hunspelldialog.cpp create mode 100644 scribus/plugins/tools/hunspellcheck/hunspelldialog.h create mode 100644 scribus/plugins/tools/hunspellcheck/hunspelldialogbase.ui create mode 100644 scribus/plugins/tools/hunspellcheck/hunspellplugin.cpp create mode 100644 scribus/plugins/tools/hunspellcheck/hunspellplugin.h create mode 100644 scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.cpp create mode 100644 scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.h create mode 100644 scribus/plugins/tools/hunspellcheck/hunspellpluginstructs.h (limited to 'scribus/plugins') diff --git a/scribus/plugins/tools/CMakeLists.txt b/scribus/plugins/tools/CMakeLists.txt index 16805ec..979354e 100644 --- a/scribus/plugins/tools/CMakeLists.txt +++ b/scribus/plugins/tools/CMakeLists.txt @@ -9,4 +9,7 @@ ADD_SUBDIRECTORY(subdivide) if (HAVE_ASPELL) ADD_SUBDIRECTORY(spellcheck) endif (HAVE_ASPELL) +if (HAVE_HUNSPELL) + ADD_SUBDIRECTORY(hunspellcheck) +endif (HAVE_HUNSPELL) ADD_SUBDIRECTORY(transform) diff --git a/scribus/plugins/tools/hunspellcheck/CMakeLists.txt b/scribus/plugins/tools/hunspellcheck/CMakeLists.txt new file mode 100644 index 0000000..4d1129c --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/CMakeLists.txt @@ -0,0 +1,46 @@ + + INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/scribus + ${HUNSPELL_INCLUDE_DIR} + ) + + SET(HUNSPELL_PLUGIN_UI_SRC + hunspelldialogbase.ui + ) + + SET(HUNSPELL_PLUGIN_MOC_CLASSES + hunspelldialog.h + hunspellplugin.h + hunspellpluginimpl.h + ) + + SET(HUNSPELL_PLUGIN_SOURCES + hunspelldialog.cpp + hunspellplugin.cpp + hunspellpluginimpl.cpp + ) + + SET(SCRIBUS_HUNSPELL_PLUGIN "hunspellplugin") + + QT4_WRAP_UI(HUNSPELL_PLUGIN_UI_SOURCES ${HUNSPELL_PLUGIN_UI_SRC} ) + QT4_WRAP_CPP(HUNSPELL_PLUGIN_MOC_SOURCES ${HUNSPELL_PLUGIN_MOC_CLASSES}) + + ADD_LIBRARY(${SCRIBUS_HUNSPELL_PLUGIN} MODULE + ${HUNSPELL_PLUGIN_SOURCES} + ${HUNSPELL_PLUGIN_MOC_SOURCES} + ${HUNSPELL_PLUGIN_UI_SOURCES} + ) + + TARGET_LINK_LIBRARIES(${SCRIBUS_HUNSPELL_PLUGIN} ${HUNSPELL_LIBRARIES} ${PLUGIN_LIBRARIES}) + + INSTALL(TARGETS ${SCRIBUS_HUNSPELL_PLUGIN} + LIBRARY + DESTINATION ${PLUGINDIR} + PERMISSIONS ${PLUGIN_PERMISSIONS} + ) + + ADD_DEPENDENCIES(${SCRIBUS_HUNSPELL_PLUGIN} ${EXE_NAME}) + +# SET_TARGET_PROPERTIES(${SCRIBUS_ASPELL_PLUGIN} PROPERTIES VERSION "0.0.1") + diff --git a/scribus/plugins/tools/hunspellcheck/hunspelldialog.cpp b/scribus/plugins/tools/hunspellcheck/hunspelldialog.cpp new file mode 100644 index 0000000..4d589e3 --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspelldialog.cpp @@ -0,0 +1,143 @@ +/* +For general Scribus (>=1.3.2) copyright and licensing information please refer +to the COPYING file provided with the program. Following this notice may exist +a copyright and/or license notice that predates the release of Scribus 1.3.2 +for which a new license (GPL+exception) is in place. +*/ + +#include +#include +#include +#include "hunspelldialog.h" + + +HunspellDialog::HunspellDialog(QWidget *parent, ScribusDoc *doc, PageItem *frameToCheck) +{ + setupUi( this ); + setModal( true ); + + connect (ignoreOncePushButton, SIGNAL(clicked()), this, SLOT(goToNextWord())); + connect (ignoreAllPushButton, SIGNAL(clicked()), this, SLOT(ignoreAllWords())); + connect (changePushButton, SIGNAL(clicked()), this, SLOT(changeWord())); + connect (changeAllPushButton, SIGNAL(clicked()), this, SLOT(changeAllWords())); + + m_doc=doc; + m_docChanged=false; + fTC=frameToCheck; + changeOffset=0; +} + +void HunspellDialog::set(QStringList *dictEntries, Hunspell **hspellers, QList *wfList) +{ + m_dictEntries=dictEntries; + m_hspellers=hspellers; + m_wfList=wfList; + + languagesComboBox->addItems(*dictEntries); + + wfListIndex=0; + goToNextWord(0); +} + +void HunspellDialog::goToNextWord(int i) +{ + if (i>=0) + wfListIndex=i; + else + ++wfListIndex; + if (wfListIndex>=m_wfList->count()) + { + statusLabel->setText(tr("Spelling check complete")); + suggestionsListWidget->clear(); + sentenceTextEdit->clear(); + changePushButton->setEnabled(false); + changeAllPushButton->setEnabled(false); + return; + } + else + statusLabel->setText(""); + currWF=m_wfList->at(wfListIndex); + suggestionsListWidget->clear(); + suggestionsListWidget->addItems(currWF.replacements); + suggestionsListWidget->setCurrentRow(0); + StoryText *iText=&fTC->itemText; + int sentencePos=qMax(0,iText->prevSentence(currWF.start)); + sentencePos=qMax(sentencePos, iText->nextWord(sentencePos)); + int nextSentencePos=qMin(iText->length(), iText->nextSentence(currWF.end)); + QString sentence=iText->text(sentencePos, nextSentencePos-sentencePos); + sentence.insert(currWF.end-sentencePos+changeOffset,""); + sentence.insert(currWF.start-sentencePos+changeOffset,""); + sentenceTextEdit->setText(sentence); + +} + +void HunspellDialog::ignoreAllWords() +{ + QString wordToIgnore=m_wfList->at(wfListIndex).w; + //Do we start from 0 or from the instance of the word where we are... 0 for now + for(int i=0;icount();++i) + if(m_wfList->at(i).w==wordToIgnore) + m_wfList->value(i).ignore=true; + goToNextWord(); +} + +void HunspellDialog::changeWord() +{ + //If we have ignored a word, skip to the next. + if(m_wfList->at(wfListIndex).ignore && !m_wfList->at(wfListIndex).changed) + goToNextWord(); + replaceWord(wfListIndex); + m_docChanged=true; + goToNextWord(); +} + +void HunspellDialog::changeAllWords() +{ + if(m_wfList->at(wfListIndex).ignore && !m_wfList->at(wfListIndex).changed) + return; + QString wordToChange=m_wfList->at(wfListIndex).w; + //Do we start from 0 or from the instance of the word where we are... 0 for now + for(int i=0;icount();++i) + if(m_wfList->at(i).w==wordToChange) + { + m_wfList->value(i).changed=true; + } + m_docChanged=true; + goToNextWord(); +} + +void HunspellDialog::replaceWord(int i) +{ + StoryText *iText=&fTC->itemText; + currWF=m_wfList->at(i); + m_wfList->value(i).changed=true; + QString newText(suggestionsListWidget->currentItem()->text()); + if (newText.length()==currWF.w.length()) + { + for (int i = 0; i < currWF.w.length(); ++i) + iText->replaceChar(currWF.start+i+changeOffset, newText[i]); + } + else + { + if (newText.length()>currWF.w.length()) + { + for (int i = 0; i < currWF.w.length(); ++i) + iText->replaceChar(currWF.start+i+changeOffset, newText[i]); + for (int i = currWF.w.length(); i < newText.length(); ++i) + iText->insertChars(currWF.start+i+changeOffset, newText.mid(i,1), true); + int lengthDiff=newText.length()-currWF.w.length(); + changeOffset+=lengthDiff; + qDebug()<<"Change Offset is:"<replaceChar(currWF.start+i+changeOffset, newText[i]); + int lengthDiff=currWF.w.length() - newText.length(); + iText->removeChars(currWF.start+changeOffset+newText.length(), lengthDiff); + changeOffset-=lengthDiff; + qDebug()<<"Change Offset is:"< +#include +#include +#include + +#include + +#include "pluginapi.h" +#include "hunspellpluginstructs.h" +#include "scribusdoc.h" +#include "pageitem.h" + +#include "ui_hunspelldialogbase.h" + +class PLUGIN_API HunspellDialog : public QDialog, private Ui::HunspellDialogBase +{ + Q_OBJECT + + public: + HunspellDialog(QWidget* parent, ScribusDoc *doc, PageItem* frameToCheck); + ~HunspellDialog() {}; + void set(QStringList* dictEntries, Hunspell **hspellers, QList* wfList); + bool docChanged() {return m_docChanged;} + + public slots: + void goToNextWord(int i=-1); + void ignoreAllWords(); + void changeWord(); + void changeAllWords(); + void replaceWord(int i); + + private: + ScribusDoc* m_doc; + PageItem* fTC; + QStringList* m_dictEntries; + Hunspell **m_hspellers; + QList* m_wfList; + WordsFound currWF; + int wfListIndex; + bool m_docChanged; + int changeOffset; +}; + +#endif // HUNSPELLDIALOG_H diff --git a/scribus/plugins/tools/hunspellcheck/hunspelldialogbase.ui b/scribus/plugins/tools/hunspellcheck/hunspelldialogbase.ui new file mode 100644 index 0000000..96f1631 --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspelldialogbase.ui @@ -0,0 +1,205 @@ + + + HunspellDialogBase + + + + 0 + 0 + 687 + 406 + + + + Check Spelling + + + + + + + + Text Language: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Not in dictionary + + + + + + + + + + + + + + Ignore Once + + + + + + + Ignore All + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Suggestions + + + + + + + + + + + + + + Change + + + + + + + Change All + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + HunspellDialogBase + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + HunspellDialogBase + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/scribus/plugins/tools/hunspellcheck/hunspellplugin.cpp b/scribus/plugins/tools/hunspellcheck/hunspellplugin.cpp new file mode 100644 index 0000000..5b089a7 --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspellplugin.cpp @@ -0,0 +1,95 @@ +/* +For general Scribus (>=1.3.2) copyright and licensing information please refer +to the COPYING file provided with the program. Following this notice may exist +a copyright and/or license notice that predates the release of Scribus 1.3.2 +for which a new license (GPL+exception) is in place. +*/ +#include "hunspellplugin.h" +#include "hunspellpluginimpl.h" +#include "scribuscore.h" + +// See scplugin.h and pluginmanager.{cpp,h} for detail on what these methods +// do. That documentatation is not duplicated here. +// Please don't implement the functionality of your plugin here; do that +// in mypluginimpl.h and mypluginimpl.cpp . + +HunspellPlugin::HunspellPlugin() : ScActionPlugin() +{ + // Set action info in languageChange, so we only have to do + // it in one place. + languageChange(); +} + +HunspellPlugin::~HunspellPlugin() {}; + +void HunspellPlugin::languageChange() +{ + // Note that we leave the unused members unset. They'll be initialised + // with their default ctors during construction. + // Action name + m_actionInfo.name = "HunspellPlugin"; + // Action text for menu, including &accel + m_actionInfo.text = tr("Hunspell &Plugin"); + // Menu + m_actionInfo.menu = "Item"; + // If needed, what item to add the menu item after + //m_actionInfo.menuAfterName = "ColorWheel" + // If needed, the keyboard shortcut for the plugin + m_actionInfo.keySequence = "SHIFT+F7"; + // Should the menu item be enabled when the app starts + // (even without a document open) ? + m_actionInfo.enabledOnStartup = false; + m_actionInfo.notSuitableFor.append(PageItem::Line); + m_actionInfo.notSuitableFor.append(PageItem::Polygon); + m_actionInfo.notSuitableFor.append(PageItem::ImageFrame); + m_actionInfo.notSuitableFor.append(PageItem::PathText); + m_actionInfo.notSuitableFor.append(PageItem::LatexFrame); + m_actionInfo.needsNumObjects = 1; +} + +const QString HunspellPlugin::fullTrName() const +{ + return QObject::tr("Hunspell Plugin"); +} + +const ScActionPlugin::AboutData* HunspellPlugin::getAboutData() const +{ + AboutData* about = new AboutData; + Q_CHECK_PTR(about); + return about; +} + +void HunspellPlugin::deleteAboutData(const AboutData* about) const +{ + Q_ASSERT(about); + delete about; +} + +bool HunspellPlugin::run(ScribusDoc* doc, QString target) +{ + HunspellPluginImpl *hunspellPluginImpl = new HunspellPluginImpl(); + Q_CHECK_PTR(hunspellPluginImpl); + bool result = hunspellPluginImpl->run(target, doc); + delete hunspellPluginImpl; + return result; +} + +// Low level plugin API +int hunspellplugin_getPluginAPIVersion() +{ + return PLUGIN_API_VERSION; +} + +ScPlugin* hunspellplugin_getPlugin() +{ + HunspellPlugin* plug = new HunspellPlugin(); + Q_CHECK_PTR(plug); + return plug; +} + +void hunspellplugin_freePlugin(ScPlugin* plugin) +{ + HunspellPlugin* plug = dynamic_cast(plugin); + Q_ASSERT(plug); + delete plug; +} diff --git a/scribus/plugins/tools/hunspellcheck/hunspellplugin.h b/scribus/plugins/tools/hunspellcheck/hunspellplugin.h new file mode 100644 index 0000000..0b89101 --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspellplugin.h @@ -0,0 +1,40 @@ +/* +For general Scribus (>=1.3.2) copyright and licensing information please refer +to the COPYING file provided with the program. Following this notice may exist +a copyright and/or license notice that predates the release of Scribus 1.3.2 +for which a new license (GPL+exception) is in place. +*/ +#ifndef HUNSPELLPLUGIN_H +#define HUNSPELLPLUGIN_H + +#include "pluginapi.h" +#include "scplugin.h" + +/*! \brief See scplugin.h and pluginmanager.{cpp,h} for detail on what these methods do. +That documentatation is not duplicated here. +Please don't implement the functionality of your plugin here; do that +in mypluginimpl.h and mypluginimpl.cpp. */ +class PLUGIN_API HunspellPlugin : public ScActionPlugin +{ + Q_OBJECT + + public: + //! \brief Standard plugin implementation + HunspellPlugin(); + virtual ~HunspellPlugin(); + //! \brief main method to run the plug + virtual bool run(ScribusDoc* doc, QString target = QString::null); + virtual const QString fullTrName() const; + virtual const AboutData* getAboutData() const; + virtual void deleteAboutData(const AboutData* about) const; + virtual void languageChange(); + virtual void addToMainWindowMenu(ScribusMainWindow *) {}; + + // Special features (none) +}; + +extern "C" PLUGIN_API int hunspellplugin_getPluginAPIVersion(); +extern "C" PLUGIN_API ScPlugin* hunspellplugin_getPlugin(); +extern "C" PLUGIN_API void hunspellplugin_freePlugin(ScPlugin* plugin); + +#endif diff --git a/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.cpp b/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.cpp new file mode 100644 index 0000000..7d3c7da --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.cpp @@ -0,0 +1,251 @@ +/* +For general Scribus (>=1.3.2) copyright and licensing information please refer +to the COPYING file provided with the program. Following this notice may exist +a copyright and/or license notice that predates the release of Scribus 1.3.2 +for which a new license (GPL+exception) is in place. +*/ +#include "hunspellpluginimpl.h" +#include "hunspelldialog.h" +#include "pageitem.h" +#include "pageitem_textframe.h" +#include "selection.h" +#include "scribusdoc.h" +#include "scribus.h" +#include "text/specialchars.h" +#include "util.h" + +#include +#include +#include +#include + +#ifdef Q_OS_WIN32 +#include +#include +#endif + + +// Initialize members here, if any +HunspellPluginImpl::HunspellPluginImpl() : QObject(0) +{ + hspellers=NULL; + numDicts=0; +} + +HunspellPluginImpl::~HunspellPluginImpl() +{ + if (hspellers) + { + for (int i = 0; i < numDicts; ++i) + { + delete hspellers[i]; + hspellers[i] = NULL; + } + delete[] hspellers; + } + hspellers = NULL; + numDicts = 0; +} + +bool HunspellPluginImpl::run(const QString & target, ScribusDoc* doc) +{ + m_doc=doc; + bool initOk=initHunspell(); + qDebug()<<"Hunspell Init Ok:"<m_Selection->count(); ++i ) + { + frameToCheck = m_doc->m_Selection->itemAt(i); + parseTextFrame(frameToCheck); + openGUIForTextFrame(frameToCheck); + m_doc->view()->DrawNew(); + } + return true; +} + +bool HunspellPluginImpl::parseTextFrame(PageItem *frameToCheck) +{ + static QString wordBoundaries(" .,:;\"'!?\n"); + + StoryText *iText=&frameToCheck->itemText; + int len=iText->length(); + QString text=iText->text(0,len); +// qDebug()<nextWord(currPos); + currPos=wordPos; + int eoWord=wordPos; + while(eoWord < len) + { + if (iText->text(eoWord).isLetterOrNumber()) + ++eoWord; + else + break; + } + QString word=iText->text(wordPos,eoWord-wordPos); + ++wordCount; + ++wordNo; + QStringList replacements; + if (hspellers[0]->spell(word.toLocal8Bit().constData())==0) + { +// qDebug()<suggest(&sugglist, word.toLocal8Bit().constData()); + for (int j=0; j < suggCount; ++j) + { +// qDebug()<<"Suggestion "<free_list(&sugglist, suggCount); + + struct WordsFound wf; + wf.start=currPos; + wf.end=eoWord; + wf.w=word; + wf.replacements=replacements; + wf.changed=false; + wf.ignore=false; + wordsToCorrect.append(wf); + } + } +// qDebug()<<"Errors found:"<scMW(), m_doc, frameToCheck); + hsDialog.set(&dictEntries, hspellers, &wordsToCorrect); + hsDialog.exec(); + if (hsDialog.docChanged()) + m_doc->changed(); + return true; +} + diff --git a/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.h b/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.h new file mode 100644 index 0000000..d664682 --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspellpluginimpl.h @@ -0,0 +1,48 @@ +/* +For general Scribus (>=1.3.2) copyright and licensing information please refer +to the COPYING file provided with the program. Following this notice may exist +a copyright and/or license notice that predates the release of Scribus 1.3.2 +for which a new license (GPL+exception) is in place. +*/ +#ifndef HUNSPELLPLUGINIMPL_H +#define HUNSPELLPLUGINIMPL_H + +#include +#include "hunspellpluginstructs.h" + +#include +#include +#include + +class QString; +class ScribusDoc; +class PageItem; + + + +class HunspellPluginImpl : public QObject +{ + Q_OBJECT + public: + HunspellPluginImpl(); + ~HunspellPluginImpl(); + bool run(const QString & target, ScribusDoc* doc=0); + bool findDictionaries(); + bool initHunspell(); + bool checkWithHunspell(); + bool parseTextFrame(PageItem *frameToCheck); + bool openGUIForTextFrame(PageItem *frameToCheck); + QList wordsToCorrect; + + protected: + QStringList dictionaryPaths; + QString dictPath, affPath; + int numDicts, numAFFs; + Hunspell **hspellers; + QStringList dictEntries; + QStringList affEntries; + ScribusDoc* m_doc; +}; + +#endif + diff --git a/scribus/plugins/tools/hunspellcheck/hunspellpluginstructs.h b/scribus/plugins/tools/hunspellcheck/hunspellpluginstructs.h new file mode 100644 index 0000000..0515cbb --- /dev/null +++ b/scribus/plugins/tools/hunspellcheck/hunspellpluginstructs.h @@ -0,0 +1,16 @@ +#ifndef HUNSPELLPLUGINSTRUCTS_H +#define HUNSPELLPLUGINSTRUCTS_H + +#include +#include + +struct WordsFound { + int start; + int end; + QString w; + QStringList replacements; + bool changed; + bool ignore; +}; + +#endif // HUNSPELLPLUGINSTRUCTS_H -- cgit