diff --git a/CMakeLists.txt b/CMakeLists.txt index e9c94b5..a4ebdba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,95 +1,95 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.65.0") # handled by release scripts project(Sonnet VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.64.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(ECMQtDeclareLoggingCategory) +include(ECMGenerateExportHeader) +include(ECMSetupVersion) +include(ECMGenerateHeaders) + +include(ECMAddQch) +include(ECMPoQmTools) + +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") set(REQUIRED_QT_VERSION 5.11.0) option(SONNET_USE_WIDGETS "Build components using Qt5Widgets" ON) if(SONNET_USE_WIDGETS) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Widgets) endif() find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core) -include(GenerateExportHeader) - -include(ECMSetupVersion) -include(ECMGenerateHeaders) - -include(ECMAddQch) -include(ECMPoQmTools) - ecm_setup_version(PROJECT VARIABLE_PREFIX SONNET VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/sonnet_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5SonnetConfigVersion.cmake" SOVERSION 5) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") if(SONNET_USE_WIDGETS) option(BUILD_DESIGNERPLUGIN "Build plugin for Qt Designer" ON) add_feature_info(DESIGNERPLUGIN ${BUILD_DESIGNERPLUGIN} "Build plugin for Qt Designer") endif() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() add_definitions(-DQT_NO_FOREACH) add_subdirectory(data) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) endif() if(TARGET Qt5::Widgets) add_subdirectory(examples) endif() # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Sonnet") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5SonnetCore_QCH KF5SonnetUi_QCH FILE KF5SonnetQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5SonnetQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5SonnetConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5SonnetConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5SonnetConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5SonnetConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5SonnetTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5SonnetTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sonnet_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) # contains list of debug categories, for kdebugsettings install(FILES sonnet.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/docs/Doxyfile.local b/docs/Doxyfile.local new file mode 100644 index 0000000..16a8825 --- /dev/null +++ b/docs/Doxyfile.local @@ -0,0 +1,10 @@ +### KApiDox Project-specific Overrides File + +# define so that deprecated API is not skipped +PREDEFINED += \ + "SONNETCORE_ENABLE_DEPRECATED_SINCE(x, y)=1" \ + "SONNETCORE_BUILD_DEPRECATED_SINCE(x, y)=1" \ + "SONNETCORE_DEPRECATED_VERSION(x, y, t)=" \ + "SONNETUI_ENABLE_DEPRECATED_SINCE(x, y)=1" \ + "SONNETUI_BUILD_DEPRECATED_SINCE(x, y)=1" \ + "SONNETUI_DEPRECATED_VERSION(x, y, t)=" \ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 793d85f..d44f1f9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,88 +1,98 @@ project(sonnetcore) set(sonnetcore_SRCS loader.cpp client.cpp spellerplugin.cpp speller.cpp settings.cpp backgroundchecker.cpp guesslanguage.cpp textbreaks.cpp tokenizer.cpp languagefilter.cpp ) # create trigrams file + add trigrams resource if (TARGET KF5::parsetrigrams) add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/data/trigrams.map" COMMAND KF5::parsetrigrams "${CMAKE_SOURCE_DIR}/data/trigrams" > "${CMAKE_BINARY_DIR}/data/trigrams.map") configure_file(${CMAKE_SOURCE_DIR}/data/trigrams.qrc.in ${CMAKE_BINARY_DIR}/data/trigrams.qrc @ONLY) qt5_add_resources(sonnetcore_SRCS "${CMAKE_BINARY_DIR}/data/trigrams.qrc") endif() ecm_qt_declare_logging_category(sonnetcore_SRCS HEADER core_debug.h IDENTIFIER SONNET_LOG_CORE CATEGORY_NAME sonnet.core) # Dear packagers, this is just used as an extra search paths for plugins. Don't get your panties in a twist. add_definitions(-DINSTALLATION_PLUGIN_PATH="${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_PLUGINDIR}") add_library(KF5SonnetCore ${sonnetcore_SRCS}) -generate_export_header(KF5SonnetCore BASE_NAME SonnetCore EXPORT_FILE_NAME sonnetcore_export.h) +ecm_generate_export_header(KF5SonnetCore + BASE_NAME SonnetCore + GROUP_BASE_NAME KF + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + #DEPRECATION_VERSIONS 5.65 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) + + add_library(KF5::SonnetCore ALIAS KF5SonnetCore) ecm_generate_headers(SonnetCore_CamelCase_HEADERS HEADER_NAMES BackgroundChecker Speller GuessLanguage PREFIX Sonnet REQUIRED_HEADERS SonnetCore_HEADERS ) target_link_libraries(KF5SonnetCore PUBLIC Qt5::Core) set_target_properties(KF5SonnetCore PROPERTIES VERSION ${SONNET_VERSION_STRING} SOVERSION ${SONNET_SOVERSION} EXPORT_NAME SonnetCore ) # CMAKE_CURRENT_BINARY_DIR: for camelcase headers and lowercase forwarders target_include_directories(KF5SonnetCore INTERFACE "$") target_include_directories(KF5SonnetCore PUBLIC "$") install(TARGETS KF5SonnetCore EXPORT KF5SonnetTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${SonnetCore_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetCore/Sonnet COMPONENT Devel) install(FILES ${SonnetCore_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/sonnetcore_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetCore/sonnet COMPONENT Devel) if (BUILD_QCH) ecm_add_qch( KF5SonnetCore_QCH NAME SonnetCore BASE_NAME KF5SonnetCore VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${SonnetCore_HEADERS} LINK_QCHS Qt5Core_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS SONNETCORE_EXPORT SONNETCORE_DEPRECATED_EXPORT SONNETCORE_DEPRECATED + "SONNETCORE_DEPRECATED_VERSION(x, y, t)" TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME SonnetCore LIB_NAME KF5SonnetCore DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetCore) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 01acf5c..bb407b8 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,95 +1,104 @@ project(sonnetui) ecm_create_qm_loader(sonnet_QM_LOADER sonnet5_qt) set(sonnetui_SRCS configdialog.cpp configwidget.cpp dialog.cpp dictionarycombobox.cpp highlighter.cpp spellcheckdecorator.cpp ${sonnet_QM_LOADER} ) ecm_qt_declare_logging_category(sonnetui_SRCS HEADER ui_debug.h IDENTIFIER SONNET_LOG_UI CATEGORY_NAME sonnet.ui) set(sonnetui_UI configui.ui sonnetui.ui ) ecm_generate_headers(SonnetUi_CamelCase_HEADERS HEADER_NAMES Dialog Highlighter ConfigDialog ConfigWidget DictionaryComboBox SpellCheckDecorator PREFIX Sonnet REQUIRED_HEADERS SonnetUi_HEADERS ) qt5_wrap_ui(sonnetui_SRCS ${sonnetui_UI}) add_library(KF5SonnetUi ${sonnetui_SRCS}) -generate_export_header(KF5SonnetUi BASE_NAME SonnetUi EXPORT_FILE_NAME sonnetui_export.h) +ecm_generate_export_header(KF5SonnetUi + BASE_NAME SonnetUi + GROUP_BASE_NAME KF + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.65 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) + add_library(KF5::SonnetUi ALIAS KF5SonnetUi) target_link_libraries(KF5SonnetUi PUBLIC Qt5::Widgets PRIVATE KF5::SonnetCore ) set_target_properties(KF5SonnetUi PROPERTIES VERSION ${SONNET_VERSION_STRING} SOVERSION ${SONNET_SOVERSION} EXPORT_NAME SonnetUi ) # CMAKE_CURRENT_BINARY_DIR: for camelcase headers and lowercase forwarders target_include_directories(KF5SonnetUi INTERFACE "$") target_include_directories(KF5SonnetUi PUBLIC "$") install(TARGETS KF5SonnetUi EXPORT KF5SonnetTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${SonnetUi_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetUi/Sonnet COMPONENT Devel) install(FILES ${SonnetUi_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/sonnetui_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetUi/sonnet COMPONENT Devel) if(BUILD_DESIGNERPLUGIN) add_subdirectory(designer) endif() if (BUILD_QCH) ecm_add_qch( KF5SonnetUi_QCH NAME SonnetUi BASE_NAME KF5SonnetUi VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${SonnetUi_HEADERS} LINK_QCHS Qt5Core_QCH Qt5Gui_QCH Qt5Widgets_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS SONNETUI_EXPORT SONNETUI_DEPRECATED_EXPORT SONNETUI_DEPRECATED + "SONNETUI_DEPRECATED_VERSION(x, y, t)" TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME SonnetUi LIB_NAME KF5SonnetUi DEPS "widgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/SonnetUi) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/ui/dialog.cpp b/src/ui/dialog.cpp index 9062527..a18f986 100644 --- a/src/ui/dialog.cpp +++ b/src/ui/dialog.cpp @@ -1,433 +1,436 @@ /** * dialog.cpp * * Copyright (C) 2003 Zack Rusin * Copyright (C) 2009-2010 Michel Ludwig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include "dialog.h" #include "ui_sonnetui.h" #include "backgroundchecker.h" #include "speller.h" #include "settings_p.h" #include #include #include #include #include namespace Sonnet { //to initially disable sorting in the suggestions listview #define NONSORTINGCOLUMN 2 class ReadOnlyStringListModel : public QStringListModel { public: ReadOnlyStringListModel(QObject *parent) : QStringListModel(parent) { } Qt::ItemFlags flags(const QModelIndex &index) const override { Q_UNUSED(index); return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } }; class DialogPrivate { public: Ui_SonnetUi ui; ReadOnlyStringListModel *suggestionsModel = nullptr; QWidget *wdg = nullptr; QDialogButtonBox *buttonBox = nullptr; QProgressDialog *progressDialog = nullptr; QString originalBuffer; BackgroundChecker *checker = nullptr; QString currentWord; int currentPosition; QMap replaceAllMap; bool restart;//used when text is distributed across several qtextedits, eg in KAider QMap dictsMap; int progressDialogTimeout; bool showCompletionMessageBox; bool spellCheckContinuedAfterReplacement; bool canceled; void deleteProgressDialog(bool directly) { if (progressDialog) { progressDialog->hide(); if (directly) { delete progressDialog; } else { progressDialog->deleteLater(); } progressDialog = nullptr; } } }; Dialog::Dialog(BackgroundChecker *checker, QWidget *parent) : QDialog(parent) , d(new DialogPrivate) { setModal(true); setWindowTitle(tr("Check Spelling", "@title:window")); d->checker = checker; d->canceled = false; d->showCompletionMessageBox = false; d->spellCheckContinuedAfterReplacement = true; d->progressDialogTimeout = -1; d->progressDialog = nullptr; initGui(); initConnections(); } Dialog::~Dialog() { delete d; } void Dialog::initConnections() { connect(d->ui.m_addBtn, &QAbstractButton::clicked, this, &Dialog::slotAddWord); connect(d->ui.m_replaceBtn, &QAbstractButton::clicked, this, &Dialog::slotReplaceWord); connect(d->ui.m_replaceAllBtn, &QAbstractButton::clicked, this, &Dialog::slotReplaceAll); connect(d->ui.m_skipBtn, &QAbstractButton::clicked, this, &Dialog::slotSkip); connect(d->ui.m_skipAllBtn, &QAbstractButton::clicked, this, &Dialog::slotSkipAll); connect(d->ui.m_suggestBtn, &QAbstractButton::clicked, this, &Dialog::slotSuggest); connect(d->ui.m_language, SIGNAL(activated(QString)), SLOT(slotChangeLanguage(QString))); connect(d->ui.m_suggestions, SIGNAL(clicked(QModelIndex)), SLOT(slotSelectionChanged(QModelIndex))); connect(d->checker, SIGNAL(misspelling(QString,int)), SLOT(slotMisspelling(QString,int))); connect(d->checker, SIGNAL(done()), SLOT(slotDone())); connect(d->ui.m_suggestions, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotReplaceWord())); connect(d->buttonBox, &QDialogButtonBox::accepted, this, &Dialog::slotFinished); connect(d->buttonBox, &QDialogButtonBox::rejected, this, &Dialog::slotCancel); connect(d->ui.m_replacement, SIGNAL(returnPressed()), this, SLOT(slotReplaceWord())); connect(d->ui.m_autoCorrect, SIGNAL(clicked()), SLOT(slotAutocorrect())); // button use by kword/kpresenter // hide by default d->ui.m_autoCorrect->hide(); } void Dialog::initGui() { QVBoxLayout *layout = new QVBoxLayout(this); d->wdg = new QWidget(this); d->ui.setupUi(d->wdg); layout->addWidget(d->wdg); setGuiEnabled(false); d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); layout->addWidget(d->wdg); layout->addWidget(d->buttonBox); //d->ui.m_suggestions->setSorting( NONSORTINGCOLUMN ); fillDictionaryComboBox(); d->restart = false; d->suggestionsModel = new ReadOnlyStringListModel(this); d->ui.m_suggestions->setModel(d->suggestionsModel); } void Dialog::activeAutoCorrect(bool _active) { if (_active) { d->ui.m_autoCorrect->show(); } else { d->ui.m_autoCorrect->hide(); } } void Dialog::showProgressDialog(int timeout) { d->progressDialogTimeout = timeout; } void Dialog::showSpellCheckCompletionMessage(bool b) { d->showCompletionMessageBox = b; } void Dialog::setSpellCheckContinuedAfterReplacement(bool b) { d->spellCheckContinuedAfterReplacement = b; } void Dialog::slotAutocorrect() { setGuiEnabled(false); setProgressDialogVisible(true); emit autoCorrect(d->currentWord, d->ui.m_replacement->text()); slotReplaceWord(); } void Dialog::setGuiEnabled(bool b) { d->wdg->setEnabled(b); } void Dialog::setProgressDialogVisible(bool b) { if (!b) { d->deleteProgressDialog(true); } else if (d->progressDialogTimeout >= 0) { if (d->progressDialog) { return; } d->progressDialog = new QProgressDialog(this); d->progressDialog->setLabelText(tr("Spell checking in progress...", "progress label")); d->progressDialog->setWindowTitle(tr("Check Spelling", "@title:window")); d->progressDialog->setModal(true); d->progressDialog->setAutoClose(false); d->progressDialog->setAutoReset(false); // create an 'indefinite' progress box as we currently cannot get progress feedback from // the speller d->progressDialog->reset(); d->progressDialog->setRange(0, 0); d->progressDialog->setValue(0); connect(d->progressDialog, &QProgressDialog::canceled, this, &Dialog::slotCancel); d->progressDialog->setMinimumDuration(d->progressDialogTimeout); } } void Dialog::slotFinished() { setProgressDialogVisible(false); emit stop(); //FIXME: should we emit done here? +#if SONNETUI_BUILD_DEPRECATED_SINCE(5, 65) emit done(d->checker->text()); +#endif + emit spellCheckDone(d->checker->text()); emit spellCheckStatus(tr("Spell check stopped.")); accept(); } void Dialog::slotCancel() { d->canceled = true; d->deleteProgressDialog(false); // this method can be called in response to // pressing 'Cancel' on the dialog emit cancel(); emit spellCheckStatus(tr("Spell check canceled.")); reject(); } QString Dialog::originalBuffer() const { return d->originalBuffer; } QString Dialog::buffer() const { return d->checker->text(); } void Dialog::setBuffer(const QString &buf) { d->originalBuffer = buf; //it is possible to change buffer inside slot connected to done() signal d->restart = true; } void Dialog::fillDictionaryComboBox() { // Since m_language is changed to DictionaryComboBox most code here is gone, // So fillDictionaryComboBox() could be removed and code moved to initGui() // because the call in show() looks obsolete Speller speller = d->checker->speller(); d->dictsMap = speller.availableDictionaries(); updateDictionaryComboBox(); } void Dialog::updateDictionaryComboBox() { const Speller &speller = d->checker->speller(); d->ui.m_language->setCurrentByDictionary(speller.language()); } void Dialog::updateDialog(const QString &word) { d->ui.m_unknownWord->setText(word); d->ui.m_contextLabel->setText(d->checker->currentContext()); const QStringList suggs = d->checker->suggest(word); if (suggs.isEmpty()) { d->ui.m_replacement->clear(); } else { d->ui.m_replacement->setText(suggs.first()); } fillSuggestions(suggs); } void Dialog::show() { d->canceled = false; fillDictionaryComboBox(); if (d->originalBuffer.isEmpty()) { d->checker->start(); } else { d->checker->setText(d->originalBuffer); } setProgressDialogVisible(true); } void Dialog::slotAddWord() { setGuiEnabled(false); setProgressDialogVisible(true); d->checker->addWordToPersonal(d->currentWord); d->checker->continueChecking(); } void Dialog::slotReplaceWord() { setGuiEnabled(false); setProgressDialogVisible(true); QString replacementText = d->ui.m_replacement->text(); emit replace(d->currentWord, d->currentPosition, replacementText); if (d->spellCheckContinuedAfterReplacement) { d->checker->replace(d->currentPosition, d->currentWord, replacementText); d->checker->continueChecking(); } else { d->checker->stop(); } } void Dialog::slotReplaceAll() { setGuiEnabled(false); setProgressDialogVisible(true); d->replaceAllMap.insert(d->currentWord, d->ui.m_replacement->text()); slotReplaceWord(); } void Dialog::slotSkip() { setGuiEnabled(false); setProgressDialogVisible(true); d->checker->continueChecking(); } void Dialog::slotSkipAll() { setGuiEnabled(false); setProgressDialogVisible(true); //### do we want that or should we have a d->ignoreAll list? Speller speller = d->checker->speller(); speller.addToPersonal(d->currentWord); d->checker->setSpeller(speller); d->checker->continueChecking(); } void Dialog::slotSuggest() { QStringList suggs = d->checker->suggest(d->ui.m_replacement->text()); fillSuggestions(suggs); } void Dialog::slotChangeLanguage(const QString &lang) { Speller speller = d->checker->speller(); QString languageCode = d->dictsMap[lang]; if (!languageCode.isEmpty()) { d->checker->changeLanguage(languageCode); slotSuggest(); emit languageChanged(languageCode); } } void Dialog::slotSelectionChanged(const QModelIndex &item) { d->ui.m_replacement->setText(item.data().toString()); } void Dialog::fillSuggestions(const QStringList &suggs) { d->suggestionsModel->setStringList(suggs); } void Dialog::slotMisspelling(const QString &word, int start) { setGuiEnabled(true); setProgressDialogVisible(false); emit misspelling(word, start); //NOTE this is HACK I had to introduce because BackgroundChecker lacks 'virtual' marks on methods //this dramatically reduces spellchecking time in Lokalize //as this doesn't fetch suggestions for words that are present in msgid if (!updatesEnabled()) { return; } d->currentWord = word; d->currentPosition = start; if (d->replaceAllMap.contains(word)) { d->ui.m_replacement->setText(d->replaceAllMap[ word ]); slotReplaceWord(); } else { updateDialog(word); } QDialog::show(); } void Dialog::slotDone() { d->restart = false; emit done(d->checker->text()); if (d->restart) { updateDictionaryComboBox(); d->checker->setText(d->originalBuffer); d->restart = false; } else { setProgressDialogVisible(false); emit spellCheckStatus(tr("Spell check complete.")); accept(); if (!d->canceled && d->showCompletionMessageBox) { QMessageBox::information(this, tr("Spell check complete."), tr("Check Spelling", "@title:window")); } } } } diff --git a/src/ui/dialog.h b/src/ui/dialog.h index 57b335f..b40062b 100644 --- a/src/ui/dialog.h +++ b/src/ui/dialog.h @@ -1,162 +1,171 @@ /* * dialog.h * * Copyright (C) 2003 Zack Rusin * Copyright (C) 2009-2010 Michel Ludwig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #ifndef SONNET_DIALOG_H #define SONNET_DIALOG_H #include #include "sonnetui_export.h" class QListWidgetItem; class QModelIndex; namespace Sonnet { class BackgroundChecker; class DialogPrivate; /** * @short Spellcheck dialog * * \code * Sonnet::Dialog dlg = new Sonnet::Dialog( * new Sonnet::BackgroundChecker(this), this); * //connect signals * ... * dlg->setBuffer( someText ); * dlg->show(); * \endcode * * You can change buffer inside a slot connected to done() signal * and spellcheck will continue with new data automatically. */ class SONNETUI_EXPORT Dialog : public QDialog { Q_OBJECT public: Dialog(BackgroundChecker *checker, QWidget *parent); ~Dialog(); QString originalBuffer() const; QString buffer() const; void show(); void activeAutoCorrect(bool _active); // Hide warning about done(), which is a slot in QDialog and a signal here. using QDialog::done; /** * Controls whether an (indefinite) progress dialog is shown when the spell * checking takes longer than the given time to complete. By default no * progress dialog is shown. If the progress dialog is set to be shown, no * time consuming operation (for example, showing a notification message) should * be performed in a slot connected to the 'done' signal as this might trigger * the progress dialog unnecessarily. * * @param timeout time after which the progress dialog should appear; a negative * value can be used to hide it * @since 4.4 */ void showProgressDialog(int timeout = 500); /** * Controls whether a message box indicating the completion of the spell checking * is shown or not. By default it is not shown. * * @since 4.4 */ void showSpellCheckCompletionMessage(bool b = true); /** * Controls whether the spell checking is continued after the replacement of a * misspelled word has been performed. By default it is continued. * * @since 4.4 */ void setSpellCheckContinuedAfterReplacement(bool b); public Q_SLOTS: void setBuffer(const QString &); Q_SIGNALS: +#if SONNETUI_ENABLE_DEPRECATED_SINCE(5, 65) /** * The dialog won't be closed if you setBuffer() in slot connected to this signal - * * Also emitted after stop() signal + * @deprecated Since 5.65, use spellCheckDone */ + SONNETUI_DEPRECATED_VERSION(5, 65, "Use Dialog::spellCheckDone()") void done(const QString &newBuffer); +#endif + /** + * The dialog won't be closed if you setBuffer() in slot connected to this signal + * Also emitted after stop() signal + * @Since 5.65 + */ + void spellCheckDone(const QString &newBuffer); void misspelling(const QString &word, int start); void replace(const QString &oldWord, int start, const QString &newWord); void stop(); void cancel(); void autoCorrect(const QString ¤tWord, const QString &replaceWord); /** * Signal sends when spell checking is finished/stopped/completed * @since 4.1 */ void spellCheckStatus(const QString &); /** * Emitted when the user changes the language used for spellchecking, * which is shown in a combobox of this dialog. * * @param dictionary the new language the user selected * @since 4.1 */ void languageChanged(const QString &language); private Q_SLOTS: void slotMisspelling(const QString &word, int start); void slotDone(); void slotFinished(); void slotCancel(); void slotAddWord(); void slotReplaceWord(); void slotReplaceAll(); void slotSkip(); void slotSkipAll(); void slotSuggest(); void slotChangeLanguage(const QString &); void slotSelectionChanged(const QModelIndex &); void slotAutocorrect(); void setGuiEnabled(bool b); void setProgressDialogVisible(bool b); private: void updateDialog(const QString &word); void fillDictionaryComboBox(); void updateDictionaryComboBox(); void fillSuggestions(const QStringList &suggs); void initConnections(); void initGui(); void continueChecking(); private: DialogPrivate *const d; Q_DISABLE_COPY(Dialog) }; } #endif