1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2001 S.R. Haque <srhaque@iee.org>.
4 SPDX-FileCopyrightText: 2002 David Faure <david@mandrakesoft.com>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "kreplacedialog.h"
10#include "kfinddialog_p.h"
11
12#include <QCheckBox>
13#include <QGridLayout>
14#include <QGroupBox>
15#include <QLineEdit>
16#include <QRegularExpression>
17
18#include <KHistoryComboBox>
19#include <KLocalizedString>
20#include <KMessageBox>
21
22/**
23 * we need to insert the strings after the dialog is set
24 * up, otherwise QComboBox will deliver an awful big sizeHint
25 * for long replacement texts.
26 */
27class KReplaceDialogPrivate : public KFindDialogPrivate
28{
29 Q_DECLARE_PUBLIC(KReplaceDialog)
30
31public:
32 explicit KReplaceDialogPrivate(KReplaceDialog *qq)
33 : KFindDialogPrivate(qq)
34 {
35 }
36
37 void slotOk();
38
39 QStringList replaceStrings;
40 mutable QWidget *replaceExtension = nullptr;
41 bool initialShowDone = false;
42};
43
44KReplaceDialog::KReplaceDialog(QWidget *parent, long options, const QStringList &findStrings, const QStringList &replaceStrings, bool hasSelection)
45 : KFindDialog(*new KReplaceDialogPrivate(this), parent, options, findStrings, hasSelection, true /*create replace dialog*/)
46{
47 Q_D(KReplaceDialog);
48
49 d->replaceStrings = replaceStrings;
50}
51
52KReplaceDialog::~KReplaceDialog() = default;
53
54void KReplaceDialog::showEvent(QShowEvent *e)
55{
56 Q_D(KReplaceDialog);
57
58 if (!d->initialShowDone) {
59 d->initialShowDone = true; // only once
60
61 if (!d->replaceStrings.isEmpty()) {
62 setReplacementHistory(d->replaceStrings);
63 d->replace->lineEdit()->setText(d->replaceStrings[0]);
64 }
65 }
66
67 KFindDialog::showEvent(e);
68}
69
70long KReplaceDialog::options() const
71{
72 Q_D(const KReplaceDialog);
73
74 long options = 0;
75
76 options = KFindDialog::options();
77 if (d->promptOnReplace->isChecked()) {
78 options |= PromptOnReplace;
79 }
80 if (d->backRef->isChecked()) {
81 options |= BackReference;
82 }
83 return options;
84}
85
86QWidget *KReplaceDialog::replaceExtension() const
87{
88 Q_D(const KReplaceDialog);
89
90 if (!d->replaceExtension) {
91 d->replaceExtension = new QWidget(d->replaceGrp);
92 d->replaceLayout->addWidget(d->replaceExtension, row: 3, column: 0, rowSpan: 1, columnSpan: 2);
93 }
94
95 return d->replaceExtension;
96}
97
98QString KReplaceDialog::replacement() const
99{
100 Q_D(const KReplaceDialog);
101
102 return d->replace->currentText();
103}
104
105QStringList KReplaceDialog::replacementHistory() const
106{
107 Q_D(const KReplaceDialog);
108
109 QStringList lst = d->replace->historyItems();
110 // historyItems() doesn't tell us about the case of replacing with an empty string
111 if (d->replace->lineEdit()->text().isEmpty()) {
112 lst.prepend(t: QString());
113 }
114 return lst;
115}
116
117void KReplaceDialog::setOptions(long options)
118{
119 Q_D(KReplaceDialog);
120
121 KFindDialog::setOptions(options);
122 d->promptOnReplace->setChecked(options & PromptOnReplace);
123 d->backRef->setChecked(options & BackReference);
124}
125
126void KReplaceDialog::setReplacementHistory(const QStringList &strings)
127{
128 Q_D(KReplaceDialog);
129
130 if (!strings.isEmpty()) {
131 d->replace->setHistoryItems(items: strings, setCompletionList: true);
132 } else {
133 d->replace->clearHistory();
134 }
135}
136
137void KReplaceDialogPrivate::slotOk()
138{
139 Q_Q(KReplaceDialog);
140
141 // If regex and backrefs are enabled, do a sanity check.
142 if (regExp->isChecked() && backRef->isChecked()) {
143 const QRegularExpression re(q->pattern(), QRegularExpression::UseUnicodePropertiesOption);
144 const int caps = re.captureCount();
145
146 const QString rep = q->replacement();
147 const QRegularExpression check(QStringLiteral("((?:\\\\)+)(\\d+)"));
148 auto iter = check.globalMatch(subject: rep);
149 while (iter.hasNext()) {
150 const QRegularExpressionMatch match = iter.next();
151 if ((match.captured(nth: 1).size() % 2) && match.captured(nth: 2).toInt() > caps) {
152 KMessageBox::information(parent: q,
153 i18n("Your replacement string is referencing a capture greater than '\\%1', ", caps)
154 + (caps ? i18np("but your pattern only defines 1 capture.", "but your pattern only defines %1 captures.", caps)
155 : i18n("but your pattern defines no captures."))
156 + i18n("\nPlease correct."));
157 return; // abort OKing
158 }
159 }
160 }
161
162 slotOk();
163 replace->addToHistory(item: q->replacement());
164}
165
166#include "moc_kreplacedialog.cpp"
167

source code of ktextwidgets/src/findreplace/kreplacedialog.cpp