1 /************************************************************************
2 **
3 ** Copyright (C) 2015-2021 Kevin B. Hendricks, Stratford Ontario Canada
4 ** Copyright (C) 2012-2013 John Schember <john@nachtimwald.com>
5 ** Copyright (C) 2012-2013 Dave Heiland
6 **
7 ** This file is part of Sigil.
8 **
9 ** Sigil is free software: you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation, either version 3 of the License, or
12 ** (at your option) any later version.
13 **
14 ** Sigil is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with Sigil. If not, see <http://www.gnu.org/licenses/>.
21 **
22 *************************************************************************/
23
24 #include <QtCore/QHashIterator>
25 #include <QtCore/QSignalMapper>
26 #include <QtGui/QContextMenuEvent>
27 #include <QtWidgets/QMessageBox>
28 #include <QtWidgets/QPushButton>
29
30 #include "Dialogs/SpellcheckEditor.h"
31 #include "Misc/CaseInsensitiveItem.h"
32 #include "Misc/NumericItem.h"
33 #include "Misc/SettingsStore.h"
34 #include "Misc/SpellCheck.h"
35 #include "Misc/Utility.h"
36 #include "Misc/HTMLSpellCheckML.h"
37 #include "Misc/Language.h"
38 #include "ResourceObjects/Resource.h"
39
40 static const QString SETTINGS_GROUP = "spellcheck_editor";
41 static const QString SELECTED_DICTIONARY = "selected_dictionary";
42 static const QString SHOW_ALL_WORDS = "show_all_words";
43 static const QString CASE_INSENSITIVE_SORT = "case_insensitive_sort";
44 static const QString SORT_COLUMN = "sort_column";
45 static const QString SORT_ORDER = "sort_order";
46 static const QString FILE_EXTENSION = "ini";
47
SpellcheckEditor(QWidget * parent)48 SpellcheckEditor::SpellcheckEditor(QWidget *parent)
49 :
50 QDialog(parent),
51 m_Book(NULL),
52 m_SpellcheckEditorModel(new QStandardItemModel(this)),
53 m_ContextMenu(new QMenu(this)),
54 m_MultipleSelection(false),
55 m_SelectRow(-1),
56 m_FilterSC(new QShortcut(QKeySequence(tr("f", "Filter")), this)),
57 m_ShowAllSC(new QShortcut(QKeySequence(tr("s", "ShowAllWords")), this)),
58 m_NoCaseSC(new QShortcut(QKeySequence(tr("c", "Case-InsensitiveSort")), this)),
59 m_RefreshSC(new QShortcut(QKeySequence(tr("r", "Refresh")), this))
60 {
61 ui.setupUi(this);
62 ui.FilterText->installEventFilter(this);
63
64 SetupSpellcheckEditorTree();
65 CreateContextMenuActions();
66 ConnectSignalsSlots();
67 UpdateDictionaries();
68 ReadSettings();
69 }
70
~SpellcheckEditor()71 SpellcheckEditor::~SpellcheckEditor()
72 {
73 WriteSettings();
74 }
75
SetBook(QSharedPointer<Book> book)76 void SpellcheckEditor::SetBook(QSharedPointer <Book> book)
77 {
78 m_Book = book;
79 }
80
SetupSpellcheckEditorTree()81 void SpellcheckEditor::SetupSpellcheckEditorTree()
82 {
83 ui.SpellcheckEditorTree->setModel(m_SpellcheckEditorModel);
84 ui.SpellcheckEditorTree->setContextMenuPolicy(Qt::CustomContextMenu);
85 ui.SpellcheckEditorTree->setSortingEnabled(true);
86 ui.SpellcheckEditorTree->setWordWrap(true);
87 ui.SpellcheckEditorTree->setAlternatingRowColors(true);
88 ui.SpellcheckEditorTree->header()->setStretchLastSection(false);
89 }
90
showEvent(QShowEvent * event)91 void SpellcheckEditor::showEvent(QShowEvent *event)
92 {
93 ui.FilterText->clear();
94 Refresh();
95 }
96
eventFilter(QObject * obj,QEvent * event)97 bool SpellcheckEditor::eventFilter(QObject *obj, QEvent *event)
98 {
99 if (obj == ui.FilterText) {
100 if (event->type() == QEvent::KeyPress) {
101 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
102 int key = keyEvent->key();
103
104 if (key == Qt::Key_Down) {
105 ui.SpellcheckEditorTree->setFocus();
106 return true;
107 }
108 }
109 }
110
111 // pass the event on to the parent class
112 return QDialog::eventFilter(obj, event);
113 }
114
toggleShowAllWords()115 void SpellcheckEditor::toggleShowAllWords()
116 {
117 ui.ShowAllWords->click();
118 ui.SpellcheckEditorTree->setFocus();
119 }
120
toggleCaseInsensitiveSort()121 void SpellcheckEditor::toggleCaseInsensitiveSort()
122 {
123 ui.CaseInsensitiveSort->click();
124 ui.SpellcheckEditorTree->setFocus();
125 }
126
SelectedRowsCount()127 int SpellcheckEditor::SelectedRowsCount()
128 {
129 int count = 0;
130
131 if (ui.SpellcheckEditorTree->selectionModel()->hasSelection()) {
132 count = ui.SpellcheckEditorTree->selectionModel()->selectedRows(0).count();
133 }
134
135 return count;
136 }
137
GetSelectedItems()138 QList<QStandardItem *> SpellcheckEditor::GetSelectedItems()
139 {
140 QList<QStandardItem *> selected_items;
141 if (SelectedRowsCount() < 1) {
142 return selected_items;
143 }
144
145 // Shift-click order is top to bottom regardless of starting position
146 // Ctrl-click order is first clicked to last clicked (included shift-clicks stay ordered as is)
147 QModelIndexList selected_indexes = ui.SpellcheckEditorTree->selectionModel()->selectedRows(0);
148 foreach(QModelIndex index, selected_indexes) {
149 selected_items.append(m_SpellcheckEditorModel->itemFromIndex(index));
150 }
151 return selected_items;
152 }
153
Ignore()154 void SpellcheckEditor::Ignore()
155 {
156 if (SelectedRowsCount() < 1) {
157 emit ShowStatusMessageRequest(tr("No words selected."));
158 return;
159 }
160
161 m_MultipleSelection = SelectedRowsCount() > 1;
162
163 SpellCheck *sc = SpellCheck::instance();
164 foreach (QStandardItem *item, GetSelectedItems()) {
165 sc->ignoreWord(HTMLSpellCheckML::textOf(item->text()));
166 MarkSpelledOkay(item->row());
167 }
168
169 if (m_MultipleSelection) {
170 m_MultipleSelection = false;
171 FindSelectedWord();
172 }
173 emit ShowStatusMessageRequest(tr("Ignored word(s)."));
174 emit SpellingHighlightRefreshRequest();
175 }
176
Add()177 void SpellcheckEditor::Add()
178 {
179 if (SelectedRowsCount() < 1) {
180 emit ShowStatusMessageRequest(tr("No words selected."));
181 return;
182 }
183
184 QString dict_name = ui.Dictionaries->currentText();
185 if (dict_name.isEmpty()) {
186 return;
187 }
188
189 m_MultipleSelection = SelectedRowsCount() > 1;
190
191 SpellCheck *sc = SpellCheck::instance();
192 SettingsStore settings;
193 QStringList enabled_dicts = settings.enabledUserDictionaries();
194 bool enabled = false;
195 foreach (QStandardItem *item, GetSelectedItems()) {
196 sc->addToUserDictionary(item->text(), dict_name);
197 if (enabled_dicts.contains(dict_name)) {
198 enabled = true;
199 MarkSpelledOkay(item->row());
200 }
201 }
202
203 if (m_MultipleSelection) {
204 m_MultipleSelection = false;
205 FindSelectedWord();
206 }
207 if (enabled) {
208 emit ShowStatusMessageRequest(tr("Added word(s) to dictionary."));
209 } else {
210 emit ShowStatusMessageRequest(tr("Added word(s) to dictionary. The dictionary is not enabled in Preferences."));
211 }
212 emit SpellingHighlightRefreshRequest();
213 }
214
ChangeAll()215 void SpellcheckEditor::ChangeAll()
216 {
217 QString old_word = GetSelectedWord();
218 if (old_word.isEmpty()) {
219 emit ShowStatusMessageRequest(tr("No words selected."));
220 return;
221 }
222 QString new_word = ui.cbChangeAll->currentText();
223
224 if (new_word.contains("<") || new_word.contains(">") || new_word.contains("&")) {
225 Utility::DisplayStdErrorDialog(tr("The new word cannot contain \"<\", \">\", or \"&\"."));
226 return;
227 }
228
229 m_SelectRow = GetSelectedRow();
230
231 emit UpdateWordRequest(old_word, new_word);
232 }
233
MarkSpelledOkay(int row)234 void SpellcheckEditor::MarkSpelledOkay(int row)
235 {
236 m_SpellcheckEditorModel->invisibleRootItem()->child(row, 2)->setText(tr("No"));
237 if (ui.ShowAllWords->checkState() == Qt::Unchecked) {
238 m_SpellcheckEditorModel->removeRows(row, 1);
239 if (row >= m_SpellcheckEditorModel->rowCount()) {
240 row--;
241 }
242 if (row >= 0) {
243 ui.SpellcheckEditorTree->selectionModel()->clear();
244 QModelIndex index = m_SpellcheckEditorModel->index(row, 0);
245 ui.SpellcheckEditorTree->setCurrentIndex(index);
246 ui.SpellcheckEditorTree->selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
247 }
248 }
249 }
250
CreateModel(int sort_column,Qt::SortOrder sort_order)251 void SpellcheckEditor::CreateModel(int sort_column, Qt::SortOrder sort_order)
252 {
253 m_SpellcheckEditorModel->clear();
254 QStringList header;
255 header.append(tr("Word"));
256 header.append(tr("Count"));
257 header.append(tr("Language"));
258 header.append(tr("Misspelled?"));
259 m_SpellcheckEditorModel->setHorizontalHeaderLabels(header);
260 ui.SpellcheckEditorTree->header()->setSectionResizeMode(0, QHeaderView::Stretch);
261
262 QHash<QString, int> unique_words = m_Book->GetUniqueWordsInHTMLFiles();
263
264 int total_misspelled_words = 0;
265 SpellCheck *sc = SpellCheck::instance();
266 Language *lp = Language::instance();
267
268 QHashIterator<QString, int> i(unique_words);
269 while (i.hasNext()) {
270 i.next();
271 QString lcword = i.key();
272 QString code = HTMLSpellCheckML::langOf(lcword);
273 QString lang = lp->GetLanguageName(code, code);
274 QString word = HTMLSpellCheckML::textOf(lcword);
275 int count = unique_words.value(lcword);
276 bool misspelled = !sc->spell(lcword);
277 if (misspelled) {
278 total_misspelled_words++;
279 }
280
281 if (ui.ShowAllWords->checkState() == Qt::Unchecked && !misspelled) {
282 continue;
283 }
284
285 QList<QStandardItem *> row_items;
286
287 if (ui.CaseInsensitiveSort->checkState() == Qt::Unchecked) {
288 QStandardItem *word_item = new QStandardItem(word);
289 word_item->setData(code);
290 word_item->setEditable(false);
291 row_items << word_item;
292 } else {
293 CaseInsensitiveItem *word_item = new CaseInsensitiveItem();
294 word_item->setText(word);
295 word_item->setData(code);
296 word_item->setEditable(false);
297 row_items << word_item;
298 }
299 NumericItem *count_item = new NumericItem();
300 count_item->setText(QString::number(count));
301 row_items << count_item;
302
303 QStandardItem *lang_item = new QStandardItem(lang);
304 row_items << lang_item;
305
306 QStandardItem *misspelled_item = new QStandardItem();
307 misspelled_item->setEditable(false);
308 if (misspelled) {
309 misspelled_item->setText(tr("Yes"));
310 } else {
311 misspelled_item->setText(tr("No"));
312 }
313 row_items << misspelled_item ;
314
315 m_SpellcheckEditorModel->invisibleRootItem()->appendRow(row_items);
316 }
317
318 ui.SpellcheckEditorTree->resizeColumnToContents(0);
319 ui.SpellcheckEditorTree->resizeColumnToContents(1);
320 ui.SpellcheckEditorTree->resizeColumnToContents(2);
321 ui.SpellcheckEditorTree->resizeColumnToContents(3);
322
323 // Changing the sortIndicator order should not cause the entire wordlist to be regenerated
324 // disconnect(ui.SpellcheckEditorTree->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(Sort(int, Qt::SortOrder)));
325
326 ui.SpellcheckEditorTree->header()->setSortIndicator(sort_column, sort_order);
327
328 // Changing the sortIndicator order should not cause the entire wordlist to be regenerated
329 // connect(ui.SpellcheckEditorTree->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(Sort(int, Qt::SortOrder)));
330
331
332 ui.SpellcheckEditorTree->header()->setToolTip("<table><tr><td>" % tr("Misspelled Words") % ":</td><td style=\"text-align:right;\">" % QString::number(total_misspelled_words) % "</td></tr><tr><td>" % tr("Total Unique Words") % ":</td><td style=\"text-align:right;\">" % QString::number(unique_words.count()) % "</td></tr></table>");
333 }
334
Refresh(int sort_column,Qt::SortOrder sort_order)335 void SpellcheckEditor::Refresh(int sort_column, Qt::SortOrder sort_order)
336 {
337 QApplication::setOverrideCursor(Qt::WaitCursor);
338
339 WriteSettings();
340 CreateModel(sort_column, sort_order);
341 UpdateDictionaries();
342
343 ReadSettings();
344
345 ui.FilterText->setFocus();
346 FilterEditTextChangedSlot(ui.FilterText->text());
347
348 SelectRow(m_SelectRow);
349 UpdateSuggestions();
350
351 QApplication::restoreOverrideCursor();
352 }
353
UpdateDictionaries()354 void SpellcheckEditor::UpdateDictionaries()
355 {
356 ui.Dictionaries->clear();
357 SpellCheck *sc = SpellCheck::instance();
358 QStringList dicts = sc->userDictionaries();
359 if (dicts.count() > 0) {
360 ui.Dictionaries->addItems(dicts);
361 }
362 }
363
DictionaryChanged(QString dictionary)364 void SpellcheckEditor::DictionaryChanged(QString dictionary)
365 {
366 ui.Dictionaries->setToolTip(dictionary);
367 }
368
ChangeState(int state)369 void SpellcheckEditor::ChangeState(int state)
370 {
371 Refresh();
372 }
373
SelectAll()374 void SpellcheckEditor::SelectAll()
375 {
376 ui.SpellcheckEditorTree->selectAll();
377 }
378
GetSelectedWord()379 QString SpellcheckEditor::GetSelectedWord()
380 {
381 QString word;
382
383 if (SelectedRowsCount() != 1 || m_MultipleSelection) {
384 return word;
385 }
386
387 QModelIndex index = ui.SpellcheckEditorTree->selectionModel()->selectedRows(0).first();
388 // word = m_SpellcheckEditorModel->itemFromIndex(index)->text();
389 word = m_SpellcheckEditorModel->itemFromIndex(index)->data().toString() + ": " +
390 m_SpellcheckEditorModel->itemFromIndex(index)->text();
391 return word;
392 }
393
GetSelectedRow()394 int SpellcheckEditor::GetSelectedRow()
395 {
396 int row = -1;
397
398 if (SelectedRowsCount() != 1 || m_MultipleSelection) {
399 return row;
400 }
401
402 return ui.SpellcheckEditorTree->selectionModel()->selectedRows(0).first().row();
403 }
404
SelectRow(int row)405 void SpellcheckEditor::SelectRow(int row)
406 {
407 QStandardItem *root_item = m_SpellcheckEditorModel->invisibleRootItem();
408
409 if (root_item->rowCount() > 0 && row >= 0) {
410 if (row >= root_item->rowCount()) {
411 row = root_item->rowCount() - 1;
412 }
413
414 QStandardItem *child = root_item->child(row, 0);
415 if (child) {
416 QModelIndex index = child->index();
417 ui.SpellcheckEditorTree->setFocus();
418 ui.SpellcheckEditorTree->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
419 ui.SpellcheckEditorTree->setCurrentIndex(child->index());
420 }
421 }
422
423 m_SelectRow = -1;
424 }
425
UpdateSuggestions()426 void SpellcheckEditor::UpdateSuggestions()
427 {
428 ui.cbChangeAll->clear();
429 QString word = GetSelectedWord();
430 if (!word.isEmpty()) {
431 SpellCheck *sc = SpellCheck::instance();
432 ui.cbChangeAll->addItems(sc->suggest(word));
433 }
434 }
435
FindSelectedWord()436 void SpellcheckEditor::FindSelectedWord()
437 {
438 QString word = GetSelectedWord();
439 if (!word.isEmpty()) {
440 emit FindWordRequest(word);
441 }
442 }
443
SelectionChanged(const QItemSelection & selected,const QItemSelection & deselected)444 void SpellcheckEditor::SelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
445 {
446 UpdateSuggestions();
447 // do not do a FindSelectedWord() here just because selection changed, wait for user to double-click
448 // so that paging up and down in the wordlist is not painfully slow in larger epubs
449 }
450
FilterEditTextChangedSlot(const QString & text)451 void SpellcheckEditor::FilterEditTextChangedSlot(const QString &text)
452 {
453 const QString lowercaseText = text.toLower();
454 QModelIndex root_index = m_SpellcheckEditorModel->indexFromItem(m_SpellcheckEditorModel->invisibleRootItem());
455
456 for (int row = 0; row < m_SpellcheckEditorModel->invisibleRootItem()->rowCount(); row++) {
457 QStandardItem *item = m_SpellcheckEditorModel->item(row, 0);
458 bool hidden = !(text.isEmpty() || item->text().toLower().contains(lowercaseText));
459 ui.SpellcheckEditorTree->setRowHidden(item->row(), root_index, hidden);
460 }
461 }
462
Sort(int logicalindex,Qt::SortOrder order)463 void SpellcheckEditor::Sort(int logicalindex, Qt::SortOrder order)
464 {
465 Refresh(logicalindex, order);
466 }
467
ReadSettings()468 void SpellcheckEditor::ReadSettings()
469 {
470 SettingsStore settings;
471 settings.beginGroup(SETTINGS_GROUP);
472 // The size of the window and it's full screen status
473 QByteArray geometry = settings.value("geometry").toByteArray();
474
475 if (!geometry.isNull()) {
476 restoreGeometry(geometry);
477 }
478
479 // Selected Dictionary
480 int index = -1;
481 QString dictionary;
482 if (settings.contains(SELECTED_DICTIONARY)) {
483 dictionary = settings.value(SELECTED_DICTIONARY).toString();
484 index = ui.Dictionaries->findText(dictionary);
485 }
486 if (index < 0) {
487 index = 0;
488 }
489 ui.Dictionaries->setCurrentIndex(index);
490 if (dictionary.isEmpty()) {
491 dictionary = ui.Dictionaries->currentText();
492 }
493 ui.Dictionaries->setToolTip(dictionary);
494
495 // Checkboxes
496 // Disconnect signals to avoid refresh when setting.
497 if (settings.contains(SHOW_ALL_WORDS)) {
498 if (settings.value(SHOW_ALL_WORDS).toBool()) {
499 disconnect(ui.ShowAllWords, SIGNAL(stateChanged(int)),
500 this, SLOT(ChangeState(int)));
501 ui.ShowAllWords->setCheckState(Qt::Checked);
502 connect(ui.ShowAllWords, SIGNAL(stateChanged(int)),
503 this, SLOT(ChangeState(int)));
504 }
505 }
506 if (settings.contains(CASE_INSENSITIVE_SORT)) {
507 if (settings.value(CASE_INSENSITIVE_SORT).toBool()) {
508 disconnect(ui.CaseInsensitiveSort, SIGNAL(stateChanged(int)),
509 this, SLOT(ChangeState(int)));
510 ui.CaseInsensitiveSort->setCheckState(Qt::Checked);
511 connect(ui.CaseInsensitiveSort, SIGNAL(stateChanged(int)),
512 this, SLOT(ChangeState(int)));
513 }
514 }
515
516 // Sort Order.
517 if (settings.contains(SORT_COLUMN) && settings.contains(SORT_ORDER)) {
518 int sort_column = settings.value(SORT_COLUMN).toInt();
519 Qt::SortOrder sort_order = Qt::AscendingOrder;
520 if (!settings.value(SORT_ORDER).toBool()) {
521 sort_order = Qt::DescendingOrder;
522 }
523
524
525 // Changing the sortIndicator should not cause the entire wordlist to be regenerated!
526 // disconnect(ui.SpellcheckEditorTree->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(Sort(int, Qt::SortOrder)));
527
528 ui.SpellcheckEditorTree->header()->setSortIndicator(sort_column, sort_order);
529
530 // Changing the sortIndicator should not cause the entire wordlist to be regenerated!
531 // connect(ui.SpellcheckEditorTree->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(Sort(int, Qt::SortOrder)));
532 }
533
534 settings.endGroup();
535 }
536
WriteSettings()537 void SpellcheckEditor::WriteSettings()
538 {
539 SettingsStore settings;
540 settings.beginGroup(SETTINGS_GROUP);
541 // The size of the window and it's full screen status
542 settings.setValue("geometry", saveGeometry());
543
544 // Selected Dictionary
545 settings.setValue(SELECTED_DICTIONARY, ui.Dictionaries->currentText());
546
547 // Checkboxes
548 settings.setValue(SHOW_ALL_WORDS, ui.ShowAllWords->checkState() == Qt::Checked);
549 settings.setValue(CASE_INSENSITIVE_SORT, ui.CaseInsensitiveSort->checkState() == Qt::Checked);
550 settings.setValue(SORT_COLUMN, ui.SpellcheckEditorTree->header()->sortIndicatorSection());
551 settings.setValue(SORT_ORDER, ui.SpellcheckEditorTree->header()->sortIndicatorOrder() == Qt::AscendingOrder);
552
553 settings.endGroup();
554 }
555
CreateContextMenuActions()556 void SpellcheckEditor::CreateContextMenuActions()
557 {
558 m_Ignore = new QAction(tr("Ignore"), this);
559 m_Add = new QAction(tr("Add to Dictionary"), this);
560 m_Find = new QAction(tr("Find in Text"), this);
561 m_SelectAll = new QAction(tr("Select All"), this);
562 m_Ignore->setShortcut(QKeySequence(Qt::Key_F1));
563 m_Add->setShortcut(QKeySequence(Qt::Key_F2));
564 m_Find->setShortcut(QKeySequence(Qt::Key_F3));
565 // Has to be added to the dialog itself for the keyboard shortcut to work.
566 addAction(m_Ignore);
567 addAction(m_Add);
568 addAction(m_Find);
569 }
570
OpenContextMenu(const QPoint & point)571 void SpellcheckEditor::OpenContextMenu(const QPoint &point)
572 {
573 SetupContextMenu(point);
574 m_ContextMenu->exec(ui.SpellcheckEditorTree->viewport()->mapToGlobal(point));
575 if (!m_ContextMenu.isNull()) {
576 m_ContextMenu->clear();
577 // Make sure every action is enabled - in case shortcut is used after context menu disables some.
578 m_Ignore->setEnabled(true);
579 m_Add->setEnabled(true);
580 m_Find->setEnabled(true);
581 m_SelectAll->setEnabled(true);
582 }
583 }
584
SetupContextMenu(const QPoint & point)585 void SpellcheckEditor::SetupContextMenu(const QPoint &point)
586 {
587 int selected_rows_count = SelectedRowsCount();
588 m_ContextMenu->addAction(m_Ignore);
589 m_Ignore->setEnabled(selected_rows_count > 0);
590 m_ContextMenu->addAction(m_Add);
591 m_Add->setEnabled(selected_rows_count > 0);
592 m_ContextMenu->addAction(m_Find);
593 m_Find->setEnabled(selected_rows_count > 0);
594 m_ContextMenu->addSeparator();
595 m_ContextMenu->addAction(m_SelectAll);
596 }
597
ForceClose()598 void SpellcheckEditor::ForceClose()
599 {
600 close();
601 }
602
ConnectSignalsSlots()603 void SpellcheckEditor::ConnectSignalsSlots()
604 {
605 QItemSelectionModel *selectionModel = ui.SpellcheckEditorTree->selectionModel();
606 connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
607 this, SLOT(SelectionChanged(const QItemSelection &, const QItemSelection &)));
608
609 connect(ui.FilterText, SIGNAL(textChanged(QString)), this, SLOT(FilterEditTextChangedSlot(QString)));
610 connect(ui.Refresh, SIGNAL(clicked()), this, SLOT(Refresh()));
611 connect(ui.Ignore, SIGNAL(clicked()), this, SLOT(Ignore()));
612 connect(ui.Add, SIGNAL(clicked()), this, SLOT(Add()));
613 connect(ui.ChangeAll, SIGNAL(clicked()), this, SLOT(ChangeAll()));
614 connect(ui.SpellcheckEditorTree, SIGNAL(customContextMenuRequested(const QPoint &)),
615 this, SLOT(OpenContextMenu(const QPoint &)));
616
617 // Changing the sortIndicator order should not cause the entire wordlist to be regenerated
618 // connect(ui.SpellcheckEditorTree->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)),
619 // this, SLOT(Sort(int, Qt::SortOrder)));
620
621 connect(m_Ignore, SIGNAL(triggered()), this, SLOT(Ignore()));
622 connect(m_Add, SIGNAL(triggered()), this, SLOT(Add()));
623 connect(m_Find, SIGNAL(triggered()), this, SLOT(FindSelectedWord()));
624 connect(m_SelectAll, SIGNAL(triggered()), this, SLOT(SelectAll()));
625 connect(ui.SpellcheckEditorTree, SIGNAL(doubleClicked(const QModelIndex &)),
626 this, SLOT(FindSelectedWord()));
627 connect(ui.ShowAllWords, SIGNAL(stateChanged(int)),
628 this, SLOT(ChangeState(int)));
629 connect(ui.CaseInsensitiveSort, SIGNAL(stateChanged(int)),
630 this, SLOT(ChangeState(int)));
631 connect(ui.Dictionaries, SIGNAL(activated(const QString &)),
632 this, SLOT(DictionaryChanged(const QString &)));
633
634 connect(m_FilterSC, SIGNAL(activated()), ui.FilterText, SLOT(setFocus()));
635 connect(m_ShowAllSC, SIGNAL(activated()), this, SLOT(toggleShowAllWords()));
636 connect(m_NoCaseSC, SIGNAL(activated()), this, SLOT(toggleCaseInsensitiveSort()));
637 connect(m_RefreshSC, SIGNAL(activated()), this, SLOT(Refresh()));
638
639 }
640