File indexing completed on 2024-12-01 03:43:35
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 #ifndef KREPLACE_H 0010 #define KREPLACE_H 0011 0012 #include "kfind.h" 0013 0014 #include "ktextwidgets_export.h" 0015 0016 class KReplacePrivate; 0017 0018 /** 0019 * @class KReplace kreplace.h <KReplace> 0020 * 0021 * @brief A generic implementation of the "replace" function. 0022 * 0023 * @author S.R.Haque <srhaque@iee.org>, David Faure <faure@kde.org> 0024 * 0025 * \b Detail: 0026 * 0027 * This class includes prompt handling etc. Also provides some 0028 * static functions which can be used to create custom behavior 0029 * instead of using the class directly. 0030 * 0031 * \b Example: 0032 * 0033 * To use the class to implement a complete replace feature: 0034 * 0035 * In the slot connect to the replace action, after using KReplaceDialog: 0036 * \code 0037 * 0038 * // This creates a replace-on-prompt dialog if needed. 0039 * m_replace = new KReplace(pattern, replacement, options, this); 0040 * 0041 * // Connect signals to code which handles highlighting of found text, and 0042 * // on-the-fly replacement. 0043 * connect(m_replace, &KFind::textFound, this, [this](const QString &text, int matchingIndex, int matchedLength) { 0044 * slotHighlight(text, matchingIndex, matchedLength); 0045 * }); 0046 * // Connect findNext signal - called when pressing the button in the dialog 0047 * connect( m_replace, SIGNAL( findNext() ), 0048 * this, SLOT( slotReplaceNext() ) ); 0049 * // Connect to the textReplaced() signal - emitted when a replacement is done 0050 * connect( m_replace, &KReplace::textReplaced, this, [this](const QString &text, int replacementIndex, int replacedLength, int matchedLength) { 0051 * slotReplace(text, replacementIndex, replacedLength, matchedLength); 0052 * }); 0053 * \endcode 0054 * Then initialize the variables determining the "current position" 0055 * (to the cursor, if the option FromCursor is set, 0056 * to the beginning of the selection if the option SelectedText is set, 0057 * and to the beginning of the document otherwise). 0058 * Initialize the "end of search" variables as well (end of doc or end of selection). 0059 * Swap begin and end if FindBackwards. 0060 * Finally, call slotReplaceNext(); 0061 * 0062 * \code 0063 * void slotReplaceNext() 0064 * { 0065 * KFind::Result res = KFind::NoMatch; 0066 * while ( res == KFind::NoMatch && <position not at end> ) { 0067 * if ( m_replace->needData() ) 0068 * m_replace->setData( <current text fragment> ); 0069 * 0070 * // Let KReplace inspect the text fragment, and display a dialog if a match is found 0071 * res = m_replace->replace(); 0072 * 0073 * if ( res == KFind::NoMatch ) { 0074 * <Move to the next text fragment, honoring the FindBackwards setting for the direction> 0075 * } 0076 * } 0077 * 0078 * if ( res == KFind::NoMatch ) // i.e. at end 0079 * <Call either m_replace->displayFinalDialog(); delete m_replace; m_replace = nullptr; 0080 * or if ( m_replace->shouldRestart() ) { reinit (w/o FromCursor) and call slotReplaceNext(); } 0081 * else { m_replace->closeReplaceNextDialog(); }> 0082 * } 0083 * \endcode 0084 * 0085 * Don't forget delete m_find in the destructor of your class, 0086 * unless you gave it a parent widget on construction. 0087 * 0088 */ 0089 class KTEXTWIDGETS_EXPORT KReplace : public KFind 0090 { 0091 Q_OBJECT 0092 0093 public: 0094 /** 0095 * Only use this constructor if you don't use KFindDialog, or if 0096 * you use it as a modal dialog. 0097 */ 0098 KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent = nullptr); 0099 /** 0100 * This is the recommended constructor if you also use KReplaceDialog (non-modal). 0101 * You should pass the pointer to it here, so that when a message box 0102 * appears it has the right parent. Don't worry about deletion, KReplace 0103 * will notice if the find dialog is closed. 0104 */ 0105 KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent, QWidget *replaceDialog); 0106 0107 ~KReplace() override; 0108 0109 /** 0110 * Return the number of replacements made (i.e. the number of times 0111 * the textReplaced() signal was emitted). 0112 * 0113 * Can be used in a dialog box to tell the user how many replacements were made. 0114 * The final dialog does so already, unless you used setDisplayFinalDialog(false). 0115 */ 0116 int numReplacements() const; 0117 0118 /** 0119 * Call this to reset the numMatches & numReplacements counts. 0120 * Can be useful if reusing the same KReplace for different operations, 0121 * or when restarting from the beginning of the document. 0122 */ 0123 void resetCounts() override; 0124 0125 /** 0126 * Walk the text fragment (e.g. kwrite line, kspread cell) looking for matches. 0127 * For each match, if prompt-on-replace is specified, emits the textFound() signal 0128 * and displays the prompt-for-replace dialog before doing the replace. 0129 */ 0130 Result replace(); 0131 0132 /** 0133 * Return (or create) the dialog that shows the "find next?" prompt. 0134 * Usually you don't need to call this. 0135 * One case where it can be useful, is when the user selects the "Find" 0136 * menu item while a find operation is under way. In that case, the 0137 * program may want to call setActiveWindow() on that dialog. 0138 */ 0139 QDialog *replaceNextDialog(bool create = false); 0140 0141 /** 0142 * Close the "replace next?" dialog. The application should do this when 0143 * the last match was hit. If the application deletes the KReplace, then 0144 * "find previous" won't be possible anymore. 0145 */ 0146 void closeReplaceNextDialog(); 0147 0148 /** 0149 * Searches the given @p text for @p pattern; if a match is found it is replaced 0150 * with @p replacement and the index of the replacement string is returned. 0151 * 0152 * @param text The string to search 0153 * @param pattern The pattern to search for 0154 * @param replacement The replacement string to insert into the text 0155 * @param index The starting index into the string 0156 * @param options The options to use 0157 * @param replacedLength Output parameter, contains the length of the replaced string 0158 * Not always the same as replacement.length(), when backreferences are used 0159 * @return The index at which a match was found, or -1 otherwise 0160 */ 0161 static int replace(QString &text, const QString &pattern, const QString &replacement, int index, long options, int *replacedLength); 0162 0163 /** 0164 * Returns true if we should restart the search from scratch. 0165 * Can ask the user, or return false (if we already searched/replaced the 0166 * whole document without the PromptOnReplace option). 0167 * 0168 * @param forceAsking set to true if the user modified the document during the 0169 * search. In that case it makes sense to restart the search again. 0170 * 0171 * @param showNumMatches set to true if the dialog should show the number of 0172 * matches. Set to false if the application provides a "find previous" action, 0173 * in which case the match count will be erroneous when hitting the end, 0174 * and we could even be hitting the beginning of the document (so not all 0175 * matches have even been seen). 0176 */ 0177 bool shouldRestart(bool forceAsking = false, bool showNumMatches = true) const override; 0178 0179 /** 0180 * Displays the final dialog telling the user how many replacements were made. 0181 * Call either this or shouldRestart(). 0182 */ 0183 void displayFinalDialog() const override; 0184 0185 Q_SIGNALS: 0186 /** 0187 * Connect to this signal to implement updating of replaced text during the replace 0188 * operation. 0189 * 0190 * Extra care must be taken to properly implement the "no prompt-on-replace" case. 0191 * For instance, the textFound() signal isn't emitted in that case (some code 0192 * might rely on it), and for performance reasons one should repaint after 0193 * replace() ONLY if prompt-on-replace was selected. 0194 * 0195 * @param text The text, in which the replacement has already been done 0196 * @param replacementIndex Starting index of the matched substring 0197 * @param replacedLength Length of the replacement string 0198 * @param matchedLength Length of the matched string 0199 * 0200 * @since 5.83 0201 */ 0202 void textReplaced(const QString &text, int replacementIndex, int replacedLength, int matchedLength); 0203 0204 private: 0205 Q_DECLARE_PRIVATE(KReplace) 0206 }; 0207 #endif