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(i18nc("@action:button Replace all occurrences", "&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 q->KFind::d->dialog->deleteLater(); q->KFind::d->dialog = 0L;
00273 } else
00274 emit q->findNext();
00275 }
00276
00277 void KReplacePrivate::_k_slotReplace()
00278 {
00279 doReplace();
00280 if ( q->KFind::d->dialogClosed ) {
00281 q->KFind::d->dialog->deleteLater(); q->KFind::d->dialog = 0L;
00282 } else
00283 emit q->findNext();
00284 }
00285
00286 void KReplacePrivate::doReplace()
00287 {
00288 int replacedLength = replace(q->KFind::d->text, m_replacement, q->KFind::d->index, q->KFind::d->options, q->KFind::d->matchedLength);
00289
00290
00291
00292 emit q->replace(q->KFind::d->text, q->KFind::d->index, replacedLength, q->KFind::d->matchedLength);
00293 #ifdef DEBUG_REPLACE
00294 kDebug() << "after replace() signal: KFind::d->index=" << q->KFind::d->index << " replacedLength=" << replacedLength;
00295 #endif
00296 m_replacements++;
00297 if (q->KFind::d->options & KFind::FindBackwards)
00298 q->KFind::d->index--;
00299 else {
00300 q->KFind::d->index += replacedLength;
00301
00302 if ( q->KFind::d->pattern.isEmpty() )
00303 ++(q->KFind::d->index);
00304 }
00305 #ifdef DEBUG_REPLACE
00306 kDebug() << "after adjustement: KFind::d->index=" << q->KFind::d->index;
00307 #endif
00308 }
00309
00310 void KReplace::resetCounts()
00311 {
00312 KFind::resetCounts();
00313 d->m_replacements = 0;
00314 }
00315
00316 bool KReplace::shouldRestart( bool forceAsking, bool showNumMatches ) const
00317 {
00318
00319
00320
00321
00322 if ( !forceAsking && (KFind::d->options & KFind::FromCursor) == 0
00323 && (KFind::d->options & KReplaceDialog::PromptOnReplace) == 0 )
00324 {
00325 displayFinalDialog();
00326 return false;
00327 }
00328 QString message;
00329 if ( showNumMatches )
00330 {
00331 if ( !d->m_replacements )
00332 message = i18n("No text was replaced.");
00333 else
00334 message = i18np("1 replacement done.", "%1 replacements done.", d->m_replacements );
00335 }
00336 else
00337 {
00338 if ( KFind::d->options & KFind::FindBackwards )
00339 message = i18n( "Beginning of document reached." );
00340 else
00341 message = i18n( "End of document reached." );
00342 }
00343
00344 message += '\n';
00345
00346 message +=
00347 ( KFind::d->options & KFind::FindBackwards ) ?
00348 i18n("Do you want to restart search from the end?")
00349 : i18n("Do you want to restart search at the beginning?");
00350
00351 int ret = KMessageBox::questionYesNo( parentWidget(), message, QString(),
00352 KGuiItem(i18nc("@action:button Restart find & replace", "Restart")),
00353 KGuiItem(i18nc("@action:button Stop find & replace", "Stop")) );
00354 return( ret == KMessageBox::Yes );
00355 }
00356
00357 void KReplace::closeReplaceNextDialog()
00358 {
00359 closeFindNextDialog();
00360 }
00361
00362 #include "kreplace.moc"