• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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     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 // this loop is only because validateMatch can fail
00155     {
00156 #ifdef DEBUG_REPLACE
00157         kDebug() << "beginning of loop: KFind::d->index=" << KFind::d->index;
00158 #endif
00159         // Find the next match.
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             // Flexibility: the app can add more rules to validate a possible match
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                     // Display accurate initial string and replacement string, they can vary
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                     // Tell the world about the match we found, in case someone wants to
00186                     // highlight it.
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(); // this moves on too
00195                 }
00196             }
00197             else
00198             {
00199                 // not validated -> move on
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; // will exit the loop
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     // Backreferences: replace \0 with the right portion of 'text'
00250     if ( options & KReplaceDialog::BackReference )
00251         rep.replace( "\\0", text.mid( index, length ) );
00252     // Then replace rep into the text
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; // hide it again
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; // hide it again
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     // Tell the world about the replacement we made, in case someone wants to
00291     // highlight it.
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         // when replacing the empty pattern, move on. See also kjs/regexp.cpp for how this should be done for regexps.
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     // Only ask if we did a "find from cursor", otherwise it's pointless.
00319     // ... Or if the prompt-on-replace option was set.
00320     // Well, unless the user can modify the document during a search operation,
00321     // hence the force boolean.
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     // Hope this word puzzle is ok, it's a different sentence
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"

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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