• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • spellcheck
spellcheckdialog.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries and the Kate part.
2  *
3  * Copyright (C) 2009-2010 by Michel Ludwig <michel.ludwig@kdemail.net>
4  * Copyright (C) 2008 Mirko Stocker <me@misto.ch>
5  * Copyright (C) 2004-2005 Anders Lund <anders@alweb.dk>
6  * Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
7  * Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
8  * Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
9  * Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB. If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "spellcheckdialog.h"
28 #include "spellcheckdialog.moc"
29 
30 #include "katedocument.h"
31 #include "kateglobal.h"
32 #include "kateview.h"
33 #include "spellcheck/spellcheck.h"
34 
35 #include <kaction.h>
36 #include <kactioncollection.h>
37 #include <kicon.h>
38 #include <kstandardaction.h>
39 #include <sonnet/dialog.h>
40 #include <sonnet/backgroundchecker.h>
41 #include <sonnet/speller.h>
42 
43 KateSpellCheckDialog::KateSpellCheckDialog( KateView* view )
44  : QObject( view )
45  , m_view (view)
46  , m_speller (NULL)
47  , m_backgroundChecker(NULL)
48  , m_sonnetDialog(NULL)
49  , m_globalSpellCheckRange(NULL)
50  , m_spellCheckCancelledByUser(false)
51 {
52 }
53 
54 KateSpellCheckDialog::~KateSpellCheckDialog()
55 {
56  delete m_globalSpellCheckRange;
57  delete m_sonnetDialog;
58  delete m_backgroundChecker;
59  delete m_speller;
60 }
61 
62 void KateSpellCheckDialog::createActions( KActionCollection* ac )
63 {
64  ac->addAction( KStandardAction::Spelling, this, SLOT(spellcheck()) );
65 
66  KAction *a = new KAction( i18n("Spelling (from cursor)..."), this);
67  ac->addAction("tools_spelling_from_cursor", a );
68  a->setIcon( KIcon( "tools-check-spelling" ) );
69  a->setWhatsThis(i18n("Check the document's spelling from the cursor and forward"));
70  connect( a, SIGNAL(triggered()), this, SLOT(spellcheckFromCursor()) );
71 
72  m_spellcheckSelection = new KAction( i18n("Spellcheck Selection..."), this );
73  ac->addAction("tools_spelling_selection", m_spellcheckSelection);
74  m_spellcheckSelection->setIcon( KIcon( "tools-check-spelling" ) );
75  m_spellcheckSelection->setWhatsThis(i18n("Check spelling of the selected text"));
76  connect( m_spellcheckSelection, SIGNAL(triggered()), this, SLOT(spellcheckSelection()) );
77 }
78 
79 void KateSpellCheckDialog::updateActions ()
80 {
81  m_spellcheckSelection->setEnabled (m_view->selection ());
82 }
83 
84 void KateSpellCheckDialog::spellcheckFromCursor()
85 {
86  spellcheck( m_view->cursorPosition() );
87 }
88 
89 void KateSpellCheckDialog::spellcheckSelection()
90 {
91  spellcheck( m_view->selectionRange().start(), m_view->selectionRange().end() );
92 }
93 
94 void KateSpellCheckDialog::spellcheck()
95 {
96  spellcheck( KTextEditor::Cursor( 0, 0 ) );
97 }
98 
99 void KateSpellCheckDialog::spellcheck( const KTextEditor::Cursor &from, const KTextEditor::Cursor &to )
100 {
101  KTextEditor::Cursor start = from;
102  KTextEditor::Cursor end = to;
103 
104  if ( end.line() == 0 && end.column() == 0 )
105  {
106  end = m_view->doc()->documentEnd();
107  }
108 
109  if ( !m_speller )
110  {
111  m_speller = new Sonnet::Speller();
112  }
113  m_speller->restore(KGlobal::config().data());
114 
115  if ( !m_backgroundChecker )
116  {
117  m_backgroundChecker = new Sonnet::BackgroundChecker(*m_speller);
118  }
119 
120  m_backgroundChecker->restore(KGlobal::config().data());
121 
122  if ( !m_sonnetDialog )
123  {
124  m_sonnetDialog = new Sonnet::Dialog(m_backgroundChecker, m_view);
125  m_sonnetDialog->showProgressDialog(200);
126  m_sonnetDialog->showSpellCheckCompletionMessage();
127  m_sonnetDialog->setSpellCheckContinuedAfterReplacement(false);
128 
129  connect(m_sonnetDialog,SIGNAL(done(QString)),this,SLOT(installNextSpellCheckRange()));
130 
131  connect(m_sonnetDialog,SIGNAL(replace(QString,int,QString)),
132  this,SLOT(corrected(QString,int,QString)));
133 
134  connect(m_sonnetDialog,SIGNAL(misspelling(QString,int)),
135  this,SLOT(misspelling(QString,int)));
136 
137  connect(m_sonnetDialog,SIGNAL(cancel()),
138  this,SLOT(cancelClicked()));
139 
140  connect(m_sonnetDialog,SIGNAL(destroyed(QObject*)),
141  this,SLOT(objectDestroyed(QObject*)));
142 
143  connect(m_sonnetDialog,SIGNAL(languageChanged(QString)),
144  this,SLOT(languageChanged(QString)));
145  }
146 
147  m_userSpellCheckLanguage.clear();
148  m_previousGivenSpellCheckLanguage.clear();
149  delete m_globalSpellCheckRange;
150  // we expand to handle the situation when the last word in the range is replace by a new one
151  m_globalSpellCheckRange = m_view->doc()->newMovingRange (KTextEditor::Range( start, end ),
152  KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight);
153  m_spellCheckCancelledByUser = false;
154  performSpellCheck( *m_globalSpellCheckRange );
155 }
156 
157 KTextEditor::Cursor KateSpellCheckDialog::locatePosition( int pos )
158 {
159  uint remains;
160 
161  while ( m_spellLastPos < (uint)pos )
162  {
163  remains = pos - m_spellLastPos;
164  uint l = m_view->doc()->lineLength( m_spellPosCursor.line() ) - m_spellPosCursor.column();
165  if ( l > remains )
166  {
167  m_spellPosCursor.setColumn( m_spellPosCursor.column() + remains );
168  m_spellLastPos = pos;
169  }
170  else
171  {
172  m_spellPosCursor.setLine( m_spellPosCursor.line() + 1 );
173  m_spellPosCursor.setColumn(0);
174  m_spellLastPos += l + 1;
175  }
176  }
177 
178  return m_spellPosCursor;
179 }
180 
181 void KateSpellCheckDialog::misspelling( const QString& word, int pos )
182 {
183  KTextEditor::Cursor cursor;
184  int length;
185  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );
186  cursor = locatePosition( origPos );
187  length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
188  - origPos;
189 
190  m_view->setCursorPositionInternal (cursor, 1);
191  m_view->setSelection( KTextEditor::Range(cursor, length) );
192 }
193 
194 void KateSpellCheckDialog::corrected( const QString& word, int pos, const QString& newWord )
195 {
196  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );
197 
198  int length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
199  - origPos;
200 
201  KTextEditor::Cursor replacementStartCursor = locatePosition( origPos );
202  KTextEditor::Range replacementRange = KTextEditor::Range( replacementStartCursor, length );
203  KateDocument *doc = m_view->doc();
204  KateGlobal::self()->spellCheckManager()->replaceCharactersEncodedIfNecessary( newWord, doc, replacementRange );
205 
206  m_currentSpellCheckRange.setRange( KTextEditor::Range( replacementStartCursor, m_currentSpellCheckRange.end() ) );
207  // we have to be careful here: due to static word wrapping the text might change in addition to simply
208  // the misspelled word being replaced, i.e. new line breaks might be inserted as well. As such, the text
209  // in the 'Sonnet::Dialog' might be eventually out of sync with the visible text. Therefore, we 'restart'
210  // spell checking from the current position.
211  performSpellCheck( KTextEditor::Range( replacementStartCursor, m_globalSpellCheckRange->end() ) );
212 }
213 
214 void KateSpellCheckDialog::performSpellCheck(const KTextEditor::Range& range)
215 {
216  if(range.isEmpty()) {
217  spellCheckDone();
218  }
219  m_languagesInSpellCheckRange = KateGlobal::self()->spellCheckManager()->spellCheckLanguageRanges(m_view->doc(), range);
220  m_currentLanguageRangeIterator = m_languagesInSpellCheckRange.begin();
221  m_currentSpellCheckRange = KTextEditor::Range::invalid();
222  installNextSpellCheckRange();
223  // first check if there is really something to spell check
224  if(m_currentSpellCheckRange.isValid()) {
225  m_sonnetDialog->show();
226  }
227 }
228 
229 void KateSpellCheckDialog::installNextSpellCheckRange()
230 {
231  if ( m_spellCheckCancelledByUser
232  || m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
233  {
234  spellCheckDone();
235  return;
236  }
237  KateSpellCheckManager *spellCheckManager = KateGlobal::self()->spellCheckManager();
238  KTextEditor::Cursor nextRangeBegin = (m_currentSpellCheckRange.isValid() ? m_currentSpellCheckRange.end()
239  : KTextEditor::Cursor::invalid());
240  m_currentSpellCheckRange = KTextEditor::Range::invalid();
241  m_currentDecToEncOffsetList.clear();
242  QList<QPair<KTextEditor::Range, QString> > rangeDictionaryPairList;
243  while ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
244  {
245  const KTextEditor::Range& currentLanguageRange = (*m_currentLanguageRangeIterator).first;
246  const QString& dictionary = (*m_currentLanguageRangeIterator).second;
247  KTextEditor::Range languageSubRange = (nextRangeBegin.isValid() ? KTextEditor::Range(nextRangeBegin, currentLanguageRange.end())
248  : currentLanguageRange);
249  rangeDictionaryPairList = spellCheckManager->spellCheckWrtHighlightingRanges(m_view->doc(),
250  languageSubRange,
251  dictionary,
252  false, true);
253  Q_ASSERT(rangeDictionaryPairList.size() <= 1);
254  if(rangeDictionaryPairList.size() == 0) {
255  ++m_currentLanguageRangeIterator;
256  if ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
257  {
258  nextRangeBegin = (*m_currentLanguageRangeIterator).first.start();
259  }
260  }
261  else {
262  m_currentSpellCheckRange = rangeDictionaryPairList.first().first;
263  QString dictionary = rangeDictionaryPairList.first().second;
264  const bool languageChanged = (dictionary != m_previousGivenSpellCheckLanguage);
265  m_previousGivenSpellCheckLanguage = dictionary;
266 
267  // if there was no change of dictionary stemming from the document language ranges and
268  // the user has set a dictionary in the dialog, we use that one
269  if(!languageChanged && !m_userSpellCheckLanguage.isEmpty()) {
270  dictionary = m_userSpellCheckLanguage;
271  }
272  // we only allow the user to override the preset dictionary within a language range
273  // given by the document
274  else if(languageChanged) {
275  m_userSpellCheckLanguage.clear();
276  }
277 
278  m_spellPosCursor = m_currentSpellCheckRange.start();
279  m_spellLastPos = 0;
280 
281  m_currentDecToEncOffsetList.clear();
282  KateDocument::OffsetList encToDecOffsetList;
283  QString text = m_view->doc()->decodeCharacters(m_currentSpellCheckRange,
284  m_currentDecToEncOffsetList,
285  encToDecOffsetList);
286  // ensure that no empty string is passed on to Sonnet as this can lead to a crash
287  // (bug 228789)
288  if(text.isEmpty()) {
289  nextRangeBegin = m_currentSpellCheckRange.end();
290  continue;
291  }
292 
293  if(m_speller->language() != dictionary) {
294  m_speller->setLanguage(dictionary);
295  m_backgroundChecker->setSpeller(*m_speller);
296  }
297 
298  m_sonnetDialog->setBuffer(text);
299  break;
300  }
301  }
302  if ( m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
303  {
304  spellCheckDone();
305  return;
306  }
307 }
308 
309 void KateSpellCheckDialog::cancelClicked()
310 {
311  m_spellCheckCancelledByUser = true;
312 }
313 
314 void KateSpellCheckDialog::spellCheckDone()
315 {
316  m_currentSpellCheckRange = KTextEditor::Range::invalid();
317  m_currentDecToEncOffsetList.clear();
318  m_view->clearSelection();
319 }
320 
321 void KateSpellCheckDialog::objectDestroyed(QObject *object)
322 {
323  Q_UNUSED(object);
324  m_sonnetDialog = NULL;
325 }
326 
327 void KateSpellCheckDialog::languageChanged(const QString &language)
328 {
329  m_userSpellCheckLanguage = language;
330 }
331 
332 //END
333 
334 
335 // kate: space-indent on; indent-width 2; replace-tabs on;
QList::clear
void clear()
KateGlobal::spellCheckManager
KateSpellCheckManager * spellCheckManager()
spell check manager
Definition: kateglobal.h:345
KateSpellCheckDialog::updateActions
void updateActions()
Definition: spellcheckdialog.cpp:79
KateSpellCheckDialog::KateSpellCheckDialog
KateSpellCheckDialog(KateView *)
Definition: spellcheckdialog.cpp:43
kateview.h
Kate::Script::i18n
QScriptValue i18n(QScriptContext *context, QScriptEngine *engine)
i18n("text", arguments [optional])
Definition: katescripthelpers.cpp:186
KateDocument::computePositionWrtOffsets
int computePositionWrtOffsets(const OffsetList &offsetList, int pos)
Definition: katedocument.cpp:5248
KateView::clearSelection
bool clearSelection()
Definition: kateview.cpp:1991
KateDocument::newMovingRange
virtual KTextEditor::MovingRange * newMovingRange(const KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors=KTextEditor::MovingRange::DoNotExpand, KTextEditor::MovingRange::EmptyBehavior emptyBehavior=KTextEditor::MovingRange::AllowEmpty)
Create a new moving range for this document.
Definition: katedocument.cpp:4741
spellcheckdialog.h
KateDocument::lineLength
virtual int lineLength(int line) const
Definition: katedocument.cpp:758
katedocument.h
KateGlobal::self
static KateGlobal * self()
Kate Part Internal stuff ;)
Definition: kateglobal.cpp:465
spellcheck.h
KateSpellCheckManager::spellCheckLanguageRanges
QList< QPair< KTextEditor::Range, QString > > spellCheckLanguageRanges(KateDocument *doc, const KTextEditor::Range &range)
Definition: spellcheck.cpp:92
QList::size
int size() const
KateSpellCheckDialog::createActions
void createActions(KActionCollection *)
Definition: spellcheckdialog.cpp:62
QString::clear
void clear()
KateView::selectionRange
virtual const KTextEditor::Range & selectionRange() const
Definition: kateview.cpp:2815
KateDocument::decodeCharacters
QString decodeCharacters(const KTextEditor::Range &range, KateDocument::OffsetList &decToEncOffsetList, KateDocument::OffsetList &encToDecOffsetList)
The first OffsetList is from decoded to encoded, and the second OffsetList from encoded to decoded...
Definition: katedocument.cpp:5260
KateView::setSelection
virtual bool setSelection(const KTextEditor::Range &selection)
Definition: kateview.cpp:1956
QObject
kateglobal.h
QString::isEmpty
bool isEmpty() const
KateSpellCheckDialog::~KateSpellCheckDialog
~KateSpellCheckDialog()
Definition: spellcheckdialog.cpp:54
KateDocument::documentEnd
virtual KTextEditor::Cursor documentEnd() const
Definition: katedocument.cpp:4681
KateSpellCheckManager
Definition: spellcheck.h:36
QList::first
T & first()
QString
QList
KateView::selection
virtual bool selection() const
Definition: kateview.cpp:2033
KateView
Definition: kateview.h:77
QList::end
iterator end()
KateDocument
Definition: katedocument.h:74
KateView::cursorPosition
KTextEditor::Cursor cursorPosition() const
Definition: kateview.cpp:2423
KAction
QString::length
int length() const
KateView::doc
KateDocument * doc()
accessor to katedocument pointer
Definition: kateview.h:553
KateSpellCheckManager::spellCheckWrtHighlightingRanges
QList< QPair< KTextEditor::Range, QString > > spellCheckWrtHighlightingRanges(KateDocument *doc, const KTextEditor::Range &range, const QString &dictionary=QString(), bool singleLine=false, bool returnSingleRange=false)
Definition: spellcheck.cpp:129
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KateView::setCursorPositionInternal
bool setCursorPositionInternal(const KTextEditor::Cursor &position, uint tabwidth=1, bool calledExternally=false)
Definition: kateview.cpp:1293
QList::begin
iterator begin()
QObject::destroyed
void destroyed(QObject *obj)
KateSpellCheckManager::replaceCharactersEncodedIfNecessary
void replaceCharactersEncodedIfNecessary(const QString &newWord, KateDocument *doc, const KTextEditor::Range &replacementRange)
Definition: spellcheck.cpp:239
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:59 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

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

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal