• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kreplace.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2001, S.R.Haque <srhaque@iee.org>.
00003     Copyright (C) 2002, David Faure <david@mandrakesoft.com>
00004     This file is part of the KDE project
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License version 2, as published by the Free Software Foundation.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
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 //#define DEBUG_REPLACE
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 
00056     m_mainLabel = new QLabel( this );
00057     setMainWidget( m_mainLabel );
00058 }
00059 
00060 void KReplaceNextDialog::setLabel( const QString& pattern, const QString& replacement )
00061 {
00062     m_mainLabel->setText( i18n("Replace '%1' with '%2'?", pattern, replacement) );
00063 }
00064 
00066 
00067 class KReplacePrivate
00068 {
00069 public:
00070     KReplacePrivate(KReplace *q, const QString& replacement)
00071         : q(q)
00072         , m_replacement( replacement )
00073         , m_replacements( 0 )
00074     {}
00075 
00076     KReplaceNextDialog* dialog();
00077     void doReplace();
00078 
00079     void _k_slotSkip();
00080     void _k_slotReplace();
00081     void _k_slotReplaceAll();
00082 
00083     KReplace *q;
00084     QString m_replacement;
00085     unsigned m_replacements;
00086 };
00087 
00088 
00090 
00091 KReplace::KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent) :
00092     KFind( pattern, options, parent ),
00093     d( new KReplacePrivate(this, replacement) )
00094 {
00095 }
00096 
00097 KReplace::KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent, QWidget *dlg) :
00098     KFind( pattern, options, parent, dlg ),
00099     d( new KReplacePrivate(this, replacement) )
00100 {
00101 }
00102 
00103 KReplace::~KReplace()
00104 {
00105     delete d;
00106 }
00107 
00108 int KReplace::numReplacements() const
00109 {
00110     return d->m_replacements;
00111 }
00112 
00113 KDialog* KReplace::replaceNextDialog( bool create )
00114 {
00115     if ( KFind::d->dialog || create )
00116         return d->dialog();
00117     return 0L;
00118 }
00119 
00120 KReplaceNextDialog* KReplacePrivate::dialog()
00121 {
00122     if ( !q->KFind::d->dialog )
00123     {
00124         q->KFind::d->dialog = new KReplaceNextDialog( q->parentWidget() );
00125         q->connect( q->KFind::d->dialog, SIGNAL( user1Clicked() ), q, SLOT( _k_slotReplaceAll() ) );
00126         q->connect( q->KFind::d->dialog, SIGNAL( user2Clicked() ), q, SLOT( _k_slotSkip() ) );
00127         q->connect( q->KFind::d->dialog, SIGNAL( user3Clicked() ), q, SLOT( _k_slotReplace() ) );
00128         q->connect( q->KFind::d->dialog, SIGNAL( finished() ), q, SLOT( _k_slotDialogClosed() ) );
00129     }
00130     return static_cast<KReplaceNextDialog *>(q->KFind::d->dialog);
00131 }
00132 
00133 void KReplace::displayFinalDialog() const
00134 {
00135     if ( !d->m_replacements )
00136         KMessageBox::information(parentWidget(), i18n("No text was replaced."));
00137     else
00138         KMessageBox::information(parentWidget(), i18np("1 replacement done.", "%1 replacements done.", d->m_replacements ) );
00139 }
00140 
00141 static int replaceHelper(QString &text, const QString &replacement, int index, long options, int length, const QRegExp* regExp)
00142 {
00143     QString rep(replacement);
00144     if (options & KReplaceDialog::BackReference) {
00145         // Backreferences: replace \0 with the right portion of 'text'
00146         rep.replace( "\\0", text.mid( index, length ) );
00147 
00148         // Other backrefs
00149         if (regExp) {
00150             const QStringList caps = regExp->capturedTexts();
00151             for (int i = 0; i < caps.count(); ++i) {
00152                 rep.replace( "\\" + QString::number(i), caps.at(i) );
00153             }
00154         }
00155     }
00156 
00157     // Then replace rep into the text
00158     text.replace(index, length, rep);
00159     return rep.length();
00160 }
00161 
00162 KFind::Result KReplace::replace()
00163 {
00164     KFind::Private* df = KFind::d;
00165 #ifdef DEBUG_REPLACE
00166     kDebug() << "d->index=" << df->index;
00167 #endif
00168     if ( df->index == INDEX_NOMATCH && df->lastResult == Match )
00169     {
00170         df->lastResult = NoMatch;
00171         return NoMatch;
00172     }
00173 
00174     do // this loop is only because validateMatch can fail
00175     {
00176 #ifdef DEBUG_REPLACE
00177         kDebug() << "beginning of loop: df->index=" << df->index;
00178 #endif
00179         // Find the next match.
00180         if ( df->options & KFind::RegularExpression )
00181             df->index = KFind::find(df->text, *df->regExp, df->index, df->options, &df->matchedLength);
00182         else
00183             df->index = KFind::find(df->text, df->pattern, df->index, df->options, &df->matchedLength);
00184 
00185 #ifdef DEBUG_REPLACE
00186         kDebug() << "KFind::find returned df->index=" << df->index;
00187 #endif
00188         if ( df->index != -1 )
00189         {
00190             // Flexibility: the app can add more rules to validate a possible match
00191             if ( validateMatch( df->text, df->index, df->matchedLength ) )
00192             {
00193                 if ( df->options & KReplaceDialog::PromptOnReplace )
00194                 {
00195 #ifdef DEBUG_REPLACE
00196                     kDebug() << "PromptOnReplace";
00197 #endif
00198                     // Display accurate initial string and replacement string, they can vary
00199                     QString matchedText (df->text.mid( df->index, df->matchedLength ));
00200                     QString rep (matchedText);
00201                     replaceHelper(rep, d->m_replacement, 0, df->options, df->matchedLength, df->regExp);
00202                     d->dialog()->setLabel( matchedText, rep );
00203                     d->dialog()->show(); // TODO kde5: virtual void showReplaceNextDialog(QString,QString), so that kreplacetest can skip the show()
00204 
00205                     // Tell the world about the match we found, in case someone wants to
00206                     // highlight it.
00207                     emit highlight(df->text, df->index, df->matchedLength);
00208 
00209                     df->lastResult = Match;
00210                     return Match;
00211                 }
00212                 else
00213                 {
00214                     d->doReplace(); // this moves on too
00215                 }
00216             }
00217             else
00218             {
00219                 // not validated -> move on
00220                 if (df->options & KFind::FindBackwards)
00221                     df->index--;
00222                 else
00223                     df->index++;
00224             }
00225         } else
00226             df->index = INDEX_NOMATCH; // will exit the loop
00227     }
00228     while (df->index != INDEX_NOMATCH);
00229 
00230     df->lastResult = NoMatch;
00231     return NoMatch;
00232 }
00233 
00234 int KReplace::replace(QString &text, const QString &pattern, const QString &replacement, int index, long options, int *replacedLength)
00235 {
00236     int matchedLength;
00237 
00238     index = KFind::find(text, pattern, index, options, &matchedLength);
00239     if (index != -1)
00240     {
00241         *replacedLength = replaceHelper(text, replacement, index, options, matchedLength, NULL);
00242         if (options & KFind::FindBackwards)
00243             index--;
00244         else
00245             index += *replacedLength;
00246     }
00247     return index;
00248 }
00249 
00250 int KReplace::replace(QString &text, const QRegExp &pattern, const QString &replacement, int index, long options, int *replacedLength)
00251 {
00252     int matchedLength;
00253 
00254     index = KFind::find(text, pattern, index, options, &matchedLength);
00255     if (index != -1)
00256     {
00257         *replacedLength = replaceHelper(text, replacement, index, options, matchedLength, &pattern);
00258         if (options & KFind::FindBackwards)
00259             index--;
00260         else
00261             index += *replacedLength;
00262     }
00263     return index;
00264 }
00265 
00266 void KReplacePrivate::_k_slotReplaceAll()
00267 {
00268     doReplace();
00269     q->KFind::d->options &= ~KReplaceDialog::PromptOnReplace;
00270     emit q->optionsChanged();
00271     emit q->findNext();
00272 }
00273 
00274 void KReplacePrivate::_k_slotSkip()
00275 {
00276     if (q->KFind::d->options & KFind::FindBackwards)
00277         q->KFind::d->index--;
00278     else
00279         q->KFind::d->index++;
00280     if ( q->KFind::d->dialogClosed ) {
00281         q->KFind::d->dialog->deleteLater(); q->KFind::d->dialog = 0L; // hide it again
00282     } else
00283         emit q->findNext();
00284 }
00285 
00286 void KReplacePrivate::_k_slotReplace()
00287 {
00288     doReplace();
00289     if ( q->KFind::d->dialogClosed ) {
00290         q->KFind::d->dialog->deleteLater(); q->KFind::d->dialog = 0L; // hide it again
00291     } else
00292         emit q->findNext();
00293 }
00294 
00295 void KReplacePrivate::doReplace()
00296 {
00297     KFind::Private* df = q->KFind::d;
00298     Q_ASSERT(df->index >= 0);
00299     const int replacedLength = replaceHelper(df->text, m_replacement, df->index, df->options, df->matchedLength, df->regExp);
00300 
00301     // Tell the world about the replacement we made, in case someone wants to
00302     // highlight it.
00303     emit q->replace(df->text, df->index, replacedLength, df->matchedLength);
00304 #ifdef DEBUG_REPLACE
00305     kDebug() << "after replace() signal: KFind::d->index=" << df->index << " replacedLength=" << replacedLength;
00306 #endif
00307     m_replacements++;
00308     if (df->options & KFind::FindBackwards) {
00309         Q_ASSERT(df->index >= 0);
00310         df->index--;
00311     } else {
00312         df->index += replacedLength;
00313         // when replacing the empty pattern, move on. See also kjs/regexp.cpp for how this should be done for regexps.
00314         if ( df->pattern.isEmpty() )
00315             ++(df->index);
00316     }
00317 #ifdef DEBUG_REPLACE
00318     kDebug() << "after adjustement: KFind::d->index=" << df->index;
00319 #endif
00320 }
00321 
00322 void KReplace::resetCounts()
00323 {
00324     KFind::resetCounts();
00325     d->m_replacements = 0;
00326 }
00327 
00328 bool KReplace::shouldRestart( bool forceAsking, bool showNumMatches ) const
00329 {
00330     // Only ask if we did a "find from cursor", otherwise it's pointless.
00331     // ... Or if the prompt-on-replace option was set.
00332     // Well, unless the user can modify the document during a search operation,
00333     // hence the force boolean.
00334     if ( !forceAsking && (KFind::d->options & KFind::FromCursor) == 0
00335          && (KFind::d->options & KReplaceDialog::PromptOnReplace) == 0 )
00336     {
00337         displayFinalDialog();
00338         return false;
00339     }
00340     QString message;
00341     if ( showNumMatches )
00342     {
00343         if ( !d->m_replacements )
00344             message = i18n("No text was replaced.");
00345         else
00346             message = i18np("1 replacement done.", "%1 replacements done.", d->m_replacements );
00347     }
00348     else
00349     {
00350         if ( KFind::d->options & KFind::FindBackwards )
00351             message = i18n( "Beginning of document reached." );
00352         else
00353             message = i18n( "End of document reached." );
00354     }
00355 
00356     message += '\n';
00357     // Hope this word puzzle is ok, it's a different sentence
00358     message +=
00359         ( KFind::d->options & KFind::FindBackwards ) ?
00360         i18n("Do you want to restart search from the end?")
00361         : i18n("Do you want to restart search at the beginning?");
00362 
00363     int ret = KMessageBox::questionYesNo( parentWidget(), message, QString(),
00364                                           KGuiItem(i18nc("@action:button Restart find & replace", "Restart")),
00365                                           KGuiItem(i18nc("@action:button Stop find & replace", "Stop")) );
00366     return( ret == KMessageBox::Yes );
00367 }
00368 
00369 void KReplace::closeReplaceNextDialog()
00370 {
00371     closeFindNextDialog();
00372 }
00373 
00374 #include "kreplace.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal