File indexing completed on 2024-12-08 03:43:01
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2001 S.R. Haque <srhaque@iee.org>. 0004 SPDX-FileCopyrightText: 2002 David Faure <david@mandrakesoft.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #include "kreplacedialog.h" 0010 #include "kfinddialog_p.h" 0011 0012 #include <QCheckBox> 0013 #include <QGridLayout> 0014 #include <QGroupBox> 0015 #include <QLineEdit> 0016 #include <QRegularExpression> 0017 0018 #include <KHistoryComboBox> 0019 #include <KLocalizedString> 0020 #include <KMessageBox> 0021 0022 /** 0023 * we need to insert the strings after the dialog is set 0024 * up, otherwise QComboBox will deliver an awful big sizeHint 0025 * for long replacement texts. 0026 */ 0027 class KReplaceDialogPrivate : public KFindDialogPrivate 0028 { 0029 Q_DECLARE_PUBLIC(KReplaceDialog) 0030 0031 public: 0032 explicit KReplaceDialogPrivate(KReplaceDialog *qq) 0033 : KFindDialogPrivate(qq) 0034 { 0035 } 0036 0037 void slotOk(); 0038 0039 QStringList replaceStrings; 0040 mutable QWidget *replaceExtension = nullptr; 0041 bool initialShowDone = false; 0042 }; 0043 0044 KReplaceDialog::KReplaceDialog(QWidget *parent, long options, const QStringList &findStrings, const QStringList &replaceStrings, bool hasSelection) 0045 : KFindDialog(*new KReplaceDialogPrivate(this), parent, options, findStrings, hasSelection, true /*create replace dialog*/) 0046 { 0047 Q_D(KReplaceDialog); 0048 0049 d->replaceStrings = replaceStrings; 0050 } 0051 0052 KReplaceDialog::~KReplaceDialog() = default; 0053 0054 void KReplaceDialog::showEvent(QShowEvent *e) 0055 { 0056 Q_D(KReplaceDialog); 0057 0058 if (!d->initialShowDone) { 0059 d->initialShowDone = true; // only once 0060 0061 if (!d->replaceStrings.isEmpty()) { 0062 setReplacementHistory(d->replaceStrings); 0063 d->replace->lineEdit()->setText(d->replaceStrings[0]); 0064 } 0065 } 0066 0067 KFindDialog::showEvent(e); 0068 } 0069 0070 long KReplaceDialog::options() const 0071 { 0072 Q_D(const KReplaceDialog); 0073 0074 long options = 0; 0075 0076 options = KFindDialog::options(); 0077 if (d->promptOnReplace->isChecked()) { 0078 options |= PromptOnReplace; 0079 } 0080 if (d->backRef->isChecked()) { 0081 options |= BackReference; 0082 } 0083 return options; 0084 } 0085 0086 QWidget *KReplaceDialog::replaceExtension() const 0087 { 0088 Q_D(const KReplaceDialog); 0089 0090 if (!d->replaceExtension) { 0091 d->replaceExtension = new QWidget(d->replaceGrp); 0092 d->replaceLayout->addWidget(d->replaceExtension, 3, 0, 1, 2); 0093 } 0094 0095 return d->replaceExtension; 0096 } 0097 0098 QString KReplaceDialog::replacement() const 0099 { 0100 Q_D(const KReplaceDialog); 0101 0102 return d->replace->currentText(); 0103 } 0104 0105 QStringList KReplaceDialog::replacementHistory() const 0106 { 0107 Q_D(const KReplaceDialog); 0108 0109 QStringList lst = d->replace->historyItems(); 0110 // historyItems() doesn't tell us about the case of replacing with an empty string 0111 if (d->replace->lineEdit()->text().isEmpty()) { 0112 lst.prepend(QString()); 0113 } 0114 return lst; 0115 } 0116 0117 void KReplaceDialog::setOptions(long options) 0118 { 0119 Q_D(KReplaceDialog); 0120 0121 KFindDialog::setOptions(options); 0122 d->promptOnReplace->setChecked(options & PromptOnReplace); 0123 d->backRef->setChecked(options & BackReference); 0124 } 0125 0126 void KReplaceDialog::setReplacementHistory(const QStringList &strings) 0127 { 0128 Q_D(KReplaceDialog); 0129 0130 if (!strings.isEmpty()) { 0131 d->replace->setHistoryItems(strings, true); 0132 } else { 0133 d->replace->clearHistory(); 0134 } 0135 } 0136 0137 void KReplaceDialogPrivate::slotOk() 0138 { 0139 Q_Q(KReplaceDialog); 0140 0141 // If regex and backrefs are enabled, do a sanity check. 0142 if (regExp->isChecked() && backRef->isChecked()) { 0143 const QRegularExpression re(q->pattern(), QRegularExpression::UseUnicodePropertiesOption); 0144 const int caps = re.captureCount(); 0145 0146 const QString rep = q->replacement(); 0147 const QRegularExpression check(QStringLiteral("((?:\\\\)+)(\\d+)")); 0148 auto iter = check.globalMatch(rep); 0149 while (iter.hasNext()) { 0150 const QRegularExpressionMatch match = iter.next(); 0151 if ((match.captured(1).size() % 2) && match.captured(2).toInt() > caps) { 0152 KMessageBox::information(q, 0153 i18n("Your replacement string is referencing a capture greater than '\\%1', ", caps) 0154 + (caps ? i18np("but your pattern only defines 1 capture.", "but your pattern only defines %1 captures.", caps) 0155 : i18n("but your pattern defines no captures.")) 0156 + i18n("\nPlease correct.")); 0157 return; // abort OKing 0158 } 0159 } 0160 } 0161 0162 slotOk(); 0163 replace->addToHistory(q->replacement()); 0164 } 0165 0166 #include "moc_kreplacedialog.cpp"