• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

ktextedit.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
00003                  2005 Michael Brade <brade@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "ktextedit.h"
00022 
00023 #include <QApplication>
00024 #include <QClipboard>
00025 #include <QKeyEvent>
00026 #include <QMenu>
00027 #include <QScrollBar>
00028 #include <QTextCursor>
00029 
00030 #include <configdialog.h>
00031 #include <dialog.h>
00032 #include "backgroundchecker.h"
00033 #include <kaction.h>
00034 #include <kcursor.h>
00035 #include <kglobalsettings.h>
00036 #include <kstandardaction.h>
00037 #include <kstandardshortcut.h>
00038 #include <kicon.h>
00039 #include <kiconloader.h>
00040 #include <klocale.h>
00041 #include <kdialog.h>
00042 #include <kreplacedialog.h>
00043 #include <kfinddialog.h>
00044 #include <kfind.h>
00045 #include <kreplace.h>
00046 #include <kmessagebox.h>
00047 #include <kmenu.h>
00048 #include <kwindowsystem.h>
00049 
00050 class KTextEdit::Private
00051 {
00052   public:
00053     Private( KTextEdit *_parent )
00054       : parent( _parent ),
00055         customPalette( false ),
00056         checkSpellingEnabled( false ),
00057         findReplaceEnabled(true),
00058         highlighter( 0 ), findDlg(0),find(0),repDlg(0),replace(0), findIndex(0), repIndex(0)
00059     {
00060     }
00061 
00062     ~Private()
00063     {
00064       delete highlighter;
00065       delete findDlg;
00066       delete find;
00067       delete replace;
00068       delete repDlg;
00069     }
00070 
00076     bool overrideShortcut(const QKeyEvent* e);
00080     bool handleShortcut(const QKeyEvent* e);
00081 
00082     void spellCheckerMisspelling( const QString &text, int pos );
00083     void spellCheckerCorrected( const QString &, int,const QString &);
00084     void spellCheckerAutoCorrect(const QString&,const QString&);
00085     void spellCheckerCanceled();
00086     void spellCheckerFinished();
00087     void toggleAutoSpellCheck();
00088 
00089     void slotFindHighlight(const QString& text, int matchingIndex, int matchingLength);
00090     void slotReplaceText(const QString &text, int replacementIndex, int /*replacedLength*/, int matchedLength);
00091 
00096     void undoableClear();
00097 
00098     void slotAllowTab();
00099     void menuActivated( QAction* action );
00100 
00101     void init();
00102 
00103     KTextEdit *parent;
00104     KTextEditSpellInterface *spellInterface;
00105     QAction *autoSpellCheckAction;
00106     QAction *allowTab;
00107     QAction *spellCheckAction;
00108     bool customPalette : 1;
00109 
00110     bool checkSpellingEnabled : 1;
00111     bool findReplaceEnabled: 1;
00112     QString originalBuffer;
00113     QString spellChechingConfigFileName;
00114     QString spellCheckingLanguage;
00115     Sonnet::Highlighter *highlighter;
00116     KFindDialog *findDlg;
00117     KFind *find;
00118     KReplaceDialog *repDlg;
00119     KReplace *replace;
00120     int findIndex, repIndex;
00121 };
00122 
00123 void KTextEdit::Private::spellCheckerCanceled()
00124 {
00125     parent->selectAll();
00126     parent->setPlainText(originalBuffer);
00127     spellCheckerFinished();
00128 }
00129 
00130 void KTextEdit::Private::spellCheckerAutoCorrect(const QString&,const QString&)
00131 {
00132     //TODO
00133 }
00134 
00135 void KTextEdit::Private::spellCheckerMisspelling( const QString &text, int pos )
00136 {
00137     //kDebug()<<"TextEdit::Private::spellCheckerMisspelling :"<<text<<" pos :"<<pos;
00138     parent->highlightWord( text.length(), pos );
00139 }
00140 
00141 void KTextEdit::Private::spellCheckerCorrected( const QString& oldWord, int pos,const QString& newWord)
00142 {
00143   //kDebug()<<" oldWord :"<<oldWord<<" newWord :"<<newWord<<" pos : "<<pos;
00144   if (oldWord != newWord ) {
00145     QTextCursor cursor(parent->document());
00146     cursor.setPosition(pos);
00147     cursor.setPosition(pos+oldWord.length(),QTextCursor::KeepAnchor);
00148     cursor.insertText(newWord);
00149   }
00150 }
00151 
00152 void KTextEdit::Private::spellCheckerFinished()
00153 {
00154    QTextCursor cursor(parent->document());
00155    cursor.clearSelection();
00156    parent->setTextCursor(cursor);
00157    if (parent->highlighter())
00158        parent->highlighter()->rehighlight();
00159 }
00160 
00161 void KTextEdit::Private::toggleAutoSpellCheck()
00162 {
00163   parent->setCheckSpellingEnabled( !parent->checkSpellingEnabled() );
00164 }
00165 
00166 void KTextEdit::Private::undoableClear()
00167 {
00168     QTextCursor cursor = parent->textCursor();
00169     cursor.beginEditBlock();
00170     cursor.movePosition(QTextCursor::Start);
00171     cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
00172     cursor.removeSelectedText();
00173     cursor.endEditBlock();
00174 }
00175 
00176 void KTextEdit::Private::slotAllowTab()
00177 {
00178   parent->setTabChangesFocus( !parent->tabChangesFocus() );
00179 }
00180 
00181 void KTextEdit::Private::menuActivated( QAction* action )
00182 {
00183   if ( action == spellCheckAction )
00184     parent->checkSpelling();
00185   else if ( action == autoSpellCheckAction )
00186     toggleAutoSpellCheck();
00187   else if ( action == allowTab )
00188     slotAllowTab();
00189 }
00190 
00191 
00192 void KTextEdit::Private::slotFindHighlight(const QString& text, int matchingIndex, int matchingLength)
00193 {
00194     Q_UNUSED(text)
00195     //kDebug() << "Highlight: [" << text << "] mi:" << matchingIndex << " ml:" << matchingLength;
00196     QTextCursor tc = parent->textCursor();
00197     tc.setPosition(matchingIndex);
00198     tc.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, matchingLength);
00199     parent->setTextCursor(tc);
00200     parent->ensureCursorVisible();
00201 }
00202 
00203 
00204 void KTextEdit::Private::slotReplaceText(const QString &text, int replacementIndex, int /*replacedLength*/, int matchedLength) {
00205     Q_UNUSED(text)
00206     //kDebug() << "Replace: [" << text << "] ri:" << replacementIndex << " rl:" << replacedLength << " ml:" << matchedLength;
00207     QTextCursor tc = parent->textCursor();
00208     tc.setPosition(replacementIndex);
00209     tc.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, matchedLength);
00210     tc.removeSelectedText();
00211     tc.insertText(repDlg->replacement());
00212     parent->setTextCursor(tc);
00213     if (replace->options() & KReplaceDialog::PromptOnReplace) {
00214         parent->ensureCursorVisible();
00215     }
00216 }
00217 
00218 void KTextEdit::Private::init()
00219 {
00220     spellInterface = 0;
00221     KCursor::setAutoHideCursor(parent, true, false);
00222     parent->connect(parent, SIGNAL(languageChanged(const QString&)),
00223                     parent, SLOT(setSpellCheckingLanguage(const QString&)));
00224 }
00225 
00226 KTextEdit::KTextEdit( const QString& text, QWidget *parent )
00227   : QTextEdit( text, parent ), d( new Private( this ) )
00228 {
00229   d->init();
00230 }
00231 
00232 KTextEdit::KTextEdit( QWidget *parent )
00233   : QTextEdit( parent ), d( new Private( this ) )
00234 {
00235   d->init();
00236 }
00237 
00238 KTextEdit::~KTextEdit()
00239 {
00240   delete d;
00241 }
00242 
00243 void KTextEdit::setSpellCheckingConfigFileName(const QString &_fileName)
00244 {
00245     d->spellChechingConfigFileName = _fileName;
00246 }
00247 
00248 const QString& KTextEdit::spellCheckingLanguage() const
00249 {
00250     return d->spellCheckingLanguage;
00251 }
00252 
00253 void KTextEdit::setSpellCheckingLanguage(const QString &_language)
00254 {
00255     if (highlighter()) {
00256         highlighter()->setCurrentLanguage(_language);
00257         highlighter()->rehighlight();
00258     }
00259 
00260     if (_language != d->spellCheckingLanguage) {
00261         d->spellCheckingLanguage = _language;
00262         emit languageChanged(_language);
00263     }
00264     else
00265         d->spellCheckingLanguage = _language;
00266 }
00267 
00268 void KTextEdit::showSpellConfigDialog(const QString &configFileName,
00269                                       const QString &windowIcon)
00270 {
00271     KConfig config(configFileName);
00272     Sonnet::ConfigDialog dialog(&config, this);
00273     if (!d->spellCheckingLanguage.isEmpty())
00274         dialog.setLanguage(d->spellCheckingLanguage);
00275     connect(&dialog, SIGNAL(languageChanged(const QString &)),
00276             this, SLOT(setSpellCheckingLanguage(const QString &)));
00277     if (!windowIcon.isEmpty())
00278         dialog.setWindowIcon(KIcon(windowIcon));
00279     dialog.exec();
00280 }
00281 
00282 bool KTextEdit::event(QEvent* ev)
00283 {
00284     if (ev->type() == QEvent::ShortcutOverride) {
00285         QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00286         if (d->overrideShortcut(e)) {
00287             e->accept();
00288             return true;
00289         }
00290     }
00291     return QTextEdit::event(ev);
00292 }
00293 
00294 bool KTextEdit::Private::handleShortcut(const QKeyEvent* event)
00295 {
00296   const int key = event->key() | event->modifiers();
00297 
00298   if ( KStandardShortcut::copy().contains( key ) ) {
00299     parent->copy();
00300     return true;
00301   } else if ( KStandardShortcut::paste().contains( key ) ) {
00302     parent->paste();
00303     return true;
00304   } else if ( KStandardShortcut::cut().contains( key ) ) {
00305     parent->cut();
00306     return true;
00307   } else if ( KStandardShortcut::undo().contains( key ) ) {
00308     parent->document()->undo();
00309     return true;
00310   } else if ( KStandardShortcut::redo().contains( key ) ) {
00311     parent->document()->redo();
00312     return true;
00313   } else if ( KStandardShortcut::deleteWordBack().contains( key ) ) {
00314     parent->deleteWordBack();
00315     return true;
00316   } else if ( KStandardShortcut::deleteWordForward().contains( key ) ) {
00317     parent->deleteWordForward();
00318     return true;
00319   } else if ( KStandardShortcut::backwardWord().contains( key ) ) {
00320     QTextCursor cursor = parent->textCursor();
00321     cursor.movePosition( QTextCursor::PreviousWord );
00322     parent->setTextCursor( cursor );
00323     return true;
00324   } else if ( KStandardShortcut::forwardWord().contains( key ) ) {
00325     QTextCursor cursor = parent->textCursor();
00326     cursor.movePosition( QTextCursor::NextWord );
00327     parent->setTextCursor( cursor );
00328     return true;
00329   } else if ( KStandardShortcut::next().contains( key ) ) {
00330     QTextCursor cursor = parent->textCursor();
00331     int targetY = parent->verticalScrollBar()->value() + parent->viewport()->height();
00332     bool moved = false;
00333     do {
00334       moved = cursor.movePosition( QTextCursor::Down );
00335       parent->setTextCursor( cursor );
00336     } while ( moved && parent->verticalScrollBar()->value() < targetY );
00337     return true;
00338   } else if ( KStandardShortcut::prior().contains( key ) ) {
00339     QTextCursor cursor = parent->textCursor();
00340     int targetY = parent->verticalScrollBar()->value() - parent->viewport()->height();
00341     bool moved = false;
00342     do {
00343       moved = cursor.movePosition( QTextCursor::Up );
00344       parent->setTextCursor( cursor );
00345     } while ( moved && parent->verticalScrollBar()->value() > targetY );
00346     return true;
00347   } else if ( KStandardShortcut::begin().contains( key ) ) {
00348     QTextCursor cursor = parent->textCursor();
00349     cursor.movePosition( QTextCursor::Start );
00350     parent->setTextCursor( cursor );
00351     return true;
00352   } else if ( KStandardShortcut::end().contains( key ) ) {
00353     QTextCursor cursor = parent->textCursor();
00354     cursor.movePosition( QTextCursor::End );
00355     parent->setTextCursor( cursor );
00356     return true;
00357   } else if ( KStandardShortcut::beginningOfLine().contains( key ) ) {
00358     QTextCursor cursor = parent->textCursor();
00359     cursor.movePosition( QTextCursor::StartOfLine );
00360     parent->setTextCursor( cursor );
00361     return true;
00362   } else if ( KStandardShortcut::endOfLine().contains( key ) ) {
00363     QTextCursor cursor = parent->textCursor();
00364     cursor.movePosition( QTextCursor::EndOfLine );
00365     parent->setTextCursor( cursor );
00366     return true;
00367   } else if ( KStandardShortcut::pasteSelection().contains( key ) ) {
00368     QString text = QApplication::clipboard()->text( QClipboard::Selection );
00369     if ( !text.isEmpty() )
00370       parent->insertPlainText( text );  // TODO: check if this is html? (MiB)
00371     return true;
00372   }
00373   return false;
00374 }
00375 
00376 void KTextEdit::deleteWordBack()
00377 {
00378   QTextCursor cursor = textCursor();
00379   cursor.clearSelection();
00380   cursor.movePosition( QTextCursor::PreviousWord, QTextCursor::KeepAnchor );
00381   cursor.removeSelectedText();
00382 }
00383 
00384 void KTextEdit::deleteWordForward()
00385 {
00386   QTextCursor cursor = textCursor();
00387   cursor.clearSelection();
00388   cursor.movePosition( QTextCursor::EndOfWord, QTextCursor::KeepAnchor );
00389   cursor.removeSelectedText();
00390 }
00391 
00392 QMenu *KTextEdit::mousePopupMenu()
00393 {
00394   QMenu *popup = createStandardContextMenu();
00395   if (!popup) return 0;
00396   connect( popup, SIGNAL( triggered ( QAction* ) ),
00397              this, SLOT( menuActivated( QAction* ) ) );
00398 
00399   const bool emptyDocument = document()->isEmpty();
00400   if( !isReadOnly() )
00401   {
00402       QList<QAction *> actionList = popup->actions();
00403       enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs };
00404       QAction *separatorAction = 0L;
00405       int idx = actionList.indexOf( actionList[SelectAllAct] ) + 1;
00406       if ( idx < actionList.count() )
00407           separatorAction = actionList.at( idx );
00408       if ( separatorAction )
00409       {
00410           KAction *clearAllAction = KStandardAction::clear(this, SLOT(undoableClear()), this);
00411           if ( emptyDocument )
00412               clearAllAction->setEnabled( false );
00413           popup->insertAction( separatorAction, clearAllAction );
00414       }
00415   }
00416   KIconTheme::assignIconsToContextMenu( isReadOnly() ? KIconTheme::ReadOnlyText
00417                                           : KIconTheme::TextEditor,
00418                                           popup->actions() );
00419 
00420   if( !isReadOnly() )
00421   {
00422       popup->addSeparator();
00423       d->spellCheckAction = popup->addAction( KIcon( "tools-check-spelling" ),
00424                                               i18n( "Check Spelling..." ) );
00425       if ( emptyDocument )
00426         d->spellCheckAction->setEnabled( false );
00427       d->autoSpellCheckAction = popup->addAction( i18n( "Auto Spell Check" ) );
00428       d->autoSpellCheckAction->setCheckable( true );
00429       d->autoSpellCheckAction->setChecked( checkSpellingEnabled() );
00430       popup->addSeparator();
00431       d->allowTab = popup->addAction( i18n("Allow Tabulations") );
00432       d->allowTab->setCheckable( true );
00433       d->allowTab->setChecked( !tabChangesFocus() );
00434 
00435       if (d->findReplaceEnabled)
00436       {
00437           KAction *findAction = KStandardAction::find( this, SLOT( slotFind() ), this );
00438           KAction *findNextAction = KStandardAction::findNext( this, SLOT( slotFindNext() ), this );
00439           KAction *replaceAction = KStandardAction::replace( this, SLOT( slotReplace() ), this );
00440           if (emptyDocument)
00441           {
00442               findAction->setEnabled(false);
00443               findNextAction->setEnabled(d->find != 0 );
00444               replaceAction->setEnabled(false);
00445           }
00446           popup->addSeparator();
00447           popup->addAction(findAction);
00448           popup->addAction(findNextAction);
00449           popup->addAction(replaceAction);
00450       }
00451   }
00452   return popup;
00453 }
00454 
00455 void KTextEdit::contextMenuEvent(QContextMenuEvent *event)
00456 {
00457     // Obtain the cursor at the mouse position and the current cursor
00458     QTextCursor cursorAtMouse = cursorForPosition(event->pos());
00459     const int mousePos = cursorAtMouse.position();
00460     QTextCursor cursor = textCursor();
00461 
00462     // Check if the user clicked a selected word
00463     const bool selectedWordClicked = cursor.hasSelection() &&
00464                                mousePos >= cursor.selectionStart() &&
00465                                mousePos <= cursor.selectionEnd();
00466 
00467     // Get the word under the (mouse-)cursor and see if it is misspelled.
00468     // Don't include apostrophes at the start/end of the word in the selection.
00469     QTextCursor wordSelectCursor(cursorAtMouse);
00470     wordSelectCursor.clearSelection();
00471     wordSelectCursor.select(QTextCursor::WordUnderCursor);
00472     QString selectedWord = wordSelectCursor.selectedText();
00473 
00474     // Clear the selection again, we re-select it below (without the apostrophes).
00475     wordSelectCursor.movePosition(QTextCursor::PreviousCharacter,
00476                                   QTextCursor::MoveAnchor, selectedWord.size());
00477     if (selectedWord.startsWith('\'') || selectedWord.startsWith('\"')) {
00478         selectedWord = selectedWord.right(selectedWord.size() - 1);
00479         wordSelectCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor);
00480     }
00481     if (selectedWord.endsWith('\'') || selectedWord.endsWith('\"'))
00482         selectedWord.chop(1);
00483     wordSelectCursor.movePosition(QTextCursor::NextCharacter,
00484                                   QTextCursor::KeepAnchor, selectedWord.size());
00485 
00486     const bool wordIsMisspelled = checkSpellingEnabled() &&
00487                             !selectedWord.isEmpty() &&
00488                             highlighter() &&
00489                             highlighter()->isWordMisspelled(selectedWord);
00490 
00491     // If the user clicked a selected word, do nothing.
00492     // If the user clicked somewhere else, move the cursor there.
00493     // If the user clicked on a misspelled word, select that word.
00494     // Same behavior as in OpenOffice Writer.
00495     bool inQuote = false;
00496     if (d->spellInterface &&
00497         !d->spellInterface->shouldBlockBeSpellChecked(cursorAtMouse.block().text()))
00498         inQuote = true;
00499     if (!selectedWordClicked) {
00500         if (wordIsMisspelled && !inQuote)
00501             setTextCursor(wordSelectCursor);
00502         else
00503             setTextCursor(cursorAtMouse);
00504         cursor = textCursor();
00505     }
00506 
00507     // Use standard context menu for already selected words, correctly spelled
00508     // words and words inside quotes.
00509     if (!wordIsMisspelled || selectedWordClicked || inQuote) {
00510         QMenu *popup = mousePopupMenu();
00511         if ( popup ) {
00512             popup->exec( event->globalPos() );
00513             delete popup;
00514         }
00515     }
00516     else {
00517         KMenu suggestions;
00518         KMenu menu;
00519 
00520         //Add the suggestions to the popup menu
00521         QStringList reps = highlighter()->suggestionsForWord(selectedWord);
00522         if (reps.count() > 0) {
00523             for (QStringList::const_iterator it = reps.constBegin(); it != reps.constEnd(); ++it) {
00524                 suggestions.addAction(*it);
00525             }
00526 
00527         }
00528         suggestions.setTitle(i18n("Suggestions"));
00529 
00530         QAction *ignoreAction = menu.addAction(i18n("Ignore"));
00531         QAction *addToDictAction = menu.addAction(i18n("Add to Dictionary"));
00532         QAction *suggestionsAction = menu.addMenu(&suggestions);
00533         if (reps.count() == 0)
00534             suggestionsAction->setEnabled(false);
00535 
00536         //Execute the popup inline
00537         const QAction *selectedAction = menu.exec(event->globalPos());
00538 
00539         if (selectedAction) {
00540             Q_ASSERT(cursor.selectedText() == selectedWord);
00541 
00542             if (selectedAction == ignoreAction) {
00543                 highlighter()->ignoreWord(selectedWord);
00544                 highlighter()->rehighlight();
00545             }
00546             else if (selectedAction == addToDictAction) {
00547                 highlighter()->addWordToDictionary(selectedWord);
00548                 highlighter()->rehighlight();
00549             }
00550 
00551             // Other actions can only be one of the suggested words
00552             else {
00553                 const QString replacement = selectedAction->text();
00554                 Q_ASSERT(reps.contains(replacement));
00555                 cursor.insertText(replacement);
00556                 setTextCursor(cursor);
00557             }
00558         }
00559     }
00560 }
00561 
00562 void KTextEdit::wheelEvent( QWheelEvent *event )
00563 {
00564   if ( KGlobalSettings::wheelMouseZooms() )
00565     QTextEdit::wheelEvent( event );
00566   else // thanks, we don't want to zoom, so skip QTextEdit's impl.
00567     QAbstractScrollArea::wheelEvent( event );
00568 }
00569 
00570 void KTextEdit::createHighlighter()
00571 {
00572     setHighlighter(new Sonnet::Highlighter(this, d->spellChechingConfigFileName));
00573 }
00574 
00575 Sonnet::Highlighter* KTextEdit::highlighter() const
00576 {
00577     return d->highlighter;
00578 }
00579 
00580 void KTextEdit::setHighlighter(Sonnet::Highlighter *_highLighter)
00581 {
00582     delete d->highlighter;
00583     d->highlighter = _highLighter;
00584 }
00585 
00586 void KTextEdit::setCheckSpellingEnabled(bool check)
00587 {
00588     if (d->spellInterface)
00589         d->spellInterface->setSpellCheckingEnabled(check);
00590     else
00591         setCheckSpellingEnabledInternal(check);
00592 }
00593 
00594 void KTextEdit::setCheckSpellingEnabledInternal( bool check )
00595 {
00596   emit checkSpellingChanged( check );
00597   if ( check == d->checkSpellingEnabled )
00598     return;
00599 
00600   // From the above statment we know know that if we're turning checking
00601   // on that we need to create a new highlighter and if we're turning it
00602   // off we should remove the old one.
00603 
00604   d->checkSpellingEnabled = check;
00605     if ( check )
00606     {
00607         if ( hasFocus() ) {
00608             createHighlighter();
00609             if (!spellCheckingLanguage().isEmpty())
00610                 setSpellCheckingLanguage(spellCheckingLanguage());
00611         }
00612     }
00613     else
00614     {
00615         delete d->highlighter;
00616         d->highlighter = 0;
00617     }
00618 }
00619 
00620 void KTextEdit::focusInEvent( QFocusEvent *event )
00621 {
00622   if ( d->checkSpellingEnabled && !isReadOnly() && !d->highlighter )
00623     createHighlighter();
00624 
00625   QTextEdit::focusInEvent( event );
00626 }
00627 
00628 bool KTextEdit::checkSpellingEnabled() const
00629 {
00630     if (d->spellInterface)
00631       return d->spellInterface->isSpellCheckingEnabled();
00632     else
00633       return checkSpellingEnabledInternal();
00634 }
00635 
00636 bool KTextEdit::checkSpellingEnabledInternal() const
00637 {
00638   return d->checkSpellingEnabled;
00639 }
00640 
00641 void KTextEdit::setReadOnly( bool readOnly )
00642 {
00643   if ( !readOnly && hasFocus() && d->checkSpellingEnabled && !d->highlighter )
00644     createHighlighter();
00645 
00646   if ( readOnly == isReadOnly() )
00647     return;
00648 
00649   if ( readOnly ) {
00650     delete d->highlighter;
00651     d->highlighter = 0;
00652 
00653     d->customPalette = testAttribute( Qt::WA_SetPalette );
00654     QPalette p = palette();
00655     QColor color = p.color( QPalette::Disabled, QPalette::Background );
00656     p.setColor( QPalette::Base, color );
00657     p.setColor( QPalette::Background, color );
00658     setPalette( p );
00659   } else {
00660     if ( d->customPalette && testAttribute( Qt::WA_SetPalette ) ) {
00661         QPalette p = palette();
00662         QColor color = p.color( QPalette::Normal, QPalette::Base );
00663         p.setColor( QPalette::Base, color );
00664         p.setColor( QPalette::Background, color );
00665         setPalette( p );
00666     } else
00667         setPalette( QPalette() );
00668   }
00669 
00670   QTextEdit::setReadOnly( readOnly );
00671 }
00672 
00673 void KTextEdit::checkSpelling()
00674 {
00675   if(document()->isEmpty())
00676   {
00677       KMessageBox::information(this, i18n("Nothing to spell check."));
00678       return;
00679   }
00680   Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker(this);
00681   if(!d->spellCheckingLanguage.isEmpty())
00682      backgroundSpellCheck->changeLanguage(d->spellCheckingLanguage);
00683   Sonnet::Dialog *spellDialog = new Sonnet::Dialog(
00684       backgroundSpellCheck, 0);
00685   connect(spellDialog, SIGNAL(replace( const QString&, int,const QString&)),
00686           this, SLOT(spellCheckerCorrected( const QString&, int,const QString&)));
00687   connect(spellDialog, SIGNAL(misspelling( const QString&, int)),
00688           this, SLOT(spellCheckerMisspelling(const QString &,int)));
00689   connect(spellDialog, SIGNAL(autoCorrect(const QString&, const QString&)),
00690           this, SLOT(spellCheckerAutoCorrect(const QString&, const QString&)));
00691   connect(spellDialog, SIGNAL(done(const QString&)),
00692           this, SLOT(spellCheckerFinished()));
00693   connect(spellDialog, SIGNAL(cancel()),
00694           this, SLOT(spellCheckerCanceled()));
00695   connect(spellDialog, SIGNAL(stop()),
00696           this, SLOT(spellCheckerFinished()));
00697   connect(spellDialog, SIGNAL(spellCheckStatus(const QString &)),
00698           this,SIGNAL(spellCheckStatus(const QString &)));
00699   connect(spellDialog, SIGNAL(languageChanged(const QString &)),
00700           this, SIGNAL(languageChanged(const QString &)));
00701   d->originalBuffer = toPlainText();
00702   spellDialog->setBuffer(d->originalBuffer);
00703   spellDialog->show();
00704 }
00705 
00706 void KTextEdit::highlightWord( int length, int pos )
00707 {
00708   QTextCursor cursor(document());
00709   cursor.setPosition(pos);
00710   cursor.setPosition(pos+length,QTextCursor::KeepAnchor);
00711   setTextCursor (cursor);
00712   ensureCursorVisible();
00713 }
00714 
00715 void KTextEdit::replace()
00716 {
00717      if( document()->isEmpty() )  // saves having to track the text changes
00718         return;
00719 
00720     if ( d->repDlg ) {
00721       KWindowSystem::activateWindow( d->repDlg->winId() );
00722     } else {
00723       d->repDlg = new KReplaceDialog(this, 0,
00724                                     QStringList(), QStringList(), false);
00725       connect( d->repDlg, SIGNAL(okClicked()), this, SLOT(slotDoReplace()) );
00726     }
00727     d->repDlg->show();
00728 }
00729 
00730 void KTextEdit::slotDoReplace()
00731 {
00732     if (!d->repDlg) {
00733         // Should really assert()
00734         return;
00735     }
00736 
00737     delete d->replace;
00738     d->replace = new KReplace(d->repDlg->pattern(), d->repDlg->replacement(), d->repDlg->options(), this);
00739     d->repIndex = 0;
00740     if (d->replace->options() & KFind::FromCursor || d->replace->options() & KFind::FindBackwards) {
00741         d->repIndex = textCursor().anchor();
00742     }
00743 
00744     // Connect highlight signal to code which handles highlighting
00745     // of found text.
00746     connect(d->replace, SIGNAL(highlight(const QString &, int, int)),
00747             this, SLOT(slotFindHighlight(const QString &, int, int)));
00748     connect(d->replace, SIGNAL(findNext()), this, SLOT(slotReplaceNext()));
00749     connect(d->replace, SIGNAL(replace(const QString &, int, int, int)),
00750             this, SLOT(slotReplaceText(const QString &, int, int, int)));
00751 
00752     d->repDlg->close();
00753     slotReplaceNext();
00754 }
00755 
00756 
00757 void KTextEdit::slotReplaceNext()
00758 {
00759     if (!d->replace)
00760         return;
00761 
00762     if (!(d->replace->options() & KReplaceDialog::PromptOnReplace))
00763         viewport()->setUpdatesEnabled(false);
00764 
00765     KFind::Result res = KFind::NoMatch;
00766 
00767     if (d->replace->needData())
00768         d->replace->setData(toPlainText(), d->repIndex);
00769     res = d->replace->replace();
00770     if (!(d->replace->options() & KReplaceDialog::PromptOnReplace)) {
00771         viewport()->setUpdatesEnabled(true);
00772         viewport()->update();
00773     }
00774 
00775     if (res == KFind::NoMatch) {
00776         d->replace->displayFinalDialog();
00777         d->replace->disconnect(this);
00778         d->replace->deleteLater(); // we are in a slot connected to m_replace, don't delete it right away
00779         d->replace = 0;
00780         ensureCursorVisible();
00781         //or           if ( m_replace->shouldRestart() ) { reinit (w/o FromCursor) and call slotReplaceNext(); }
00782     } else {
00783         //m_replace->closeReplaceNextDialog();
00784     }
00785 }
00786 
00787 
00788 void KTextEdit::slotDoFind()
00789 {
00790     if (!d->findDlg) {
00791         // Should really assert()
00792         return;
00793     }
00794 
00795     delete d->find;
00796     d->find = new KFind(d->findDlg->pattern(), d->findDlg->options(), this);
00797     d->findIndex = 0;
00798     if (d->find->options() & KFind::FromCursor || d->find->options() & KFind::FindBackwards) {
00799         d->findIndex = textCursor().anchor();
00800     }
00801 
00802     // Connect highlight signal to code which handles highlighting
00803     // of found text.
00804     connect(d->find, SIGNAL(highlight(const QString &, int, int)),
00805             this, SLOT(slotFindHighlight(const QString &, int, int)));
00806     connect(d->find, SIGNAL(findNext()), this, SLOT(slotFindNext()));
00807 
00808     d->findDlg->close();
00809     d->find->closeFindNextDialog();
00810     slotFindNext();
00811 }
00812 
00813 
00814 void KTextEdit::slotFindNext()
00815 {
00816     if (!d->find)
00817         return;
00818 
00819     KFind::Result res = KFind::NoMatch;
00820     if (d->find->needData())
00821         d->find->setData(toPlainText(), d->findIndex);
00822     res = d->find->find();
00823 
00824     if (res == KFind::NoMatch) {
00825         d->find->displayFinalDialog();
00826         d->find->disconnect(this);
00827         d->find->deleteLater(); // we are in a slot connected to m_find, don't delete right away
00828         d->find = 0;
00829         //or           if ( m_find->shouldRestart() ) { reinit (w/o FromCursor) and call slotFindNext(); }
00830     } else {
00831         //m_find->closeFindNextDialog();
00832     }
00833 }
00834 
00835 
00836 void KTextEdit::slotFind()
00837 {
00838     if( document()->isEmpty() )  // saves having to track the text changes
00839         return;
00840 
00841     if ( d->findDlg ) {
00842       KWindowSystem::activateWindow( d->findDlg->winId() );
00843     } else {
00844       d->findDlg = new KFindDialog(this);
00845       connect( d->findDlg, SIGNAL(okClicked()), this, SLOT(slotDoFind()) );
00846     }
00847     d->findDlg->show();
00848 }
00849 
00850 
00851 void KTextEdit::slotReplace()
00852 {
00853     if( document()->isEmpty() )  // saves having to track the text changes
00854         return;
00855 
00856     if ( d->repDlg ) {
00857       KWindowSystem::activateWindow( d->repDlg->winId() );
00858     } else {
00859       d->repDlg = new KReplaceDialog(this, 0,
00860                                     QStringList(), QStringList(), false);
00861       connect( d->repDlg, SIGNAL(okClicked()), this, SLOT(slotDoReplace()) );
00862     }
00863     d->repDlg->show();
00864 }
00865 
00866 void KTextEdit::enableFindReplace( bool enabled )
00867 {
00868     d->findReplaceEnabled = enabled;
00869 }
00870 
00871 void KTextEdit::setSpellInterface(KTextEditSpellInterface *spellInterface)
00872 {
00873     d->spellInterface = spellInterface;
00874 }
00875 
00876 bool KTextEdit::Private::overrideShortcut(const QKeyEvent* event)
00877 {
00878   const int key = event->key() | event->modifiers();
00879 
00880   if ( KStandardShortcut::copy().contains( key ) ) {
00881     return true;
00882   } else if ( KStandardShortcut::paste().contains( key ) ) {
00883     return true;
00884   } else if ( KStandardShortcut::cut().contains( key ) ) {
00885     return true;
00886   } else if ( KStandardShortcut::undo().contains( key ) ) {
00887     return true;
00888   } else if ( KStandardShortcut::redo().contains( key ) ) {
00889     return true;
00890   } else if ( KStandardShortcut::deleteWordBack().contains( key ) ) {
00891     return true;
00892   } else if ( KStandardShortcut::deleteWordForward().contains( key ) ) {
00893     return true;
00894   } else if ( KStandardShortcut::backwardWord().contains( key ) ) {
00895     return true;
00896   } else if ( KStandardShortcut::forwardWord().contains( key ) ) {
00897     return true;
00898   } else if ( KStandardShortcut::next().contains( key ) ) {
00899     return true;
00900   } else if ( KStandardShortcut::prior().contains( key ) ) {
00901     return true;
00902   } else if ( KStandardShortcut::begin().contains( key ) ) {
00903     return true;
00904   } else if ( KStandardShortcut::end().contains( key ) ) {
00905     return true;
00906   } else if ( KStandardShortcut::beginningOfLine().contains( key ) ) {
00907     return true;
00908   } else if ( KStandardShortcut::endOfLine().contains( key ) ) {
00909     return true;
00910   } else if ( KStandardShortcut::pasteSelection().contains( key ) ) {
00911     return true;
00912   } else if (event->modifiers() == Qt::ControlModifier &&
00913             (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) &&
00914               qobject_cast<KDialog*>(parent->window()) ) {
00915     // ignore Ctrl-Return so that KDialogs can close the dialog
00916     return true;
00917   }
00918   return false;
00919 }
00920 
00921 void KTextEdit::keyPressEvent( QKeyEvent *event )
00922 {
00923     if (d->handleShortcut(event)) {
00924         event->accept();
00925     }else if (event->modifiers() == Qt::ControlModifier &&
00926             (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) &&
00927               qobject_cast<KDialog*>(window()) ) {
00928         event->ignore();
00929     } else {
00930         QTextEdit::keyPressEvent(event);
00931     }
00932 }
00933 
00934 #include "ktextedit.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal