kutils Library API Documentation

kreplace.cpp

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., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include <qlabel.h>
00022 #include <kapplication.h>
00023 #include <kdebug.h>
00024 
00025 #include <klocale.h>
00026 #include <kmessagebox.h>
00027 #include "kreplace.h"
00028 #include "kreplacedialog.h"
00029 #include <qregexp.h>
00030 
00031 //#define DEBUG_REPLACE
00032 #define INDEX_NOMATCH -1
00033 
00034 class KReplaceNextDialog : public KDialogBase
00035 {
00036 public:
00037     KReplaceNextDialog( QWidget *parent );
00038     void setLabel( const QString& pattern, const QString& replacement );
00039 private:
00040     QLabel* m_mainLabel;
00041 };
00042 
00043 KReplaceNextDialog::KReplaceNextDialog(QWidget *parent) :
00044     KDialogBase(parent, 0, false,  // non-modal!
00045         i18n("Replace"),
00046         User3 | User2 | User1 | Close,
00047         User3,
00048         false,
00049         i18n("&All"), i18n("&Skip"), i18n("&Yes"))
00050 {
00051     m_mainLabel = new QLabel( this );
00052     setMainWidget( m_mainLabel );
00053     resize(minimumSize());
00054 }
00055 
00056 void KReplaceNextDialog::setLabel( const QString& pattern, const QString& replacement )
00057 {
00058     m_mainLabel->setText( i18n("Replace '%1' with '%2'?").arg(pattern).arg(replacement) );
00059 }
00060 
00062 
00063 KReplace::KReplace(const QString &pattern, const QString &replacement, long options, QWidget *parent) :
00064     KFind( pattern, options, parent )
00065 {
00066     m_replacements = 0;
00067     m_replacement = replacement;
00068 }
00069 
00070 KReplace::~KReplace()
00071 {
00072     // KFind::~KFind will delete m_dialog
00073 }
00074 
00075 KDialogBase* KReplace::replaceNextDialog( bool create )
00076 {
00077     if ( m_dialog || create )
00078         return dialog();
00079     return 0L;
00080 }
00081 
00082 KReplaceNextDialog* KReplace::dialog()
00083 {
00084     if ( !m_dialog )
00085     {
00086         m_dialog = new KReplaceNextDialog( parentWidget() );
00087         connect( m_dialog, SIGNAL( user1Clicked() ), this, SLOT( slotReplaceAll() ) );
00088         connect( m_dialog, SIGNAL( user2Clicked() ), this, SLOT( slotSkip() ) );
00089         connect( m_dialog, SIGNAL( user3Clicked() ), this, SLOT( slotReplace() ) );
00090         connect( m_dialog, SIGNAL( finished() ), this, SLOT( slotDialogClosed() ) );
00091     }
00092     return static_cast<KReplaceNextDialog *>(m_dialog);
00093 }
00094 
00095 void KReplace::displayFinalDialog() const
00096 {
00097     if ( !m_replacements )
00098         KMessageBox::information(parentWidget(), i18n("No text was replaced."));
00099     else
00100         KMessageBox::information(parentWidget(), i18n("1 replacement done.", "%n replacements done.", m_replacements ) );
00101 }
00102 
00103 KFind::Result KReplace::replace()
00104 {
00105 #ifdef DEBUG_REPLACE
00106     kdDebug() << k_funcinfo << "m_index=" << m_index << endl;
00107 #endif
00108     Q_ASSERT( m_index != INDEX_NOMATCH );
00109 
00110     if ( m_lastResult == Match )
00111     {
00112         // Move on before doing a match
00113         if (m_options & KFindDialog::FindBackwards) {
00114             m_index--;
00115             if ( m_index == -1 ) // don't call KFind::find with -1, it has a special meaning
00116             {
00117                 m_lastResult = NoMatch;
00118                 return NoMatch;
00119             }
00120         } else
00121             m_index++;
00122     }
00123 
00124     do // this loop is only because validateMatch can fail
00125     {
00126 #ifdef DEBUG_REPLACE
00127         kdDebug() << k_funcinfo << "beginning of loop: m_index=" << m_index << endl;
00128 #endif
00129         // Find the next match.
00130         if ( m_options & KReplaceDialog::RegularExpression )
00131             m_index = KFind::find(m_text, *m_regExp, m_index, m_options, &m_matchedLength);
00132         else
00133             m_index = KFind::find(m_text, m_pattern, m_index, m_options, &m_matchedLength);
00134 #ifdef DEBUG_REPLACE
00135         kdDebug() << k_funcinfo << "KFind::find returned m_index=" << m_index << endl;
00136 #endif
00137         if ( m_index != -1 )
00138         {
00139             // Flexibility: the app can add more rules to validate a possible match
00140             if ( validateMatch( m_text, m_index, m_matchedLength ) )
00141             {
00142                 if ( m_options & KReplaceDialog::PromptOnReplace )
00143                 {
00144 #ifdef DEBUG_REPLACE
00145                     kdDebug() << k_funcinfo << "PromptOnReplace" << endl;
00146 #endif
00147                     // Display accurate initial string and replacement string, they can vary
00148                     QString matchedText = m_text.mid( m_index, m_matchedLength );
00149                     QString rep = matchedText;
00150                     KReplace::replace(rep, m_replacement, 0, m_matchedLength);
00151                     dialog()->setLabel( matchedText, rep );
00152                     dialog()->show();
00153 
00154                     // Tell the world about the match we found, in case someone wants to
00155                     // highlight it.
00156                     emit highlight(m_text, m_index, m_matchedLength);
00157 
00158                     m_lastResult = Match;
00159                     return Match;
00160                 }
00161                 else
00162                 {
00163                     doReplace();
00164                 }
00165             }
00166             // not validated, or auto-replaced -> move on
00167             if (m_options & KFindDialog::FindBackwards)
00168                 m_index--;
00169             else
00170                 m_index++;
00171         } else
00172             m_index = INDEX_NOMATCH; // will exit the loop
00173     }
00174     while (m_index != INDEX_NOMATCH);
00175 
00176     m_lastResult = NoMatch;
00177     return NoMatch;
00178 }
00179 
00180 int KReplace::replace(QString &text, const QString &pattern, const QString &replacement, int index, long options, int *replacedLength)
00181 {
00182     int matchedLength;
00183 
00184     index = KFind::find(text, pattern, index, options, &matchedLength);
00185     if (index != -1)
00186     {
00187         *replacedLength = replace(text, replacement, index, matchedLength);
00188         if (options & KReplaceDialog::FindBackwards)
00189             index--;
00190         else
00191             index += *replacedLength;
00192     }
00193     return index;
00194 }
00195 
00196 int KReplace::replace(QString &text, const QRegExp &pattern, const QString &replacement, int index, long options, int *replacedLength)
00197 {
00198     int matchedLength;
00199 
00200     index = KFind::find(text, pattern, index, options, &matchedLength);
00201     if (index != -1)
00202     {
00203         *replacedLength = replace(text, replacement, index, matchedLength);
00204         if (options & KReplaceDialog::FindBackwards)
00205             index--;
00206         else
00207             index += *replacedLength;
00208     }
00209     return index;
00210 }
00211 
00212 int KReplace::replace(QString &text, const QString &replacement, int index, int length)
00213 {
00214     // Backreferences: replace /0 with the right portion of 'text'
00215     QString rep = replacement;
00216     rep.replace( QRegExp("/0"), text.mid( index, length ) );
00217     // Then replace rep into the text
00218     text.replace(index, length, rep);
00219     return rep.length();
00220 }
00221 
00222 void KReplace::slotReplaceAll()
00223 {
00224     doReplace();
00225     m_options &= ~KReplaceDialog::PromptOnReplace;
00226     emit optionsChanged();
00227     emit findNext();
00228 }
00229 
00230 void KReplace::slotSkip()
00231 {
00232     if (m_options & KReplaceDialog::FindBackwards)
00233         m_index--;
00234     else
00235         m_index++;
00236     if ( m_dialogClosed ) {
00237         delete m_dialog; // hide it again
00238         m_dialog = 0L;
00239     } else
00240         emit findNext();
00241 }
00242 
00243 void KReplace::slotReplace()
00244 {
00245     doReplace();
00246     if ( m_dialogClosed ) {
00247         delete m_dialog; // hide it again
00248         m_dialog = 0L;
00249     } else
00250         emit findNext();
00251 }
00252 
00253 void KReplace::doReplace()
00254 {
00255     int replacedLength = KReplace::replace(m_text, m_replacement, m_index, m_matchedLength);
00256 
00257     // Tell the world about the replacement we made, in case someone wants to
00258     // highlight it.
00259     emit replace(m_text, m_index, replacedLength, m_matchedLength);
00260 #ifdef DEBUG_REPLACE
00261     kdDebug() << k_funcinfo << "after replace() signal: m_index=" << m_index << " replacedLength=" << replacedLength << endl;
00262 #endif
00263     m_replacements++;
00264     if (m_options & KReplaceDialog::FindBackwards)
00265         m_index--;
00266     else
00267         m_index += replacedLength;
00268 #ifdef DEBUG_REPLACE
00269     kdDebug() << k_funcinfo << "after adjustement: m_index=" << m_index << endl;
00270 #endif
00271 }
00272 
00273 void KReplace::resetCounts()
00274 {
00275     KFind::resetCounts();
00276     m_replacements = 0;
00277 }
00278 
00279 bool KReplace::shouldRestart( bool forceAsking, bool /*showNumMatches*/ ) const
00280 {
00281     // Only ask if we did a "find from cursor", otherwise it's pointless.
00282     // ... Or if the prompt-on-replace option was set.
00283     // Well, unless the user can modify the document during a search operation,
00284     // hence the force boolean.
00285     if ( !forceAsking && (m_options & KFindDialog::FromCursor) == 0
00286          && (m_options & KReplaceDialog::PromptOnReplace) == 0 )
00287     {
00288         displayFinalDialog();
00289         return false;
00290     }
00291     QString message;
00292     if ( m_options & KFindDialog::FindBackwards )
00293         message = i18n( "Beginning of document reached.\n"\
00294                         "Continue from the end?" );
00295     else
00296         message = i18n( "End of document reached.\n"\
00297                         "Continue from the beginning?" );
00298 
00299     int ret = KMessageBox::questionYesNo( parentWidget(), message );
00300     return( ret == KMessageBox::Yes );
00301 }
00302 
00303 void KReplace::closeReplaceNextDialog()
00304 {
00305     closeFindNextDialog();
00306 }
00307 
00308 #include "kreplace.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:55 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001