Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

aspellpluginimpl.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "aspellpluginimpl.h"
00008 #include "pageitem_textframe.h"
00009 #include "util.h"
00010 #include <QMessageBox>
00011 const char* AspellPluginImpl::kDEF_CONTEXT = "AspellPlugin";
00012 const QString AspellPluginImpl::kDEF_ASPELL_ENTRY =
00013     QString( "en" ) + Speller::Aspell::Suggest::kDICT_DELIM +
00014     QString( "en" ) + Speller::Aspell::Suggest::kDICT_DELIM +
00015     QString( "*" ) + Speller::Aspell::Suggest::kDICT_DELIM +
00016     QString( "60" );  // I.e., en/en/*/60 corresponding to default English dictionary
00017 
00018 // Initialize members here, if any
00019 AspellPluginImpl::AspellPluginImpl(ScribusDoc* doc, QWidget* parent) :
00020     QDialog( parent ), fdoc( doc ), fpos(0), fidx(0)
00021 {
00022     // Constructor.
00023     setupUi( this );
00024     setModal( true );
00025 
00026     rememberedWords.clear();
00027     // Get stored language, jargon, encoding settings
00028     fprefs = PrefsManager::instance()->prefsFile->getPluginContext( kDEF_CONTEXT );
00029     getPreferences();
00030     QString text = tr( "Loaded " ) + (fentry == kDEF_ASPELL_ENTRY ? tr( "default " ) : "") + fentry + tr( " aspell dictionary." );
00031     doc->scMW()->setStatusBarInfoText( text );
00032     try
00033     {
00034         // Deactivate GUI elements in spell-checking tab until an
00035         // aspell dictionary is chosen.
00036         deactivateSpellGUI();
00037 
00038         // Create speller, and get list of available aspell
00039         // dictionaries.
00040         fsuggest = new Speller::Aspell::Suggest( flang.toUtf8().data(), fjargon.toUtf8().data(), fencoding.toUtf8().data() );
00041         Q_CHECK_PTR( fsuggest );
00042 
00043         // Get list of available aspell dictionaries
00044         std::vector<std::string> entries;
00045         fsuggest->listDicts( entries );
00046         for( std::vector<std::string>::const_iterator i = entries.begin(); i != entries.end(); ++i )
00047         {
00048             // FIXME: Handle encodings other than UTF-8.
00049             flistDicts->addItem(i->c_str());
00050         }
00051         setCurrentComboItem(flistDicts, fentry);
00052     }
00053     catch( const std::invalid_argument& err )
00054     {
00055         QString warn = tr( "aspellplugin (AspellPluginImpl::"
00056                    "AspellPluginImpl): Error in aspell "
00057                    "speller configuration." );
00058         qWarning( "%s", warn.toUtf8().data() );
00059     }
00060     catch( const std::runtime_error& err )
00061     {
00062         QString warn = tr( "aspellplugin (AspellPluginImpl::"
00063                    "AspellPluginImpl): Error in creating "
00064                    "aspell speller." );
00065         qWarning( "%s", warn.toUtf8().data() );
00066     }
00067     activateSpellGUI();
00068     parseSelection();
00069 }
00070 //__________________________________________________________________________
00071 AspellPluginImpl::~AspellPluginImpl()
00072 {
00073     // Destructor
00074     try
00075     {
00076         fsuggest->saveLists();
00077     }
00078     catch( const std::runtime_error& err )
00079     {
00080         qWarning( "aspellplugin (AspellPluginImpl::~AspellPlugin"
00081               "Impl): Error in saving aspell word lists." );
00082     }
00083 
00084     delete fsuggest;
00085 }
00086 //__________________________________________________________________________
00087 void AspellPluginImpl::activateSpellGUI()
00088 {
00089     // Activates spell-checking GUI elements in spell-checking
00090     // tab, i.e., everything except combo box at top
00091     fcurrWord->setEnabled( true );
00092     flistReplacements->setEnabled( true );
00093     fchangeBtn->setEnabled( true );
00094     fchangeAllBtn->setEnabled( true );
00095     fskipAllBtn->setEnabled( true );
00096     fskipBtn->setEnabled( true );
00097     faddWordBtn->setEnabled( true );
00098     ftextLabel1->setEnabled( true );
00099     ftextLabel2->setEnabled( true );
00100     ftextLabel3->setEnabled( true );
00101     ftextLabel4->setEnabled( true );
00102     fmisSpelling->setEnabled( true );
00103     flistDicts->setEnabled( true );
00104 }
00105 //__________________________________________________________________________
00106 void AspellPluginImpl::deactivateSpellGUI()
00107 {
00108     // Deactivates spell-checking GUI elements in spell-checking tab,
00109     // i.e., everything except combo box at top
00110     fcurrWord->setEnabled( false );
00111     flistReplacements->setEnabled( false );
00112     fchangeBtn->setEnabled( false );
00113     fchangeAllBtn->setEnabled( false );
00114     fskipAllBtn->setEnabled( false );
00115     fskipBtn->setEnabled( false );
00116     faddWordBtn->setEnabled( false );
00117     ftextLabel1->setEnabled( false );
00118     ftextLabel2->setEnabled( false );
00119     ftextLabel3->setEnabled( false );
00120     ftextLabel4->setEnabled( false );
00121     fmisSpelling->setEnabled( false );
00122     flistDicts->setEnabled( false );
00123 }
00124 //__________________________________________________________________________
00125 void AspellPluginImpl::nextWord()
00126 {
00127     QString wordBoundaries = QString(" .,:;\"'!?\n");
00128     uint len = fFrame->itemText.length();
00129     while (fpos < len && wordBoundaries.indexOf(fFrame->itemText.text(fpos)) >= 0)
00130     {
00131         ++fpos;
00132     }
00133     int pa = fpos;
00134     int pe = 0;
00135     while (fpos < len && wordBoundaries.indexOf(fFrame->itemText.text(fpos)) < 0)
00136     {
00137         ++fpos;
00138     }
00139     pe = fpos;
00140     fcontent = fFrame->itemText.text(pa, pe - pa);
00141     fpos = pa;
00142 }
00143 //__________________________________________________________________________
00144 void AspellPluginImpl::checkText()
00145 {
00146     // Called from parseXXX(), after filling in the currently
00147     // relevant text into 'fcontent'. Handles spell-checking of
00148     // the text.
00149     while (fpos < static_cast<uint>(fFrame->itemText.length()))
00150     {
00151         std::vector<std::string> replacement;
00152         bool status = fsuggest->checkWord(fcontent.toUtf8().data(), replacement);
00153         if (!status)
00154         {
00155             fmisSpelling->setText( fcontent );
00156             fcurrWord->setText( "" );
00157             flistReplacements->clear();
00158             unsigned int idx = 0;
00159             for( std::vector<std::string>::const_iterator i = replacement.begin(); i != replacement.end(); ++i )
00160             {
00161             // FIXME: Handle encodings other than UTF-8.
00162                 QString dict = QString::fromUtf8(i->c_str());
00163                 flistReplacements->insertItem( idx, dict );
00164                 idx++;
00165             }
00166             if( flistReplacements->count() > 0 )
00167             {
00168                 // FIXME: Is this the correct substitute for
00169                 // setSelected()?
00170                 flistReplacements->setCurrentRow( 0 );
00171                 fcurrWord->setText( flistReplacements->currentItem()->text() );
00172             }
00173             if (rememberedWords.contains(fcontent))
00174             {
00175                 QString repl = rememberedWords.value(fcontent);
00176                 int cs, cx;
00177                 if (fcontent.length() == repl.length())
00178                 {
00179                     for (cs = 0; cs < fcontent.length(); ++cs)
00180                         fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00181                 }
00182                 else
00183                 {
00184                     if (fcontent.length() < repl.length())
00185                     {
00186                         for (cs = 0; cs < fcontent.length(); ++cs)
00187                             fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00188                         for (cx = cs; cx < repl.length(); ++cx)
00189                             fFrame->itemText.insertChars(fpos+cx, repl.mid(cx,1), true);
00190                     }
00191                     else
00192                     {
00193                         for (cs = 0; cs < repl.length(); ++cs)
00194                             fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00195                         fFrame->itemText.removeChars(fpos+cs, fcontent.length() - cs);
00196                     }
00197                 }
00198             }
00199             else
00200                 break;
00201         }
00202         fpos += fcontent.length();
00203         nextWord();
00204     }
00205 }
00206 //__________________________________________________________________________
00207 void AspellPluginImpl::spellCheckDone()
00208 {
00209     // Called once all words in the current text, i.e., in 'fcontent'
00210     // have been spell-checked. Pops up an information dialog.
00211     QMessageBox::information(fdoc->scMW(), tr("Spell-Checker"), tr("Spell-checking completed."));
00212     if( fFrame && fFrame->asTextFrame() )
00213         fFrame->asTextFrame()->invalidateLayout();
00214     if( fnchanges.fntot > 0 )
00215     {
00216         fdoc->changed();
00217     }
00218     // Redraw document
00219     fdoc->view()->DrawNew();
00220     QApplication::changeOverrideCursor(Qt::ArrowCursor);
00221 //  QApplication::restoreOverrideCursor();
00222     fdoc->scMW()->setStatusBarInfoText(tr("Spell-checking done." ));
00223     fdoc->scMW()->mainWindowProgressBar->reset();
00224     close();
00225 }
00226 //__________________________________________________________________________
00227 void AspellPluginImpl::on_fcloseBtn_clicked()
00228 {
00229     // Called when the "Close" button is clicked. Makes any pending
00230     // replacements and closes the spell-checking window.
00231     spellCheckDone();  // Also closes spell-checking window.
00232 }
00233 //__________________________________________________________________________
00234 void AspellPluginImpl::on_fchangeBtn_clicked()
00235 {
00236     // Called when the "Change" button is clicked. Replaces the word
00237     // being spell-checked with the current word in text edit box.
00238     // FIXME: Handle encodings other than UTF-8.
00239     QString repl = fcurrWord->text();
00240     int cs, cx;
00241     if (fcontent.length() == repl.length())
00242     {
00243         for (cs = 0; cs < fcontent.length(); ++cs)
00244             fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00245     }
00246     else
00247     {
00248         if (fcontent.length() < repl.length())
00249         {
00250             for (cs = 0; cs < fcontent.length(); ++cs)
00251                 fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00252             for (cx = cs; cx < repl.length(); ++cx)
00253                 fFrame->itemText.insertChars(fpos+cx, repl.mid(cx,1), true);
00254         }
00255         else
00256         {
00257             for (cs = 0; cs < repl.length(); ++cs)
00258                 fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00259             fFrame->itemText.removeChars(fpos+cs, fcontent.length() - cs);
00260         }
00261     }
00262     fpos += fcontent.length();
00263     nextWord();
00264     checkText();
00265 }
00266 //__________________________________________________________________________
00267 void AspellPluginImpl::on_fchangeAllBtn_clicked()
00268 {
00269     // Called when the "Change All" button is clicked. Replaces all
00270     // instances of the word being spell-checked with the current word in
00271     // text edit box.
00272     QString repl = fcurrWord->text();
00273     int cs, cx;
00274     if (fcontent.length() == repl.length())
00275     {
00276         for (cs = 0; cs < fcontent.length(); ++cs)
00277             fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00278     }
00279     else
00280     {
00281         if (fcontent.length() < repl.length())
00282         {
00283             for (cs = 0; cs < fcontent.length(); ++cs)
00284                 fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00285             for (cx = cs; cx < repl.length(); ++cx)
00286                 fFrame->itemText.insertChars(fpos+cx, repl.mid(cx,1), true);
00287         }
00288         else
00289         {
00290             for (cs = 0; cs < repl.length(); ++cs)
00291                 fFrame->itemText.replaceChar(fpos+cs, repl[cs]);
00292             fFrame->itemText.removeChars(fpos+cs, fcontent.length() - cs);
00293         }
00294     }
00295     if (!rememberedWords.contains(fcontent))
00296         rememberedWords.insert(fcontent, repl);
00297     fpos += fcontent.length();
00298     nextWord();  // Go to next word
00299     checkText();
00300 }
00301 //__________________________________________________________________________
00302 void AspellPluginImpl::on_fskipBtn_clicked()
00303 {
00304     // Called when the "Skip" button is clicked. Skips the word currently
00305     // being spell-checked.
00306     fpos += fcontent.length();
00307     nextWord();  // Go to next word
00308     checkText();
00309 }
00310 //__________________________________________________________________________
00311 void AspellPluginImpl::on_fskipAllBtn_clicked()
00312 {
00313     // Called when the "Skip All" button is clicked. Puts the word
00314     // currently being spell-checked into the list of words to be ignored
00315     // for this session.
00316     try
00317     {
00318 #if 0
00319         std::cerr << "on_fskipAllBtn_clicked: Ignoring \"" <<
00320           fwordlist[fidx] << "\"\n";
00321 #endif
00322         fsuggest->ignoreWord( fcontent.toUtf8().data() );
00323     }
00324     catch( const std::runtime_error& err )
00325     {
00326         
00327         QString warn =
00328           tr( "AspellPluginImpl::on_fskipAllBtn_clicked(): Unable "
00329               "to skip all instances of \"" ) + fcontent +
00330           tr(" by adding it to the session list.");
00331         qWarning( "%s", warn.toUtf8().data() );
00332     }
00333     fpos += fcontent.length();
00334     nextWord();  // Go to next word
00335     checkText();
00336 }
00337 //__________________________________________________________________________
00338 void AspellPluginImpl::on_faddWordBtn_clicked()
00339 {
00340     // Called when the "Add word" button is clicked. Adds word to personal
00341     // word list.
00342     try
00343     {
00344         // FIXME: Handle encodings other than UTF-8.
00345         // FIXME: Is this the right replacement for fcurrWord->text()?
00346         fsuggest->addPersonalList( fcurrWord->text().toUtf8().data() );
00347     }
00348     catch( const std::runtime_error& err )
00349     {
00350         QString warn =
00351             tr( "AspellPluginImpl::on_faddWordBtn_clicked(): "
00352                 "Unable to add word to personal list." );
00353         qWarning( "%s", warn.toUtf8().data() );
00354     }
00355 }
00356 //__________________________________________________________________________
00357 void AspellPluginImpl::on_flistReplacements_itemActivated()
00358 {
00359     // Called when an item in the list of replacements is
00360     // selected. Replaces current word in text edit box with the text
00361     // of the selected item. 
00362     fcurrWord->setText( flistReplacements->currentItem()->text() );
00363 }
00364 //__________________________________________________________________________
00365 void AspellPluginImpl::on_flistDicts_activated()
00366 {
00367     // Called when an item in the list of available aspell dictionaries is
00368     // selected, i.e., by double-clicking, or pressing enter. Resets
00369     // aspell configuration to use the selected dictionary.
00370     QString entry = flistDicts->currentText();
00371     QStringList fields = entry.split( Speller::Aspell::Suggest::kDICT_DELIM );
00372     // Ensure that we have at least the right no.of fields.
00373     if( fields.size() == 4 )
00374     {
00375         QString value =
00376             fields[0] + Speller::Aspell::Suggest::kDICT_DELIM +
00377             fields[1] + Speller::Aspell::Suggest::kDICT_DELIM +
00378             fields[2] + Speller::Aspell::Suggest::kDICT_DELIM +
00379             fields[3];
00380         fsuggest->resetConfig( fields[1].toAscii().data(), fields[2].toAscii().data() );
00381         // FIXME: Handle encodings other than UTF-8.
00382         setPreferences( fields[1], fields[2], Speller::Aspell::Suggest::kDEF_ENCODING, value );
00383     }
00384 }
00385 //__________________________________________________________________________
00386 void AspellPluginImpl::getPreferences()
00387 {
00388     // Retrieves user preferences from saved settings. Defaults are
00389     // supplied 
00390     flang = fprefs->get( "lang", Speller::Aspell::Suggest::kDEF_LANG );
00391     fjargon = fprefs->get( "jargon", Speller::Aspell::Suggest::kDEF_JARGON );
00392     // FIXME: Handle encodings other than UTF-8.
00393     fencoding = fprefs->get( "encoding", Speller::Aspell::Suggest::kDEF_ENCODING );
00394     fentry = fprefs->get( "entry", kDEF_ASPELL_ENTRY );
00395 }
00396 //__________________________________________________________________________
00397 void AspellPluginImpl::setPreferences(const QString& lang,
00398                       const QString& jargon,
00399                       const QString& encoding,
00400                       const QString& entry)
00401 {
00402     // Saves user preferences using Scribus preferences manager.
00403     fprefs->set( "lang", lang );
00404     QString val = jargon == Speller::Aspell::Suggest::kEMPTY ? "" : jargon;
00405     fprefs->set( "jargon", val );
00406     fprefs->set( "encoding", encoding );
00407     fprefs->set( "entry", entry );
00408 }
00409 //__________________________________________________________________________
00410 void AspellPluginImpl::languageChange()
00411 {
00412     qWarning( "AspellPluginImpl::languageChange(): Not implemented yet" );
00413 }
00414 //__________________________________________________________________________
00415 void AspellPluginImpl::parseItem()
00416 {
00417     // Parse text in a frame, and spell-check it.
00418     // Process only text frames
00419     if( fFrame && fFrame->asTextFrame() )
00420     {
00421         nextWord();
00422         checkText();
00423     }
00424 }
00425 //__________________________________________________________________________
00426 void AspellPluginImpl::parseSelection()
00427 {
00428     fcontent.truncate( 0 );  // Start with empty string
00429     uint ndocs = fdoc->m_Selection->count();
00430     for( uint i = 0; i < ndocs; ++i )
00431     {
00432         fFrame = fdoc->m_Selection->itemAt( i );
00433         parseItem();
00434     }
00435 }
00436 //__________________________________________________________________________
00437 //@@@@@@@@@@@@@@@@@@@@@@@@@ END OF FILE @@@@@@@@@@@@@@@@@@@@@@@@@
Created with personalized Doxygen. This is documentation for GPL software Scribus - Open Source Desktop Publishing.