00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kreplace.h"
00022 #include "kfind_p.h"
00023
00024 #include <QtGui/QLabel>
00025 #include <kapplication.h>
00026 #include <kdebug.h>
00027
00028 #include <klocale.h>
00029 #include <kmessagebox.h>
00030 #include "kreplacedialog.h"
00031 #include <QtCore/QRegExp>
00032
00033
00034 #define INDEX_NOMATCH -1
00035
00036 class KReplaceNextDialog : public KDialog
00037 {
00038 public:
00039 explicit KReplaceNextDialog( QWidget *parent );
00040 void setLabel( const QString& pattern, const QString& replacement );
00041 private:
00042 QLabel* m_mainLabel;
00043 };
00044
00045 KReplaceNextDialog::KReplaceNextDialog(QWidget *parent) :
00046 KDialog(parent)
00047 {
00048 setModal( false );
00049 setCaption( i18n("Replace") );
00050 setButtons( User3 | User2 | User1 | Close );
00051 setButtonGuiItem( User1, KGuiItem(i18n("&All")) );
00052 setButtonGuiItem( User2, KGuiItem(i18n("&Skip")) );
00053 setButtonGuiItem( User3, KGuiItem(i18n("Replace")) );
00054 setDefaultButton( User3 );
00055 showButtonSeparator( false );
00056
00057 m_mainLabel = new QLabel( this );
00058 setMainWidget( m_mainLabel );
00059 }
00060
00061 void KReplaceNextDialog::setLabel( const QString& pattern, const QString& replacement )
00062 {
00063 m_mainLabel->setText( i18n("Replace '%1' with '%2'?", pattern, replacement) );
00064 }
00065
00067
00068 class KReplacePrivate
00069 {
00070 public:
00071 KReplacePrivate(KReplace *q, const QString& replacement)
00072 : q(q)
00073 , m_replacement( replacement )
00074 , m_replacements( 0 )
00075 {}
00076
00077 KReplaceNextDialog* dialog();
00078 void doReplace();
00079 static int replace( QString &text, const QString &replacement, int index, long options, int length );
00080
00081 void _k_slotSkip();
00082 void _k_slotReplace();
00083 void _k_slotReplaceAll();
00084
00085 KReplace *q;
00086 QString m_replacement;
00087 unsigned m_replacements;
00088 };
00089
00090
00092
00093 KReplace::KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent) :
00094 KFind( pattern, options, parent ),
00095 d( new KReplacePrivate(this, replacement) )
00096 {
00097 }
00098
00099 KReplace::KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent, QWidget *dlg) :
00100 KFind( pattern, options, parent, dlg ),
00101 d( new KReplacePrivate(this, replacement) )
00102 {
00103 }
00104
00105 KReplace::~KReplace()
00106 {
00107 delete d;
00108 }
00109
00110 int KReplace::numReplacements() const
00111 {
00112 return d->m_replacements;
00113 }
00114
00115 KDialog* KReplace::replaceNextDialog( bool create )
00116 {
00117 if ( KFind::d->dialog || create )
00118 return d->dialog();
00119 return 0L;
00120 }
00121
00122 KReplaceNextDialog* KReplacePrivate::dialog()
00123 {
00124 if ( !q->KFind::d->dialog )
00125 {
00126 q->KFind::d->dialog = new KReplaceNextDialog( q->parentWidget() );
00127 q->connect( q->KFind::d->dialog, SIGNAL( user1Clicked() ), q, SLOT( _k_slotReplaceAll() ) );
00128 q->connect( q->KFind::d->dialog, SIGNAL( user2Clicked() ), q, SLOT( _k_slotSkip() ) );
00129 q->connect( q->KFind::d->dialog, SIGNAL( user3Clicked() ), q, SLOT( _k_slotReplace() ) );
00130 q->connect( q->KFind::d->dialog, SIGNAL( finished() ), q, SLOT( _k_slotDialogClosed() ) );
00131 }
00132 return static_cast<KReplaceNextDialog *>(q->KFind::d->dialog);
00133 }
00134
00135 void KReplace::displayFinalDialog() const
00136 {
00137 if ( !d->m_replacements )
00138 KMessageBox::information(parentWidget(), i18n("No text was replaced."));
00139 else
00140 KMessageBox::information(parentWidget(), i18np("1 replacement done.", "%1 replacements done.", d->m_replacements ) );
00141 }
00142
00143 KFind::Result KReplace::replace()
00144 {
00145 #ifdef DEBUG_REPLACE
00146 kDebug() << "d->index=" << KFind::d->index;
00147 #endif
00148 if ( KFind::d->index == INDEX_NOMATCH && KFind::d->lastResult == Match )
00149 {
00150 KFind::d->lastResult = NoMatch;
00151 return NoMatch;
00152 }
00153
00154 do
00155 {
00156 #ifdef DEBUG_REPLACE
00157 kDebug() << "beginning of loop: KFind::d->index=" << KFind::d->index;
00158 #endif
00159
00160 if ( KFind::d->options & KFind::RegularExpression )
00161 KFind::d->index = KFind::find(KFind::d->text, *KFind::d->regExp, KFind::d->index, KFind::d->options, &KFind::d->matchedLength);
00162 else
00163 KFind::d->index = KFind::find(KFind::d->text, KFind::d->pattern, KFind::d->index, KFind::d->options, &KFind::d->matchedLength);
00164
00165 #ifdef DEBUG_REPLACE
00166 kDebug() << "KFind::find returned KFind::d->index=" << KFind::d->index;
00167 #endif
00168 if ( KFind::d->index != -1 )
00169 {
00170
00171 if ( validateMatch( KFind::d->text, KFind::d->index, KFind::d->matchedLength ) )
00172 {
00173 if ( KFind::d->options & KReplaceDialog::PromptOnReplace )
00174 {
00175 #ifdef DEBUG_REPLACE
00176 kDebug() << "PromptOnReplace";
00177 #endif
00178
00179 QString matchedText (KFind::d->text.mid( KFind::d->index, KFind::d->matchedLength ));
00180 QString rep (matchedText);
00181 d->KReplacePrivate::replace(rep, d->m_replacement, 0, KFind::d->options, KFind::d->matchedLength);
00182 d->dialog()->setLabel( matchedText, rep );
00183 d->dialog()->show();
00184
00185
00186
00187 emit highlight(KFind::d->text, KFind::d->index, KFind::d->matchedLength);
00188
00189 KFind::d->lastResult = Match;
00190 return Match;
00191 }
00192 else
00193 {
00194 d->doReplace();
00195 }
00196 }
00197 else
00198 {
00199
00200 if (KFind::d->options & KFind::FindBackwards)
00201 KFind::d->index--;
00202 else
00203 KFind::d->index++;
00204 }
00205 } else
00206 KFind::d->index = INDEX_NOMATCH;
00207 }
00208 while (KFind::d->index != INDEX_NOMATCH);
00209
00210 KFind::d->lastResult = NoMatch;
00211 return NoMatch;
00212 }
00213
00214 int KReplace::replace(QString &text, const QString &pattern, const QString &replacement, int index, long options, int *replacedLength)
00215 {
00216 int matchedLength;
00217
00218 index = KFind::find(text, pattern, index, options, &matchedLength);
00219 if (index != -1)
00220 {
00221 *replacedLength = KReplacePrivate::replace(text, replacement, index, options, matchedLength);
00222 if (options & KFind::FindBackwards)
00223 index--;
00224 else
00225 index += *replacedLength;
00226 }
00227 return index;
00228 }
00229
00230 int KReplace::replace(QString &text, const QRegExp &pattern, const QString &replacement, int index, long options, int *replacedLength)
00231 {
00232 int matchedLength;
00233
00234 index = KFind::find(text, pattern, index, options, &matchedLength);
00235 if (index != -1)
00236 {
00237 *replacedLength = KReplacePrivate::replace(text, replacement, index, options, matchedLength);
00238 if (options & KFind::FindBackwards)
00239 index--;
00240 else
00241 index += *replacedLength;
00242 }
00243 return index;
00244 }
00245
00246 int KReplacePrivate::replace(QString &text, const QString &replacement, int index, long options, int length)
00247 {
00248 QString rep (replacement);
00249
00250 if ( options & KReplaceDialog::BackReference )
00251 rep.replace( "\\0", text.mid( index, length ) );
00252
00253 text.replace(index, length, rep);
00254 return rep.length();
00255 }
00256
00257 void KReplacePrivate::_k_slotReplaceAll()
00258 {
00259 doReplace();
00260 q->KFind::d->options &= ~KReplaceDialog::PromptOnReplace;
00261 emit q->optionsChanged();
00262 emit q->findNext();
00263 }
00264
00265 void KReplacePrivate::_k_slotSkip()
00266 {
00267 if (q->KFind::d->options & KFind::FindBackwards)
00268 q->KFind::d->index--;
00269 else
00270 q->KFind::d->index++;
00271 if ( q->KFind::d->dialogClosed ) {
00272 delete q->KFind::d->dialog;
00273 q->KFind::d->dialog = 0L;
00274 } else
00275 emit q->findNext();
00276 }
00277
00278 void KReplacePrivate::_k_slotReplace()
00279 {
00280 doReplace();
00281 if ( q->KFind::d->dialogClosed ) {
00282 delete q->KFind::d->dialog;
00283 q->KFind::d->dialog = 0L;
00284 } else
00285 emit q->findNext();
00286 }
00287
00288 void KReplacePrivate::doReplace()
00289 {
00290 int replacedLength = replace(q->KFind::d->text, m_replacement, q->KFind::d->index, q->KFind::d->options, q->KFind::d->matchedLength);
00291
00292
00293
00294 emit q->replace(q->KFind::d->text, q->KFind::d->index, replacedLength, q->KFind::d->matchedLength);
00295 #ifdef DEBUG_REPLACE
00296 kDebug() << "after replace() signal: KFind::d->index=" << q->KFind::d->index << " replacedLength=" << replacedLength;
00297 #endif
00298 m_replacements++;
00299 if (q->KFind::d->options & KFind::FindBackwards)
00300 q->KFind::d->index--;
00301 else {
00302 q->KFind::d->index += replacedLength;
00303
00304 if ( q->KFind::d->pattern.isEmpty() )
00305 ++(q->KFind::d->index);
00306 }
00307 #ifdef DEBUG_REPLACE
00308 kDebug() << "after adjustement: KFind::d->index=" << q->KFind::d->index;
00309 #endif
00310 }
00311
00312 void KReplace::resetCounts()
00313 {
00314 KFind::resetCounts();
00315 d->m_replacements = 0;
00316 }
00317
00318 bool KReplace::shouldRestart( bool forceAsking, bool showNumMatches ) const
00319 {
00320
00321
00322
00323
00324 if ( !forceAsking && (KFind::d->options & KFind::FromCursor) == 0
00325 && (KFind::d->options & KReplaceDialog::PromptOnReplace) == 0 )
00326 {
00327 displayFinalDialog();
00328 return false;
00329 }
00330 QString message;
00331 if ( showNumMatches )
00332 {
00333 if ( !d->m_replacements )
00334 message = i18n("No text was replaced.");
00335 else
00336 message = i18np("1 replacement done.", "%1 replacements done.", d->m_replacements );
00337 }
00338 else
00339 {
00340 if ( KFind::d->options & KFind::FindBackwards )
00341 message = i18n( "Beginning of document reached." );
00342 else
00343 message = i18n( "End of document reached." );
00344 }
00345
00346 message += '\n';
00347
00348 message +=
00349 ( KFind::d->options & KFind::FindBackwards ) ?
00350 i18n("Do you want to restart search from the end?")
00351 : i18n("Do you want to restart search at the beginning?");
00352
00353 int ret = KMessageBox::questionYesNo( parentWidget(), message, QString(), KGuiItem(i18n("Restart")), KGuiItem(i18n("Stop")) );
00354 return( ret == KMessageBox::Yes );
00355 }
00356
00357 void KReplace::closeReplaceNextDialog()
00358 {
00359 closeFindNextDialog();
00360 }
00361
00362 #include "kreplace.moc"