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#ifndef KREPLACE_H
10#define KREPLACE_H
11
12#include "kfind.h"
13
14#include "ktextwidgets_export.h"
15
16class KReplacePrivate;
17
18/**
19 * @class KReplace kreplace.h <KReplace>
20 *
21 * @brief A generic implementation of the "replace" function.
22 *
23 * @author S.R.Haque <srhaque@iee.org>, David Faure <faure@kde.org>
24 *
25 * \b Detail:
26 *
27 * This class includes prompt handling etc. Also provides some
28 * static functions which can be used to create custom behavior
29 * instead of using the class directly.
30 *
31 * \b Example:
32 *
33 * To use the class to implement a complete replace feature:
34 *
35 * In the slot connect to the replace action, after using KReplaceDialog:
36 * \code
37 *
38 * // This creates a replace-on-prompt dialog if needed.
39 * m_replace = new KReplace(pattern, replacement, options, this);
40 *
41 * // Connect signals to code which handles highlighting of found text, and
42 * // on-the-fly replacement.
43 * connect(m_replace, &KFind::textFound, this, [this](const QString &text, int matchingIndex, int matchedLength) {
44 * slotHighlight(text, matchingIndex, matchedLength);
45 * });
46 * // Connect findNext signal - called when pressing the button in the dialog
47 * connect( m_replace, SIGNAL( findNext() ),
48 * this, SLOT( slotReplaceNext() ) );
49 * // Connect to the textReplaced() signal - emitted when a replacement is done
50 * connect( m_replace, &KReplace::textReplaced, this, [this](const QString &text, int replacementIndex, int replacedLength, int matchedLength) {
51 * slotReplace(text, replacementIndex, replacedLength, matchedLength);
52 * });
53 * \endcode
54 * Then initialize the variables determining the "current position"
55 * (to the cursor, if the option FromCursor is set,
56 * to the beginning of the selection if the option SelectedText is set,
57 * and to the beginning of the document otherwise).
58 * Initialize the "end of search" variables as well (end of doc or end of selection).
59 * Swap begin and end if FindBackwards.
60 * Finally, call slotReplaceNext();
61 *
62 * \code
63 * void slotReplaceNext()
64 * {
65 * KFind::Result res = KFind::NoMatch;
66 * while ( res == KFind::NoMatch && <position not at end> ) {
67 * if ( m_replace->needData() )
68 * m_replace->setData( <current text fragment> );
69 *
70 * // Let KReplace inspect the text fragment, and display a dialog if a match is found
71 * res = m_replace->replace();
72 *
73 * if ( res == KFind::NoMatch ) {
74 * <Move to the next text fragment, honoring the FindBackwards setting for the direction>
75 * }
76 * }
77 *
78 * if ( res == KFind::NoMatch ) // i.e. at end
79 * <Call either m_replace->displayFinalDialog(); delete m_replace; m_replace = nullptr;
80 * or if ( m_replace->shouldRestart() ) { reinit (w/o FromCursor) and call slotReplaceNext(); }
81 * else { m_replace->closeReplaceNextDialog(); }>
82 * }
83 * \endcode
84 *
85 * Don't forget delete m_find in the destructor of your class,
86 * unless you gave it a parent widget on construction.
87 *
88 */
89class KTEXTWIDGETS_EXPORT KReplace : public KFind
90{
91 Q_OBJECT
92
93public:
94 /**
95 * Only use this constructor if you don't use KFindDialog, or if
96 * you use it as a modal dialog.
97 */
98 KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent = nullptr);
99 /**
100 * This is the recommended constructor if you also use KReplaceDialog (non-modal).
101 * You should pass the pointer to it here, so that when a message box
102 * appears it has the right parent. Don't worry about deletion, KReplace
103 * will notice if the find dialog is closed.
104 */
105 KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent, QWidget *replaceDialog);
106
107 ~KReplace() override;
108
109 /**
110 * Return the number of replacements made (i.e. the number of times
111 * the textReplaced() signal was emitted).
112 *
113 * Can be used in a dialog box to tell the user how many replacements were made.
114 * The final dialog does so already, unless you used setDisplayFinalDialog(false).
115 */
116 int numReplacements() const;
117
118 /**
119 * Call this to reset the numMatches & numReplacements counts.
120 * Can be useful if reusing the same KReplace for different operations,
121 * or when restarting from the beginning of the document.
122 */
123 void resetCounts() override;
124
125 /**
126 * Walk the text fragment (e.g. kwrite line, kspread cell) looking for matches.
127 * For each match, if prompt-on-replace is specified, emits the textFound() signal
128 * and displays the prompt-for-replace dialog before doing the replace.
129 */
130 Result replace();
131
132 /**
133 * Return (or create) the dialog that shows the "find next?" prompt.
134 * Usually you don't need to call this.
135 * One case where it can be useful, is when the user selects the "Find"
136 * menu item while a find operation is under way. In that case, the
137 * program may want to call setActiveWindow() on that dialog.
138 */
139 QDialog *replaceNextDialog(bool create = false);
140
141 /**
142 * Close the "replace next?" dialog. The application should do this when
143 * the last match was hit. If the application deletes the KReplace, then
144 * "find previous" won't be possible anymore.
145 */
146 void closeReplaceNextDialog();
147
148 /**
149 * Searches the given @p text for @p pattern; if a match is found it is replaced
150 * with @p replacement and the index of the replacement string is returned.
151 *
152 * @param text The string to search
153 * @param pattern The pattern to search for
154 * @param replacement The replacement string to insert into the text
155 * @param index The starting index into the string
156 * @param options The options to use
157 * @param replacedLength Output parameter, contains the length of the replaced string
158 * Not always the same as replacement.length(), when backreferences are used
159 * @return The index at which a match was found, or -1 otherwise
160 */
161 static int replace(QString &text, const QString &pattern, const QString &replacement, int index, long options, int *replacedLength);
162
163 /**
164 * Returns true if we should restart the search from scratch.
165 * Can ask the user, or return false (if we already searched/replaced the
166 * whole document without the PromptOnReplace option).
167 *
168 * @param forceAsking set to true if the user modified the document during the
169 * search. In that case it makes sense to restart the search again.
170 *
171 * @param showNumMatches set to true if the dialog should show the number of
172 * matches. Set to false if the application provides a "find previous" action,
173 * in which case the match count will be erroneous when hitting the end,
174 * and we could even be hitting the beginning of the document (so not all
175 * matches have even been seen).
176 */
177 bool shouldRestart(bool forceAsking = false, bool showNumMatches = true) const override;
178
179 /**
180 * Displays the final dialog telling the user how many replacements were made.
181 * Call either this or shouldRestart().
182 */
183 void displayFinalDialog() const override;
184
185Q_SIGNALS:
186 /**
187 * Connect to this signal to implement updating of replaced text during the replace
188 * operation.
189 *
190 * Extra care must be taken to properly implement the "no prompt-on-replace" case.
191 * For instance, the textFound() signal isn't emitted in that case (some code
192 * might rely on it), and for performance reasons one should repaint after
193 * replace() ONLY if prompt-on-replace was selected.
194 *
195 * @param text The text, in which the replacement has already been done
196 * @param replacementIndex Starting index of the matched substring
197 * @param replacedLength Length of the replacement string
198 * @param matchedLength Length of the matched string
199 *
200 * @since 5.83
201 */
202 void textReplaced(const QString &text, int replacementIndex, int replacedLength, int matchedLength);
203
204private:
205 Q_DECLARE_PRIVATE(KReplace)
206};
207#endif
208

source code of ktextwidgets/src/findreplace/kreplace.h