File indexing completed on 2026-07-19 08:32:55

0001 /*
0002   SPDX-FileCopyrightText: 2012-2024 Laurent Montel <montel@kde.org>
0003 
0004   SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "autocorrectionwidget.h"
0008 #include "autocorrectionutils.h"
0009 
0010 #include "ui_autocorrectionwidget.h"
0011 #include <TextAutoCorrectionCore/ImportAbstractAutocorrection>
0012 #include <TextAutoCorrectionCore/ImportKMailAutocorrection>
0013 #include <TextAutoCorrectionCore/ImportLibreOfficeAutocorrection>
0014 
0015 #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
0016 #include <TextAddonsWidgets/LineEditCatchReturnKey>
0017 #else
0018 #include <KLineEditEventHandler>
0019 #endif
0020 #include <TextAddonsWidgets/SelectSpecialCharDialog>
0021 
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 
0025 #include <QFileDialog>
0026 #include <QMenu>
0027 #include <QPointer>
0028 #include <QTreeWidgetItem>
0029 
0030 using namespace TextAutoCorrectionWidgets;
0031 using namespace TextAutoCorrectionCore;
0032 
0033 Q_DECLARE_METATYPE(AutoCorrectionWidget::ImportFileType)
0034 class TextAutoCorrectionWidgets::AutoCorrectionWidgetPrivate
0035 {
0036 public:
0037     AutoCorrectionWidgetPrivate()
0038         : ui(new Ui::AutoCorrectionWidget)
0039     {
0040     }
0041 
0042     ~AutoCorrectionWidgetPrivate() = default;
0043 
0044     TextAutoCorrectionCore::AutoCorrectionUtils::TypographicQuotes m_singleQuotes;
0045     TextAutoCorrectionCore::AutoCorrectionUtils::TypographicQuotes m_doubleQuotes;
0046     QSet<QString> m_upperCaseExceptions;
0047     QSet<QString> m_twoUpperLetterExceptions;
0048     QHash<QString, QString> m_autocorrectEntries;
0049     std::unique_ptr<Ui::AutoCorrectionWidget> const ui;
0050     TextAutoCorrectionCore::AutoCorrection *mAutoCorrection = nullptr;
0051     bool mWasChanged = false;
0052     bool mHasHtmlSupport = true;
0053 };
0054 
0055 AutoCorrectionWidget::AutoCorrectionWidget(QWidget *parent)
0056     : QWidget(parent)
0057     , d(new TextAutoCorrectionWidgets::AutoCorrectionWidgetPrivate)
0058 {
0059     d->ui->setupUi(this);
0060 
0061     d->ui->treeWidget->setSortingEnabled(true);
0062     d->ui->treeWidget->sortByColumn(0, Qt::AscendingOrder);
0063 
0064     d->ui->add1->setEnabled(false);
0065     d->ui->add2->setEnabled(false);
0066 
0067 #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
0068     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->find, this);
0069     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->replace, this);
0070     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->abbreviation, this);
0071     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->twoUpperLetter, this);
0072 #else
0073     KLineEditEventHandler::catchReturnKey(d->ui->find);
0074     KLineEditEventHandler::catchReturnKey(d->ui->replace);
0075     KLineEditEventHandler::catchReturnKey(d->ui->abbreviation);
0076     KLineEditEventHandler::catchReturnKey(d->ui->twoUpperLetter);
0077 
0078 #endif
0079     connect(d->ui->autoChangeFormat, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0080     connect(d->ui->autoFormatUrl, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0081     connect(d->ui->upperCase, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0082     connect(d->ui->upperUpper, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0083     connect(d->ui->ignoreDoubleSpace, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0084     connect(d->ui->autoReplaceNumber, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0085     connect(d->ui->capitalizeDaysName, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0086     connect(d->ui->advancedAutocorrection, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0087     connect(d->ui->enabledAutocorrection, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0088     connect(d->ui->typographicSingleQuotes, &QCheckBox::clicked, this, &AutoCorrectionWidget::enableSingleQuotes);
0089     connect(d->ui->typographicDoubleQuotes, &QCheckBox::clicked, this, &AutoCorrectionWidget::enableDoubleQuotes);
0090     connect(d->ui->autoSuperScript, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0091     connect(d->ui->singleQuote1, &QPushButton::clicked, this, &AutoCorrectionWidget::selectSingleQuoteCharOpen);
0092     connect(d->ui->singleQuote2, &QPushButton::clicked, this, &AutoCorrectionWidget::selectSingleQuoteCharClose);
0093     connect(d->ui->singleDefault, &QPushButton::clicked, this, &AutoCorrectionWidget::setDefaultSingleQuotes);
0094     connect(d->ui->doubleQuote1, &QPushButton::clicked, this, &AutoCorrectionWidget::selectDoubleQuoteCharOpen);
0095     connect(d->ui->doubleQuote2, &QPushButton::clicked, this, &AutoCorrectionWidget::selectDoubleQuoteCharClose);
0096     connect(d->ui->doubleDefault, &QPushButton::clicked, this, &AutoCorrectionWidget::setDefaultDoubleQuotes);
0097     connect(d->ui->advancedAutocorrection, &QCheckBox::clicked, this, &AutoCorrectionWidget::enableAdvAutocorrection);
0098     connect(d->ui->addButton, &QPushButton::clicked, this, &AutoCorrectionWidget::addAutocorrectEntry);
0099     connect(d->ui->removeButton, &QPushButton::clicked, this, &AutoCorrectionWidget::removeAutocorrectEntry);
0100     connect(d->ui->treeWidget, &TextAutoCorrectionWidgets::AutoCorrectionTreeWidget::itemClicked, this, &AutoCorrectionWidget::setFindReplaceText);
0101     connect(d->ui->treeWidget, &TextAutoCorrectionWidgets::AutoCorrectionTreeWidget::deleteSelectedItems, this, &AutoCorrectionWidget::removeAutocorrectEntry);
0102     connect(d->ui->treeWidget, &TextAutoCorrectionWidgets::AutoCorrectionTreeWidget::itemSelectionChanged, this, &AutoCorrectionWidget::updateAddRemoveButton);
0103     connect(d->ui->find, &QLineEdit::textChanged, this, &AutoCorrectionWidget::enableAddRemoveButton);
0104     connect(d->ui->replace, &QLineEdit::textChanged, this, &AutoCorrectionWidget::enableAddRemoveButton);
0105     connect(d->ui->abbreviation, &QLineEdit::textChanged, this, &AutoCorrectionWidget::abbreviationChanged);
0106     connect(d->ui->twoUpperLetter, &QLineEdit::textChanged, this, &AutoCorrectionWidget::twoUpperLetterChanged);
0107     connect(d->ui->add1, &QPushButton::clicked, this, &AutoCorrectionWidget::addAbbreviationEntry);
0108     connect(d->ui->remove1, &QPushButton::clicked, this, &AutoCorrectionWidget::removeAbbreviationEntry);
0109     connect(d->ui->add2, &QPushButton::clicked, this, &AutoCorrectionWidget::addTwoUpperLetterEntry);
0110     connect(d->ui->remove2, &QPushButton::clicked, this, &AutoCorrectionWidget::removeTwoUpperLetterEntry);
0111     connect(d->ui->typographicDoubleQuotes, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0112     connect(d->ui->typographicSingleQuotes, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0113     connect(d->ui->abbreviationList,
0114             &TextAutoCorrectionWidgets::AutoCorrectionListWidget::itemSelectionChanged,
0115             this,
0116             &AutoCorrectionWidget::slotEnableDisableAbreviationList);
0117     connect(d->ui->abbreviationList,
0118             &TextAutoCorrectionWidgets::AutoCorrectionListWidget::deleteSelectedItems,
0119             this,
0120             &AutoCorrectionWidget::removeAbbreviationEntry);
0121     connect(d->ui->twoUpperLetterList,
0122             &TextAutoCorrectionWidgets::AutoCorrectionListWidget::itemSelectionChanged,
0123             this,
0124             &AutoCorrectionWidget::slotEnableDisableTwoUpperEntry);
0125     connect(d->ui->twoUpperLetterList,
0126             &TextAutoCorrectionWidgets::AutoCorrectionListWidget::deleteSelectedItems,
0127             this,
0128             &AutoCorrectionWidget::removeTwoUpperLetterEntry);
0129     connect(d->ui->autocorrectionLanguage, &TextAutoCorrectionWidgets::AutoCorrectionLanguage::activated, this, &AutoCorrectionWidget::changeLanguage);
0130     connect(d->ui->addNonBreakingSpaceInFrench, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0131     connect(d->ui->twoUpperLetter, &QLineEdit::returnPressed, this, &AutoCorrectionWidget::addTwoUpperLetterEntry);
0132     connect(d->ui->abbreviation, &QLineEdit::returnPressed, this, &AutoCorrectionWidget::addAbbreviationEntry);
0133     connect(d->ui->replaceDoubleQuotesByFrenchQuotes, &QCheckBox::clicked, this, &AutoCorrectionWidget::emitChanged);
0134 
0135     connect(d->ui->customWritablePath, &QLineEdit::textChanged, this, &AutoCorrectionWidget::emitChanged);
0136     connect(d->ui->customSystemPath, &QLineEdit::textChanged, this, &AutoCorrectionWidget::emitChanged);
0137 
0138 #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
0139     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->customWritablePath, parent);
0140     TextAddonsWidgets::LineEditCatchReturnKey(d->ui->customSystemPath, parent);
0141 #else
0142     KLineEditEventHandler::catchReturnKey(d->ui->customWritablePath);
0143     KLineEditEventHandler::catchReturnKey(d->ui->customSystemPath);
0144 #endif
0145 
0146     connect(d->ui->customWritablePathToolButton, &QToolButton::clicked, this, [this]() {
0147         const QString path = QFileDialog::getExistingDirectory(this, i18n("Select Custom Writable Path"));
0148         d->ui->customWritablePath->setText(path);
0149     });
0150 
0151     connect(d->ui->customSystemPathToolButton, &QToolButton::clicked, this, [this]() {
0152         const QString path = QFileDialog::getExistingDirectory(this, i18n("Select Custom System Path"));
0153         d->ui->customSystemPath->setText(path);
0154     });
0155 
0156     slotEnableDisableAbreviationList();
0157     slotEnableDisableTwoUpperEntry();
0158 
0159     auto menu = new QMenu(this);
0160     d->ui->importAutoCorrection->setMenu(menu);
0161 
0162     auto act = new QAction(i18n("LibreOffice Autocorrection"), this);
0163     act->setData(QVariant::fromValue(AutoCorrectionWidget::LibreOffice));
0164     menu->addAction(act);
0165 
0166     act = new QAction(i18n("KMail/Calligra Autocorrection"), this);
0167     act->setData(QVariant::fromValue(AutoCorrectionWidget::KMail));
0168     menu->addAction(act);
0169 
0170     connect(menu, &QMenu::triggered, this, &AutoCorrectionWidget::slotImportAutoCorrection);
0171 
0172     connect(d->ui->exportAutoCorrection, &QPushButton::clicked, this, &AutoCorrectionWidget::slotExportAutoCorrection);
0173     connect(d->ui->tabWidget, &QTabWidget::tabBarClicked, this, &AutoCorrectionWidget::slotChangeComboboxState);
0174     slotChangeComboboxState(d->ui->tabWidget->currentIndex());
0175 
0176     d->ui->systemPath->setText(TextAutoCorrectionCore::AutoCorrectionUtils::libreOfficeSystemPath());
0177     d->ui->writablePath->setText(TextAutoCorrectionCore::AutoCorrectionUtils::libreOfficeWritableLocalAutoCorrectionPath());
0178 }
0179 
0180 AutoCorrectionWidget::~AutoCorrectionWidget() = default;
0181 
0182 void AutoCorrectionWidget::slotChangeComboboxState(int index)
0183 {
0184     d->ui->autocorrectionLanguage->setEnabled(index < 2);
0185 }
0186 
0187 void AutoCorrectionWidget::setAutoCorrection(TextAutoCorrectionCore::AutoCorrection *autoCorrect)
0188 {
0189     d->mAutoCorrection = autoCorrect;
0190     setLanguage(d->ui->autocorrectionLanguage->language());
0191 }
0192 
0193 void AutoCorrectionWidget::setHasHtmlSupport(bool b)
0194 {
0195     if (d->mHasHtmlSupport != b) {
0196         d->mHasHtmlSupport = b;
0197         updateHtmlSupport();
0198     }
0199 }
0200 
0201 void AutoCorrectionWidget::updateHtmlSupport()
0202 {
0203     d->ui->autoFormatUrl->setVisible(d->mHasHtmlSupport);
0204     d->ui->autoSuperScript->setVisible(d->mHasHtmlSupport);
0205     d->ui->autoChangeFormat->setVisible(d->mHasHtmlSupport);
0206 }
0207 
0208 void AutoCorrectionWidget::loadConfig()
0209 {
0210     if (!d->mAutoCorrection) {
0211         return;
0212     }
0213     AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0214     d->ui->autoChangeFormat->setChecked(settings->isAutoBoldUnderline());
0215     d->ui->autoFormatUrl->setChecked(settings->isAutoFormatUrl());
0216     d->ui->enabledAutocorrection->setChecked(settings->isEnabledAutoCorrection());
0217     d->ui->upperCase->setChecked(settings->isUppercaseFirstCharOfSentence());
0218     d->ui->upperUpper->setChecked(settings->isFixTwoUppercaseChars());
0219     d->ui->ignoreDoubleSpace->setChecked(settings->isSingleSpaces());
0220     d->ui->autoReplaceNumber->setChecked(settings->isAutoFractions());
0221     d->ui->capitalizeDaysName->setChecked(settings->isCapitalizeWeekDays());
0222     d->ui->advancedAutocorrection->setChecked(settings->isAdvancedAutocorrect());
0223     d->ui->autoSuperScript->setChecked(settings->isSuperScript());
0224     d->ui->typographicDoubleQuotes->setChecked(settings->isReplaceDoubleQuotes());
0225     d->ui->typographicSingleQuotes->setChecked(settings->isReplaceSingleQuotes());
0226     d->ui->addNonBreakingSpaceInFrench->setChecked(settings->isAddNonBreakingSpace());
0227     d->ui->replaceDoubleQuotesByFrenchQuotes->setChecked(settings->isReplaceDoubleQuotesByFrenchQuotes());
0228 
0229     d->ui->customWritablePath->setText(settings->customWritablePath());
0230     d->ui->customSystemPath->setText(settings->customSystemPath());
0231 
0232     loadAutoCorrectionAndException();
0233     d->mWasChanged = false;
0234 }
0235 
0236 void AutoCorrectionWidget::loadAutoCorrectionAndException()
0237 {
0238     /* tab 2 - Custom Quotes */
0239     AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0240     d->m_singleQuotes = settings->typographicSingleQuotes();
0241     d->ui->simpleQuoteBeginReplace->setText(d->m_singleQuotes.begin);
0242     d->ui->simpleQuoteEndReplace->setText(d->m_singleQuotes.end);
0243     d->m_doubleQuotes = settings->typographicDoubleQuotes();
0244     d->ui->doubleQuoteBeginReplace->setText(d->m_doubleQuotes.begin);
0245     d->ui->doubleQuoteEndReplace->setText(d->m_doubleQuotes.end);
0246     enableSingleQuotes(d->ui->typographicSingleQuotes->isChecked());
0247     enableDoubleQuotes(d->ui->typographicDoubleQuotes->isChecked());
0248 
0249     /* tab 3 - Advanced Autocorrection */
0250     d->m_autocorrectEntries = settings->autocorrectEntries();
0251     addAutoCorrectEntries();
0252 
0253     enableAdvAutocorrection(d->ui->advancedAutocorrection->isChecked());
0254     /* tab 4 - Exceptions */
0255     d->m_upperCaseExceptions = settings->upperCaseExceptions();
0256     d->m_twoUpperLetterExceptions = settings->twoUpperLetterExceptions();
0257 
0258     d->ui->twoUpperLetterList->clear();
0259     d->ui->twoUpperLetterList->addItems(d->m_twoUpperLetterExceptions.values());
0260 
0261     d->ui->abbreviationList->clear();
0262     d->ui->abbreviationList->addItems(d->m_upperCaseExceptions.values());
0263 }
0264 
0265 void AutoCorrectionWidget::addAutoCorrectEntries()
0266 {
0267     d->ui->treeWidget->clear();
0268     QHash<QString, QString>::const_iterator i = d->m_autocorrectEntries.constBegin();
0269     QTreeWidgetItem *item = nullptr;
0270     while (i != d->m_autocorrectEntries.constEnd()) {
0271         item = new QTreeWidgetItem(d->ui->treeWidget, item);
0272         item->setText(0, i.key());
0273         item->setText(1, i.value());
0274         ++i;
0275     }
0276     d->ui->treeWidget->setSortingEnabled(true);
0277     d->ui->treeWidget->sortByColumn(0, Qt::AscendingOrder);
0278 }
0279 
0280 void AutoCorrectionWidget::writeConfig()
0281 {
0282     if (!d->mAutoCorrection) {
0283         return;
0284     }
0285     AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0286     settings->setAutoBoldUnderline(d->ui->autoChangeFormat->isChecked());
0287     settings->setAutoFormatUrl(d->ui->autoFormatUrl->isChecked());
0288     settings->setEnabledAutoCorrection(d->ui->enabledAutocorrection->isChecked());
0289     settings->setUppercaseFirstCharOfSentence(d->ui->upperCase->isChecked());
0290     settings->setFixTwoUppercaseChars(d->ui->upperUpper->isChecked());
0291     settings->setSingleSpaces(d->ui->ignoreDoubleSpace->isChecked());
0292     settings->setCapitalizeWeekDays(d->ui->capitalizeDaysName->isChecked());
0293     settings->setAdvancedAutocorrect(d->ui->advancedAutocorrection->isChecked());
0294     settings->setSuperScript(d->ui->autoSuperScript->isChecked());
0295 
0296     settings->setAutoFractions(d->ui->autoReplaceNumber->isChecked());
0297 
0298     settings->setAutocorrectEntries(d->m_autocorrectEntries);
0299     settings->setUpperCaseExceptions(d->m_upperCaseExceptions);
0300     settings->setTwoUpperLetterExceptions(d->m_twoUpperLetterExceptions);
0301 
0302     settings->setReplaceDoubleQuotes(d->ui->typographicDoubleQuotes->isChecked());
0303     settings->setReplaceSingleQuotes(d->ui->typographicSingleQuotes->isChecked());
0304     settings->setTypographicSingleQuotes(d->m_singleQuotes);
0305     settings->setTypographicDoubleQuotes(d->m_doubleQuotes);
0306     settings->setAddNonBreakingSpace(d->ui->addNonBreakingSpaceInFrench->isChecked());
0307     settings->setReplaceDoubleQuotesByFrenchQuotes(d->ui->replaceDoubleQuotesByFrenchQuotes->isChecked());
0308 
0309     settings->setCustomWritablePath(d->ui->customWritablePath->text());
0310     settings->setCustomSystemPath(d->ui->customSystemPath->text());
0311 
0312     d->mAutoCorrection->setAutoCorrectionSettings(settings);
0313     d->mAutoCorrection->writeConfig();
0314     d->mWasChanged = false;
0315 }
0316 
0317 void AutoCorrectionWidget::resetToDefault()
0318 {
0319     d->ui->autoChangeFormat->setChecked(false);
0320     d->ui->autoFormatUrl->setChecked(false);
0321     d->ui->upperCase->setChecked(false);
0322     d->ui->upperUpper->setChecked(false);
0323     d->ui->ignoreDoubleSpace->setChecked(false);
0324     d->ui->capitalizeDaysName->setChecked(false);
0325     d->ui->advancedAutocorrection->setChecked(false);
0326     d->ui->typographicDoubleQuotes->setChecked(false);
0327     d->ui->typographicSingleQuotes->setChecked(false);
0328     d->ui->autoSuperScript->setChecked(false);
0329     d->ui->autoReplaceNumber->setChecked(false);
0330     d->ui->typographicDoubleQuotes->setChecked(false);
0331     d->ui->typographicSingleQuotes->setChecked(false);
0332     d->ui->addNonBreakingSpaceInFrench->setChecked(false);
0333 
0334     loadGlobalAutoCorrectionAndException();
0335 }
0336 
0337 void AutoCorrectionWidget::enableSingleQuotes(bool state)
0338 {
0339     d->ui->singleQuote1->setEnabled(state);
0340     d->ui->singleQuote2->setEnabled(state);
0341     d->ui->singleDefault->setEnabled(state);
0342 }
0343 
0344 void AutoCorrectionWidget::enableDoubleQuotes(bool state)
0345 {
0346     d->ui->doubleQuote1->setEnabled(state);
0347     d->ui->doubleQuote2->setEnabled(state);
0348     d->ui->doubleDefault->setEnabled(state);
0349 }
0350 
0351 void AutoCorrectionWidget::selectSingleQuoteCharOpen()
0352 {
0353     QPointer<TextAddonsWidgets::SelectSpecialCharDialog> dlg = new TextAddonsWidgets::SelectSpecialCharDialog(this);
0354     dlg->setCurrentChar(d->m_singleQuotes.begin);
0355     dlg->showSelectButton(false);
0356     dlg->autoInsertChar();
0357     if (dlg->exec()) {
0358         d->m_singleQuotes.begin = dlg->currentChar();
0359         d->ui->simpleQuoteBeginReplace->setText(d->m_singleQuotes.begin);
0360         emitChanged();
0361     }
0362     delete dlg;
0363 }
0364 
0365 void AutoCorrectionWidget::selectSingleQuoteCharClose()
0366 {
0367     QPointer<TextAddonsWidgets::SelectSpecialCharDialog> dlg = new TextAddonsWidgets::SelectSpecialCharDialog(this);
0368     dlg->showSelectButton(false);
0369     dlg->setCurrentChar(d->m_singleQuotes.end);
0370     dlg->autoInsertChar();
0371     if (dlg->exec()) {
0372         d->m_singleQuotes.end = dlg->currentChar();
0373         d->ui->simpleQuoteEndReplace->setText(d->m_singleQuotes.end);
0374         emitChanged();
0375     }
0376     delete dlg;
0377 }
0378 
0379 void AutoCorrectionWidget::setDefaultSingleQuotes()
0380 {
0381     d->m_singleQuotes = TextAutoCorrectionCore::AutoCorrectionUtils::typographicDefaultSingleQuotes();
0382     d->ui->simpleQuoteBeginReplace->setText(d->m_singleQuotes.begin);
0383     d->ui->simpleQuoteEndReplace->setText(d->m_singleQuotes.end);
0384     emitChanged();
0385 }
0386 
0387 void AutoCorrectionWidget::selectDoubleQuoteCharOpen()
0388 {
0389     QPointer<TextAddonsWidgets::SelectSpecialCharDialog> dlg = new TextAddonsWidgets::SelectSpecialCharDialog(this);
0390     dlg->showSelectButton(false);
0391     dlg->setCurrentChar(d->m_doubleQuotes.begin);
0392     dlg->autoInsertChar();
0393     if (dlg->exec()) {
0394         d->m_doubleQuotes.begin = dlg->currentChar();
0395         d->ui->doubleQuoteBeginReplace->setText(d->m_doubleQuotes.begin);
0396         emitChanged();
0397     }
0398     delete dlg;
0399 }
0400 
0401 void AutoCorrectionWidget::selectDoubleQuoteCharClose()
0402 {
0403     QPointer<TextAddonsWidgets::SelectSpecialCharDialog> dlg = new TextAddonsWidgets::SelectSpecialCharDialog(this);
0404     dlg->showSelectButton(false);
0405     dlg->setCurrentChar(d->m_doubleQuotes.end);
0406     dlg->autoInsertChar();
0407     if (dlg->exec()) {
0408         d->m_doubleQuotes.end = dlg->currentChar();
0409         d->ui->doubleQuoteEndReplace->setText(d->m_doubleQuotes.end);
0410         emitChanged();
0411     }
0412     delete dlg;
0413 }
0414 
0415 void AutoCorrectionWidget::setDefaultDoubleQuotes()
0416 {
0417     d->m_doubleQuotes = AutoCorrectionUtils::typographicDefaultDoubleQuotes();
0418     d->ui->doubleQuoteBeginReplace->setText(d->m_doubleQuotes.begin);
0419     d->ui->doubleQuoteEndReplace->setText(d->m_doubleQuotes.end);
0420     emitChanged();
0421 }
0422 
0423 void AutoCorrectionWidget::enableAdvAutocorrection(bool state)
0424 {
0425     d->ui->findLabel->setEnabled(state);
0426     d->ui->find->setEnabled(state);
0427     d->ui->replaceLabel->setEnabled(state);
0428     d->ui->replace->setEnabled(state);
0429 
0430     const QString find = d->ui->find->text();
0431     const QString replace = d->ui->replace->text();
0432 
0433     d->ui->addButton->setEnabled(state && !find.isEmpty() && !replace.isEmpty());
0434     d->ui->removeButton->setEnabled(state && d->ui->treeWidget->currentItem());
0435     d->ui->treeWidget->setEnabled(state);
0436 }
0437 
0438 void AutoCorrectionWidget::addAutocorrectEntry()
0439 {
0440     QTreeWidgetItem *item = d->ui->treeWidget->currentItem();
0441     const QString find = d->ui->find->text();
0442     const QString replace = d->ui->replace->text();
0443     if (find == replace) {
0444         KMessageBox::error(this, i18n("\"Replace\" string is the same as \"Find\" string."), i18n("Add Autocorrection Entry"));
0445         return;
0446     }
0447 
0448     bool modify = false;
0449 
0450     // Modify actually, not add, so we want to remove item from hash
0451     if (item && (find == item->text(0))) {
0452         d->m_autocorrectEntries.remove(find);
0453         modify = true;
0454     }
0455 
0456     d->m_autocorrectEntries.insert(find, replace);
0457     d->ui->treeWidget->setSortingEnabled(false);
0458     if (modify) {
0459         item->setText(0, find);
0460         item->setText(1, replace);
0461     } else {
0462         item = new QTreeWidgetItem(d->ui->treeWidget, item);
0463         item->setText(0, find);
0464         item->setText(1, replace);
0465     }
0466 
0467     d->ui->treeWidget->setSortingEnabled(true);
0468     d->ui->treeWidget->setCurrentItem(item);
0469     emitChanged();
0470 }
0471 
0472 void AutoCorrectionWidget::removeAutocorrectEntry()
0473 {
0474     const QList<QTreeWidgetItem *> listItems = d->ui->treeWidget->selectedItems();
0475     if (listItems.isEmpty()) {
0476         return;
0477     }
0478     for (QTreeWidgetItem *item : listItems) {
0479         QTreeWidgetItem *below = d->ui->treeWidget->itemBelow(item);
0480 
0481         QString findStr;
0482         if (below) {
0483             // qCDebug(TEXTAUTOCORRECTION_AUTOCORRECT_LOG) << "below";
0484             findStr = item->text(0);
0485             delete item;
0486             item = nullptr;
0487         } else if (d->ui->treeWidget->topLevelItemCount() > 0) {
0488             findStr = item->text(0);
0489             delete item;
0490             item = nullptr;
0491         }
0492         if (!findStr.isEmpty()) {
0493             d->m_autocorrectEntries.remove(findStr);
0494         }
0495     }
0496     d->ui->treeWidget->setSortingEnabled(false);
0497 
0498     emitChanged();
0499 }
0500 
0501 void AutoCorrectionWidget::updateAddRemoveButton()
0502 {
0503     QList<QTreeWidgetItem *> listItems = d->ui->treeWidget->selectedItems();
0504     d->ui->removeButton->setEnabled(!listItems.isEmpty());
0505 }
0506 
0507 void AutoCorrectionWidget::enableAddRemoveButton()
0508 {
0509     const QString find = d->ui->find->text();
0510     const QString replace = d->ui->replace->text();
0511 
0512     QTreeWidgetItem *item = nullptr;
0513     if (d->m_autocorrectEntries.contains(find)) {
0514         item = d->ui->treeWidget->findItems(find, Qt::MatchCaseSensitive).at(0);
0515     }
0516 
0517     bool enable = false;
0518     if (find.isEmpty() || replace.isEmpty()) { // disable if no text in find/replace
0519         enable = !(find.isEmpty() || replace.isEmpty());
0520     } else if (item && find == item->text(0)) {
0521         // We disable add / remove button if no text for the replacement
0522         enable = !item->text(1).isEmpty();
0523         d->ui->addButton->setText(i18n("&Modify"));
0524     } else if (!item || !item->text(1).isEmpty()) {
0525         enable = true;
0526         d->ui->addButton->setText(i18n("&Add"));
0527     }
0528 
0529     if (item && replace == item->text(1)) {
0530         d->ui->addButton->setEnabled(false);
0531     } else {
0532         d->ui->addButton->setEnabled(enable);
0533     }
0534     d->ui->removeButton->setEnabled(enable);
0535 }
0536 
0537 void AutoCorrectionWidget::setFindReplaceText(QTreeWidgetItem *item, int column)
0538 {
0539     Q_UNUSED(column)
0540     d->ui->find->setText(item->text(0));
0541     d->ui->replace->setText(item->text(1));
0542 }
0543 
0544 void AutoCorrectionWidget::abbreviationChanged(const QString &text)
0545 {
0546     d->ui->add1->setEnabled(!text.isEmpty());
0547 }
0548 
0549 void AutoCorrectionWidget::twoUpperLetterChanged(const QString &text)
0550 {
0551     d->ui->add2->setEnabled(!text.isEmpty());
0552 }
0553 
0554 void AutoCorrectionWidget::addAbbreviationEntry()
0555 {
0556     const QString text = d->ui->abbreviation->text();
0557     if (text.isEmpty()) {
0558         return;
0559     }
0560     if (!d->m_upperCaseExceptions.contains(text)) {
0561         d->m_upperCaseExceptions.insert(text);
0562         d->ui->abbreviationList->addItem(text);
0563     }
0564     d->ui->abbreviation->clear();
0565     slotEnableDisableAbreviationList();
0566     emitChanged();
0567 }
0568 
0569 void AutoCorrectionWidget::removeAbbreviationEntry()
0570 {
0571     const QList<QListWidgetItem *> listItem = d->ui->abbreviationList->selectedItems();
0572     if (listItem.isEmpty()) {
0573         return;
0574     }
0575     for (QListWidgetItem *item : listItem) {
0576         d->m_upperCaseExceptions.remove(item->text());
0577         delete item;
0578     }
0579     slotEnableDisableAbreviationList();
0580     emitChanged();
0581 }
0582 
0583 void AutoCorrectionWidget::addTwoUpperLetterEntry()
0584 {
0585     const QString text = d->ui->twoUpperLetter->text();
0586     if (text.isEmpty()) {
0587         return;
0588     }
0589     if (!d->m_twoUpperLetterExceptions.contains(text)) {
0590         d->m_twoUpperLetterExceptions.insert(text);
0591         d->ui->twoUpperLetterList->addItem(text);
0592         emitChanged();
0593     }
0594     slotEnableDisableTwoUpperEntry();
0595     d->ui->twoUpperLetter->clear();
0596 }
0597 
0598 void AutoCorrectionWidget::removeTwoUpperLetterEntry()
0599 {
0600     const QList<QListWidgetItem *> listItem = d->ui->twoUpperLetterList->selectedItems();
0601     if (listItem.isEmpty()) {
0602         return;
0603     }
0604     for (QListWidgetItem *item : listItem) {
0605         d->m_twoUpperLetterExceptions.remove(item->text());
0606         delete item;
0607     }
0608     slotEnableDisableTwoUpperEntry();
0609     emitChanged();
0610 }
0611 
0612 void AutoCorrectionWidget::slotEnableDisableAbreviationList()
0613 {
0614     const bool enable = (!d->ui->abbreviationList->selectedItems().isEmpty());
0615     d->ui->add1->setEnabled(!d->ui->abbreviation->text().isEmpty());
0616     d->ui->remove1->setEnabled(enable);
0617 }
0618 
0619 void AutoCorrectionWidget::slotEnableDisableTwoUpperEntry()
0620 {
0621     const bool enable = (!d->ui->twoUpperLetterList->selectedItems().isEmpty());
0622     d->ui->add2->setEnabled(!d->ui->twoUpperLetter->text().isEmpty());
0623     d->ui->remove2->setEnabled(enable);
0624 }
0625 
0626 void AutoCorrectionWidget::slotImportAutoCorrection(QAction *act)
0627 {
0628     if (act) {
0629         const auto type = act->data().value<AutoCorrectionWidget::ImportFileType>();
0630         QString title;
0631         QString filter;
0632         switch (type) {
0633         case AutoCorrectionWidget::LibreOffice:
0634             title = i18n("Import LibreOffice Autocorrection");
0635             filter = i18n("LibreOffice Autocorrection File (*.dat)");
0636             break;
0637         case AutoCorrectionWidget::KMail:
0638             title = i18n("Import KMail Autocorrection");
0639             filter = i18n("KMail Autocorrection File (*.xml)");
0640             break;
0641         }
0642         const QString fileName = QFileDialog::getOpenFileName(this, title, QString(), filter);
0643         if (!fileName.isEmpty()) {
0644             TextAutoCorrectionCore::ImportAbstractAutocorrection *importAutoCorrection = nullptr;
0645             switch (type) {
0646             case AutoCorrectionWidget::LibreOffice:
0647                 importAutoCorrection = new TextAutoCorrectionCore::ImportLibreOfficeAutocorrection;
0648                 break;
0649             case AutoCorrectionWidget::KMail:
0650                 importAutoCorrection = new TextAutoCorrectionCore::ImportKMailAutocorrection;
0651                 break;
0652             default:
0653                 return;
0654             }
0655             QString messageError;
0656             if (importAutoCorrection->import(fileName, messageError, ImportAbstractAutocorrection::All)) {
0657                 d->m_autocorrectEntries = importAutoCorrection->autocorrectEntries();
0658                 addAutoCorrectEntries();
0659 
0660                 enableAdvAutocorrection(d->ui->advancedAutocorrection->isChecked());
0661 
0662                 d->m_upperCaseExceptions = importAutoCorrection->upperCaseExceptions();
0663                 d->m_twoUpperLetterExceptions = importAutoCorrection->twoUpperLetterExceptions();
0664 
0665                 d->ui->twoUpperLetterList->clear();
0666                 d->ui->twoUpperLetterList->addItems(d->m_twoUpperLetterExceptions.values());
0667 
0668                 d->ui->abbreviationList->clear();
0669                 d->ui->abbreviationList->addItems(d->m_upperCaseExceptions.values());
0670             } else {
0671                 KMessageBox::error(this, messageError, i18n("Import Autocorrection File"));
0672             }
0673             delete importAutoCorrection;
0674         }
0675     }
0676 }
0677 
0678 void AutoCorrectionWidget::setLanguage(const QString &lang)
0679 {
0680     TextAutoCorrectionCore::AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0681     settings->setLanguage(lang);
0682     d->mAutoCorrection->setAutoCorrectionSettings(settings);
0683     loadAutoCorrectionAndException();
0684     d->mWasChanged = false;
0685 }
0686 
0687 void AutoCorrectionWidget::changeLanguage(int index)
0688 {
0689     if (index == -1) {
0690         return;
0691     }
0692     if (d->mWasChanged) {
0693         const int rc = KMessageBox::warningTwoActions(this,
0694                                                       i18n("Language was changed, do you want to save config for previous language?"),
0695                                                       i18n("Save config"),
0696                                                       KStandardGuiItem::save(),
0697                                                       KStandardGuiItem::discard());
0698         if (rc == KMessageBox::ButtonCode::PrimaryAction) {
0699             writeConfig();
0700         }
0701     }
0702     const QString lang = d->ui->autocorrectionLanguage->itemData(index).toString();
0703     TextAutoCorrectionCore::AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0704     settings->setLanguage(lang);
0705     d->mAutoCorrection->setAutoCorrectionSettings(settings);
0706     loadAutoCorrectionAndException();
0707     d->mWasChanged = false;
0708 }
0709 
0710 void AutoCorrectionWidget::emitChanged()
0711 {
0712     d->mWasChanged = true;
0713     Q_EMIT changed();
0714 }
0715 
0716 void AutoCorrectionWidget::loadGlobalAutoCorrectionAndException()
0717 {
0718     const QString lang = d->ui->autocorrectionLanguage->itemData(d->ui->autocorrectionLanguage->currentIndex()).toString();
0719     TextAutoCorrectionCore::AutoCorrectionSettings *settings = d->mAutoCorrection->autoCorrectionSettings();
0720     settings->setLanguage(lang, true);
0721     d->mAutoCorrection->setAutoCorrectionSettings(settings);
0722     loadAutoCorrectionAndException();
0723     d->mWasChanged = true;
0724     Q_EMIT changed();
0725 }
0726 
0727 void AutoCorrectionWidget::slotExportAutoCorrection()
0728 {
0729     if (d->mWasChanged) {
0730         KMessageBox::error(this, i18n("Please save changes before exporting settings."), i18n("Export Autocorrection File"));
0731         return;
0732     }
0733     const QString saveUrl = QFileDialog::getSaveFileName(this, i18n("Export Autocorrection File"), QDir::homePath());
0734     if (saveUrl.isEmpty()) {
0735         return;
0736     }
0737     d->mAutoCorrection->writeAutoCorrectionXmlFile(saveUrl);
0738 }
0739 
0740 #include "moc_autocorrectionwidget.cpp"