kate Library: katesearch.cpp Source File (kate Library)

| # kate Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# katesearch.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 2003 Clarence Dang <dang@kde.org>
    00003    Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
    00004    Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
    00005    Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
    00006    Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
    00007
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License version 2 as published by the Free Software Foundation.
    00011
    00012    This library is distributed in the hope that it will be useful,
    00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015    Library General Public License for more details.
    00016
    00017    You should have received a copy of the GNU Library General Public License
    00018    along with this library; see the file COPYING.LIB.  If not, write to
    00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020    Boston, MA 02111-1307, USA.
    00021 */
    00022
    00023 #include "katesearch.h"
    00024 #include "katesearch.moc"
    00025
    00026 #include "kateview.h"
    00027 #include "katedocument.h"
    00028 #include "katesupercursor.h"
    00029 #include "katearbitraryhighlight.h"
    00030 #include "kateconfig.h"
    00031
    00032 #include <klocale.h>
    00033 #include <kstdaction.h>
    00034 #include <kmessagebox.h>
    00035 #include <kstringhandler.h>
    00036 #include <kdebug.h>
    00037 #include <kfinddialog.h>
    00038 #include <kreplacedialog.h>
    00039
    00040 #include <qlayout.h>
    00041 #include <qlabel.h>
    00042
    00043 //BEGIN KateSearch
    00044 QStringList KateSearch::s_searchList  = QStringList();
    00045 QStringList KateSearch::s_replaceList = QStringList();
    00046 QString KateSearch::s_pattern = QString();
    00047 static const bool arbitraryHLExample = false;
    00048
    00049 KateSearch::KateSearch( KateView* view )
    00050   : QObject( view, "kate search" )
    00051   , m_view( view )
    00052   , m_doc( view->doc() )
    00053   , replacePrompt( new KateReplacePrompt( view ) )
    00054 {
    00055   m_arbitraryHLList = new KateSuperRangeList();
    00056   if (arbitraryHLExample) m_doc->arbitraryHL()->addHighlightToView(m_arbitraryHLList, m_view);
    00057
    00058   connect(replacePrompt,SIGNAL(clicked()),this,SLOT(replaceSlot()));
    00059 }
    00060
    00061 KateSearch::~KateSearch()
    00062 {
    00063   delete m_arbitraryHLList;
    00064 }
    00065
    00066 void KateSearch::createActions( KActionCollection* ac )
    00067 {
    00068   KStdAction::find( this, SLOT(find()), ac )->setWhatsThis(
    00069     i18n("Look up the first occurrence of a piece of text or regular expression."));
    00070   KStdAction::findNext( this, SLOT(slotFindNext()), ac )->setWhatsThis(
    00071     i18n("Look up the next occurrence of the search phrase."));
    00072   KStdAction::findPrev( this, SLOT(slotFindPrev()), ac, "edit_find_prev" )->setWhatsThis(
    00073     i18n("Look up the previous occurrence of the search phrase."));
    00074   KStdAction::replace( this, SLOT(replace()), ac )->setWhatsThis(
    00075     i18n("Look up a piece of text or regular expression and replace the result with some given text."));
    00076 }
    00077
    00078 void KateSearch::addToList( QStringList& list, const QString& s )
    00079 {
    00080   if( list.count() > 0 ) {
    00081     QStringList::Iterator it = list.find( s );
    00082     if( *it != 0L )
    00083       list.remove( it );
    00084     if( list.count() >= 16 )
    00085       list.remove( list.fromLast() );
    00086   }
    00087   list.prepend( s );
    00088 }
    00089
    00090 void KateSearch::find()
    00091 {
    00092   // if multiline selection around, search in it
    00093   long searchf = KateViewConfig::global()->searchFlags();
    00094   if (m_doc->hasSelection() && m_doc->selStartLine() != m_doc->selEndLine())
    00095     searchf |= KFindDialog::SelectedText;
    00096
    00097   KFindDialog *findDialog = new KFindDialog (  m_view, "", searchf,
    00098                                                s_searchList, m_doc->hasSelection() );
    00099
    00100   findDialog->setPattern (getSearchText());
    00101
    00102
    00103   if( findDialog->exec() == QDialog::Accepted ) {
    00104     s_searchList =  findDialog->findHistory () ;
    00105     // Do *not* remove the QString() wrapping, it fixes a nasty crash
    00106     find( QString(s_searchList.first()), findDialog->options(), true, true );
    00107   }
    00108
    00109   delete findDialog;
    00110   m_view->repaintText ();
    00111 }
    00112
    00113 void KateSearch::find( const QString &pattern, long flags, bool add, bool shownotfound )
    00114 {
    00115   KateViewConfig::global()->setSearchFlags( flags );
    00116   if( add )
    00117     addToList( s_searchList, pattern );
    00118
    00119    s_pattern = pattern;
    00120
    00121   SearchFlags searchFlags;
    00122
    00123   searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
    00124   searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
    00125   searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
    00126       && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
    00127   searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
    00128   searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
    00129   searchFlags.prompt = false;
    00130   searchFlags.replace = false;
    00131   searchFlags.finished = false;
    00132   searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
    00133
    00134   if ( searchFlags.selected )
    00135   {
    00136     s.selBegin = KateTextCursor( doc()->selStartLine(), doc()->selStartCol() );
    00137     s.selEnd   = KateTextCursor( doc()->selEndLine(),   doc()->selEndCol()   );
    00138     s.cursor   = s.flags.backward ? s.selEnd : s.selBegin;
    00139   } else {
    00140     s.cursor = getCursor();
    00141   }
    00142
    00143   s.wrappedEnd = s.cursor;
    00144   s.wrapped = false;
    00145   s.showNotFound = shownotfound;
    00146
    00147   search( searchFlags );
    00148 }
    00149
    00150 void KateSearch::replace()
    00151 {
    00152   if (!doc()->isReadWrite()) return;
    00153
    00154   // if multiline selection around, search in it
    00155   long searchf = KateViewConfig::global()->searchFlags();
    00156   if (m_doc->hasSelection() && m_doc->selStartLine() != m_doc->selEndLine())
    00157     searchf |= KFindDialog::SelectedText;
    00158
    00159   KReplaceDialog *replaceDialog = new KReplaceDialog (  m_view, "", searchf,
    00160                                                s_searchList, s_replaceList, m_doc->hasSelection() );
    00161
    00162   replaceDialog->setPattern (getSearchText());
    00163
    00164   if( replaceDialog->exec() == QDialog::Accepted ) {
    00165     long opts = replaceDialog->options();
    00166     m_replacement = replaceDialog->replacement();
    00167     s_searchList = replaceDialog->findHistory () ;
    00168     s_replaceList = replaceDialog->replacementHistory () ;
    00169
    00170     // Do *not* remove the QString() wrapping, it fixes a nasty crash
    00171     replace( QString(s_searchList.first()), m_replacement, opts );
    00172   }
    00173
    00174   delete replaceDialog;
    00175   m_view->update ();
    00176 }
    00177
    00178 void KateSearch::replace( const QString& pattern, const QString &replacement, long flags )
    00179 {
    00180   if (!doc()->isReadWrite()) return;
    00181
    00182   addToList( s_searchList, pattern );
    00183    s_pattern = pattern;
    00184   addToList( s_replaceList, replacement );
    00185   m_replacement = replacement;
    00186   KateViewConfig::global()->setSearchFlags( flags );
    00187
    00188   SearchFlags searchFlags;
    00189   searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
    00190   searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
    00191   searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
    00192       && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
    00193   searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
    00194   searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
    00195   searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
    00196   searchFlags.replace = true;
    00197   searchFlags.finished = false;
    00198   searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
    00199   searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
    00200   if ( searchFlags.selected )
    00201   {
    00202     s.selBegin = KateTextCursor( doc()->selStartLine(), doc()->selStartCol() );
    00203     s.selEnd   = KateTextCursor( doc()->selEndLine(),   doc()->selEndCol()   );
    00204     s.cursor   = s.flags.backward ? s.selEnd : s.selBegin;
    00205   } else {
    00206     s.cursor = getCursor();
    00207   }
    00208
    00209   s.wrappedEnd = s.cursor;
    00210   s.wrapped = false;
    00211
    00212   search( searchFlags );
    00213 }
    00214
    00215 void KateSearch::findAgain( bool back )
    00216 {
    00217   SearchFlags searchFlags;
    00218   searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
    00219   searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
    00220   searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
    00221                                && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
    00222   searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
    00223   searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
    00224   searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
    00225   searchFlags.replace = false;
    00226   searchFlags.finished = false;
    00227   searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
    00228
    00229   searchFlags.backward = searchFlags.backward != back;
    00230   searchFlags.fromBeginning = false;
    00231   searchFlags.prompt = true; // ### why is the above assignment there?
    00232   s.cursor = getCursor();
    00233
    00234   search( searchFlags );
    00235 }
    00236
    00237 void KateSearch::search( SearchFlags flags )
    00238 {
    00239   s.flags = flags;
    00240
    00241   if( s.flags.fromBeginning ) {
    00242     if( !s.flags.backward ) {
    00243       s.cursor.setPos(0, 0);
    00244     } else {
    00245       s.cursor.setLine(doc()->numLines() - 1);
    00246       s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
    00247     }
    00248   }
    00249
    00250   if((!s.flags.backward &&
    00251        s.cursor.col() == 0 &&
    00252        s.cursor.line() == 0 ) ||
    00253      ( s.flags.backward &&
    00254        s.cursor.col() == doc()->lineLength( s.cursor.line() ) &&
    00255        s.cursor.line() == (((int)doc()->numLines()) - 1) ) ) {
    00256     s.flags.finished = true;
    00257   }
    00258
    00259   if( s.flags.replace ) {
    00260     replaces = 0;
    00261     if( s.flags.prompt )
    00262       promptReplace();
    00263     else
    00264       replaceAll();
    00265   } else {
    00266     findAgain();
    00267   }
    00268 }
    00269
    00270 void KateSearch::wrapSearch()
    00271 {
    00272   if( s.flags.selected )
    00273   {
    00274       s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
    00275   }
    00276   else
    00277   {
    00278     if( !s.flags.backward ) {
    00279       s.cursor.setPos(0, 0);
    00280     } else {
    00281       s.cursor.setLine(doc()->numLines() - 1);
    00282       s.cursor.setCol(doc()->lineLength( s.cursor.line() ) );
    00283     }
    00284   }
    00285
    00286   // oh, we wrapped around one time allready now !
    00287   // only check that on replace
    00288   s.wrapped = s.flags.replace;
    00289
    00290   replaces = 0;
    00291   s.flags.finished = true;
    00292 }
    00293
    00294 void KateSearch::findAgain()
    00295 {
    00296   if(  s_pattern.isEmpty() ) {
    00297     find();
    00298     return;
    00299   }
    00300
    00301   if ( doSearch(  s_pattern ) ) {
    00302     exposeFound( s.cursor, s.matchedLength );
    00303   } else if( !s.flags.finished ) {
    00304     if( askContinue() ) {
    00305       wrapSearch();
    00306       findAgain();
    00307     } else {
    00308       if (arbitraryHLExample) m_arbitraryHLList->clear();
    00309     }
    00310   } else {
    00311     if (arbitraryHLExample) m_arbitraryHLList->clear();
    00312     if ( s.showNotFound )
    00313       KMessageBox::sorry( view(),
    00314         i18n("Search string '%1' not found!")
    00315              .arg( KStringHandler::csqueeze(  s_pattern ) ),
    00316         i18n("Find"));
    00317   }
    00318 }
    00319
    00320 void KateSearch::replaceAll()
    00321 {
    00322   doc()->editStart ();
    00323
    00324   while( doSearch(  s_pattern ) )
    00325     replaceOne();
    00326
    00327   doc()->editEnd ();
    00328
    00329   if( !s.flags.finished ) {
    00330     if( askContinue() ) {
    00331       wrapSearch();
    00332       replaceAll();
    00333     }
    00334   } else {
    00335     KMessageBox::information( view(),
    00336         i18n("%n replacement made.","%n replacements made.",replaces),
    00337         i18n("Replace") );
    00338   }
    00339 }
    00340
    00341 void KateSearch::promptReplace()
    00342 {
    00343   if ( doSearch(  s_pattern ) ) {
    00344     exposeFound( s.cursor, s.matchedLength );
    00345     replacePrompt->show();
    00346     replacePrompt->setFocus ();
    00347   } else if( !s.flags.finished && askContinue() ) {
    00348     wrapSearch();
    00349     promptReplace();
    00350   } else {
    00351     if (arbitraryHLExample) m_arbitraryHLList->clear();
    00352     replacePrompt->hide();
    00353     KMessageBox::information( view(),
    00354         i18n("%n replacement made.","%n replacements made.",replaces),
    00355         i18n("Replace") );
    00356   }
    00357 }
    00358
    00359 void KateSearch::replaceOne()
    00360 {
    00361   QString replaceWith = m_replacement;
    00362   if ( s.flags.regExp && s.flags.useBackRefs ) {
    00363     // replace each "(?!\)\d+" with the corresponding capture
    00364     QRegExp br("\\\\(\\d+)");
    00365     int pos = br.search( replaceWith );
    00366     int ncaps = m_re.numCaptures();
    00367     while ( pos >= 0 ) {
    00368       QString sc;
    00369       if ( !pos ||  replaceWith.at( pos-1) != '\\' ) {
    00370         int ccap = br.cap(1).toInt();
    00371         if (ccap <= ncaps ) {
    00372           sc = m_re.cap( ccap );
    00373           replaceWith.replace( pos, br.matchedLength(), sc );
    00374         }
    00375         else {
    00376           kdDebug()<<"KateSearch::replaceOne(): you don't have "<<ccap<<" backreferences in regexp '"<<m_re.pattern()<<"'"<<endl;
    00377         }
    00378       }
    00379       pos = br.search( replaceWith, pos+QMAX(br.matchedLength(), (int)sc.length()) );
    00380     }
    00381   }
    00382
    00383   doc()->editStart();
    00384   doc()->removeText( s.cursor.line(), s.cursor.col(),
    00385       s.cursor.line(), s.cursor.col() + s.matchedLength );
    00386   doc()->insertText( s.cursor.line(), s.cursor.col(), replaceWith );
    00387   doc()->editEnd(),
    00388
    00389   replaces++;
    00390
    00391   // if we inserted newlines, we better adjust.
    00392   uint newlines = replaceWith.contains('\n');
    00393   if ( newlines )
    00394   {
    00395     if ( ! s.flags.backward )
    00396     {
    00397       s.cursor.setLine( s.cursor.line() + newlines );
    00398       s.cursor.setCol( replaceWith.length() - replaceWith.findRev('\n') );
    00399     }
    00400     // selection?
    00401     if ( s.flags.selected )
    00402       s.selEnd.setLine( s.selEnd.line() + newlines );
    00403   }
    00404
    00405
    00406   // adjust selection endcursor if needed
    00407   if( s.flags.selected && s.cursor.line() == s.selEnd.line() )
    00408   {
    00409     s.selEnd.setCol(s.selEnd.col() + replaceWith.length() - s.matchedLength );
    00410   }
    00411
    00412   // adjust wrap cursor if needed
    00413   if( s.cursor.line() == s.wrappedEnd.line() && s.cursor.col() <= s.wrappedEnd.col())
    00414   {
    00415     s.wrappedEnd.setCol(s.wrappedEnd.col() + replaceWith.length() - s.matchedLength );
    00416   }
    00417
    00418   if( !s.flags.backward ) {
    00419     s.cursor.setCol(s.cursor.col() + replaceWith.length());
    00420   } else if( s.cursor.col() > 0 ) {
    00421     s.cursor.setCol(s.cursor.col() - 1);
    00422   } else {
    00423     s.cursor.setLine(s.cursor.line() - 1);
    00424     if( s.cursor.line() >= 0 ) {
    00425       s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
    00426     }
    00427   }
    00428 }
    00429
    00430 void KateSearch::skipOne()
    00431 {
    00432   if( !s.flags.backward ) {
    00433     s.cursor.setCol(s.cursor.col() + s.matchedLength);
    00434   } else if( s.cursor.col() > 0 ) {
    00435     s.cursor.setCol(s.cursor.col() - 1);
    00436   } else {
    00437     s.cursor.setLine(s.cursor.line() - 1);
    00438     if( s.cursor.line() >= 0 ) {
    00439       s.cursor.setCol(doc()->lineLength(s.cursor.line()));
    00440     }
    00441   }
    00442 }
    00443
    00444 void KateSearch::replaceSlot() {
    00445   switch( (Dialog_results)replacePrompt->result() ) {
    00446   case srCancel: replacePrompt->hide();                break;
    00447   case srAll:    replacePrompt->hide(); replaceAll();  break;
    00448   case srYes:    replaceOne(); promptReplace();        break;
    00449   case srLast:   replacePrompt->hide(), replaceOne();  break;
    00450   case srNo:     skipOne();    promptReplace();        break;
    00451   }
    00452 }
    00453
    00454 bool KateSearch::askContinue()
    00455 {
    00456   QString made =
    00457      i18n( "%n replacement made.",
    00458            "%n replacements made.",
    00459            replaces );
    00460
    00461   QString reached = !s.flags.backward ?
    00462      i18n( "End of document reached." ) :
    00463      i18n( "Beginning of document reached." );
    00464
    00465   if (KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText)
    00466   {
    00467     reached = !s.flags.backward ?
    00468      i18n( "End of selection reached." ) :
    00469      i18n( "Beginning of selection reached." );
    00470   }
    00471
    00472   QString question = !s.flags.backward ?
    00473      i18n( "Continue from the beginning?" ) :
    00474      i18n( "Continue from the end?" );
    00475
    00476   QString text = s.flags.replace ?
    00477      made + "\n" + reached + "\n" + question :
    00478      reached + "\n" + question;
    00479
    00480   return KMessageBox::Yes == KMessageBox::questionYesNo(
    00481      view(), text, s.flags.replace ? i18n("Replace") : i18n("Find"),
    00482      KStdGuiItem::cont(), i18n("&Stop") );
    00483 }
    00484
    00485 QString KateSearch::getSearchText()
    00486 {
    00487   // SelectionOnly: use selection
    00488   // WordOnly: use word under cursor
    00489   // SelectionWord: use selection if available, else use word under cursor
    00490   // WordSelection: use word if available, else use selection
    00491   QString str;
    00492
    00493   int getFrom = view()->config()->textToSearchMode();
    00494   switch (getFrom)
    00495   {
    00496   case KateViewConfig::SelectionOnly: // (Windows)
    00497     //kdDebug() << "getSearchText(): SelectionOnly" << endl;
    00498     if( doc()->hasSelection() )
    00499       str = doc()->selection();
    00500     break;
    00501
    00502   case KateViewConfig::SelectionWord: // (classic Kate behavior)
    00503     //kdDebug() << "getSearchText(): SelectionWord" << endl;
    00504     if( doc()->hasSelection() )
    00505       str = doc()->selection();
    00506     else
    00507       str = view()->currentWord();
    00508     break;
    00509
    00510   case KateViewConfig::WordOnly: // (weird?)
    00511     //kdDebug() << "getSearchText(): WordOnly" << endl;
    00512     str = view()->currentWord();
    00513     break;
    00514
    00515   case KateViewConfig::WordSelection: // (persistent selection lover)
    00516     //kdDebug() << "getSearchText(): WordSelection" << endl;
    00517     str = view()->currentWord();
    00518     if (str.isEmpty() && doc()->hasSelection() )
    00519       str = doc()->selection();
    00520     break;
    00521
    00522   default: // (nowhere)
    00523     //kdDebug() << "getSearchText(): Nowhere" << endl;
    00524     break;
    00525   }
    00526
    00527   str.replace( QRegExp("^\\n"), "" );
    00528   str.replace( QRegExp("\\n.*"), "" );
    00529
    00530   return str;
    00531 }
    00532
    00533 KateTextCursor KateSearch::getCursor()
    00534 {
    00535   return KateTextCursor(view()->cursorLine(), view()->cursorColumnReal());
    00536 }
    00537
    00538 bool KateSearch::doSearch( const QString& text )
    00539 {
    00540 /*
    00541   rodda: Still Working on this... :)
    00542
    00543   bool result = false;
    00544
    00545   if (m_searchResults.count()) {
    00546     m_resultIndex++;
    00547     if (m_resultIndex < (int)m_searchResults.count()) {
    00548       s = m_searchResults[m_resultIndex];
    00549       result = true;
    00550     }
    00551
    00552   } else {
    00553     int temp = 0;
    00554     do {*/
    00555
    00556 #if 0
    00557   static int oldLine = -1;
    00558   static int oldCol = -1;
    00559 #endif
    00560
    00561   uint line = s.cursor.line();
    00562   uint col = s.cursor.col();// + (result ? s.matchedLength : 0);
    00563   bool backward = s.flags.backward;
    00564   bool caseSensitive = s.flags.caseSensitive;
    00565   bool regExp = s.flags.regExp;
    00566   bool wholeWords = s.flags.wholeWords;
    00567   uint foundLine, foundCol, matchLen;
    00568   bool found = false;
    00569   //kdDebug() << "Searching at " << line << ", " << col << endl;
    00570 //   kdDebug()<<"KateSearch::doSearch: "<<line<<", "<<col<<", "<<backward<<endl;
    00571
    00572   do {
    00573       if( regExp ) {
    00574         m_re = QRegExp( text, caseSensitive );
    00575         found = doc()->searchText( line, col, m_re,
    00576                                   &foundLine, &foundCol,
    00577                                   &matchLen, backward );
    00578       } else if ( wholeWords ) {
    00579         QRegExp re( "\\b" + text + "\\b", caseSensitive );
    00580         found = doc()->searchText( line, col, re,
    00581                                   &foundLine, &foundCol,
    00582                                   &matchLen, backward );
    00583       } else {
    00584         found = doc()->searchText( line, col, text,
    00585                                   &foundLine, &foundCol,
    00586                                   &matchLen, caseSensitive, backward );
    00587       }
    00588
    00589     if ( found && s.flags.selected )
    00590     {
    00591       if ( !s.flags.backward && KateTextCursor( foundLine, foundCol ) >= s.selEnd
    00592         ||  s.flags.backward && KateTextCursor( foundLine, foundCol ) < s.selBegin )
    00593         found = false;
    00594       else if (m_doc->blockSelectionMode())
    00595       {
    00596         if ((int)foundCol < s.selEnd.col() && (int)foundCol >= s.selBegin.col())
    00597           break;
    00598       }
    00599     }
    00600
    00601     line = foundLine;
    00602     col = foundCol+1;
    00603   }
    00604   while (m_doc->blockSelectionMode() && found);
    00605
    00606   if( !found ) return false;
    00607
    00608   // save the search result
    00609   s.cursor.setPos(foundLine, foundCol);
    00610   s.matchedLength = matchLen;
    00611
    00612   // we allready wrapped around one time
    00613   if (s.wrapped)
    00614   {
    00615     if (s.flags.backward)
    00616     {
    00617       if ( (s.cursor.line() < s.wrappedEnd.line())
    00618            || ( (s.cursor.line() == s.wrappedEnd.line()) && ((s.cursor.col()+matchLen) <= uint(s.wrappedEnd.col())) ) )
    00619         return false;
    00620     }
    00621     else
    00622     {
    00623       if ( (s.cursor.line() > s.wrappedEnd.line())
    00624            || ( (s.cursor.line() == s.wrappedEnd.line()) && (s.cursor.col() > s.wrappedEnd.col()) ) )
    00625         return false;
    00626     }
    00627   }
    00628
    00629 //   kdDebug() << "Found at " << s.cursor.line() << ", " << s.cursor.col() << endl;
    00630
    00631
    00632   //m_searchResults.append(s);
    00633
    00634   if (arbitraryHLExample)  {
    00635     KateArbitraryHighlightRange* hl = new KateArbitraryHighlightRange(new KateSuperCursor(m_doc, true, s.cursor), new KateSuperCursor(m_doc, true, s.cursor.line(), s.cursor.col() + s.matchedLength), this);
    00636     hl->setBold();
    00637     hl->setTextColor(Qt::white);
    00638     hl->setBGColor(Qt::black);
    00639     // destroy the highlight upon change
    00640     connect(hl, SIGNAL(contentsChanged()), hl, SIGNAL(eliminated()));
    00641     m_arbitraryHLList->append(hl);
    00642   }
    00643
    00644   return true;
    00645
    00646     /* rodda: more of my search highlighting work
    00647
    00648     } while (++temp < 100);
    00649
    00650     if (result) {
    00651       s = m_searchResults.first();
    00652       m_resultIndex = 0;
    00653     }
    00654   }
    00655
    00656   return result;*/
    00657 }
    00658
    00659 void KateSearch::exposeFound( KateTextCursor &cursor, int slen )
    00660 {
    00661   view()->setCursorPositionInternal ( cursor.line(), cursor.col() + slen, 1 );
    00662   doc()->setSelection( cursor.line(), cursor.col(), cursor.line(), cursor.col() + slen );
    00663 }
    00664 //END KateSearch
    00665
    00666 //BEGIN KateReplacePrompt
    00667 // this dialog is not modal
    00668 KateReplacePrompt::KateReplacePrompt ( QWidget *parent )
    00669   : KDialogBase ( parent, 0L, false, i18n( "Replace Confirmation" ),
    00670                   User3 | User2 | User1 | Close | Ok , Ok, true,
    00671                   i18n("Replace &All"), i18n("Re&place && Close"), i18n("&Replace") )
    00672 {
    00673   setButtonOK( i18n("&Find Next") );
    00674   QWidget *page = new QWidget(this);
    00675   setMainWidget(page);
    00676
    00677   QBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
    00678   QLabel *label = new QLabel(i18n("Found an occurrence of your search term. What do you want to do?"),page);
    00679   topLayout->addWidget(label );
    00680 }
    00681
    00682 void KateReplacePrompt::slotOk ()
    00683 { // Search Next
    00684   done(KateSearch::srNo);
    00685 }
    00686
    00687 void KateReplacePrompt::slotClose ()
    00688 { // Close
    00689   done(KateSearch::srCancel);
    00690 }
    00691
    00692 void KateReplacePrompt::slotUser1 ()
    00693 { // Replace All
    00694   done(KateSearch::srAll);
    00695 }
    00696
    00697 void KateReplacePrompt::slotUser2 ()
    00698 { // Replace & Close
    00699   done(KateSearch::srLast);
    00700 }
    00701
    00702 void KateReplacePrompt::slotUser3 ()
    00703 { // Replace
    00704   done(KateSearch::srYes);
    00705 }
    00706
    00707 void KateReplacePrompt::done (int result)
    00708 {
    00709   setResult(result);
    00710
    00711   emit clicked();
    00712 }
    00713 //END KateReplacePrompt
    00714
    00715 //BEGIN SearchCommand
    00716 bool SearchCommand::exec(class Kate::View *view, const QString &cmd, QString &msg)
    00717 {
    00718   QString flags, pattern, replacement;
    00719   if ( cmd.startsWith( "find" ) )
    00720   {
    00721
    00722     static QRegExp re_find("find(?::([bcersw]*))?\\s+(.+)");
    00723     if ( re_find.search( cmd ) < 0 )
    00724     {
    00725       msg = i18n("Usage: find[:[bcersw]] PATTERN");
    00726       return false;
    00727     }
    00728     flags = re_find.cap( 1 );
    00729     pattern = re_find.cap( 2 );
    00730   }
    00731
    00732   else if ( cmd.startsWith( "ifind" ) )
    00733   {
    00734     static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s+(.*)");
    00735     if ( re_ifind.search( cmd ) < 0 )
    00736     {
    00737       msg = i18n("Usage: ifind[:[bcrs]] PATTERN");
    00738       return false;
    00739     }
    00740     ifindClear();
    00741     return true;
    00742   }
    00743
    00744   else if ( cmd.startsWith( "replace" ) )
    00745   {
    00746     // Try if the pattern and replacement is quoted, using a quote character ["']
    00747     static QRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
    00748     // Or one quoted argument
    00749     QRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
    00750     // Else, it's just one or two (space separated) words
    00751     QRegExp re_rep2("replace(?::([bceprsw]*))?\\s+(\\S+)(.*)");
    00752 #define unbackslash(s) p=0;\
    00753 while ( (p = pattern.find( '\\' + delim, p )) > -1 )\
    00754 {\
    00755   if ( !p || pattern[p-1] != '\\' )\
    00756     pattern.remove( p, 1 );\
    00757   p++;\
    00758 }
    00759
    00760     if ( re_rep.search( cmd ) >= 0 )
    00761     {
    00762       flags = re_rep.cap(1);
    00763       pattern = re_rep.cap( 3 );
    00764       replacement = re_rep.cap( 4 );
    00765
    00766       int p(0);
    00767       // unbackslash backslashed delimiter strings
    00768       // in pattern ..
    00769       QString delim = re_rep.cap( 2 );
    00770       unbackslash(pattern);
    00771       // .. and in replacement
    00772       unbackslash(replacement);
    00773     }
    00774     else if ( re_rep1.search( cmd ) >= 0 )
    00775     {
    00776       flags = re_rep1.cap(1);
    00777       pattern = re_rep1.cap( 3 );
    00778
    00779       int p(0);
    00780       QString delim = re_rep1.cap( 2 );
    00781       unbackslash(pattern);
    00782     }
    00783     else if ( re_rep2.search( cmd ) >= 0 )
    00784     {
    00785       flags = re_rep2.cap( 1 );
    00786       pattern = re_rep2.cap( 2 );
    00787       replacement = re_rep2.cap( 3 ).stripWhiteSpace();
    00788     }
    00789     else
    00790     {
    00791       msg = i18n("Usage: replace[:[bceprsw]] PATTERN [REPLACEMENT]");
    00792       return false;
    00793     }
    00794     kdDebug()<<"replace '"<<pattern<<"' with '"<<replacement<<"'"<<endl;
    00795 #undef unbackslash
    00796   }
    00797
    00798   long f = 0;
    00799   if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
    00800   if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
    00801   if ( flags.contains( 'e' ) ) f |= KFindDialog::SelectedText;
    00802   if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
    00803   if ( flags.contains( 'p' ) ) f |= KReplaceDialog::PromptOnReplace;
    00804   if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
    00805   if ( flags.contains( 'w' ) ) f |= KFindDialog::WholeWordsOnly;
    00806
    00807   if ( cmd.startsWith( "find" ) )
    00808   {
    00809     ((KateView*)view)->find( pattern, f );
    00810     return true;
    00811   }
    00812   else if ( cmd.startsWith( "replace" ) )
    00813   {
    00814     f |= KReplaceDialog::BackReference; // mandatory here?
    00815     ((KateView*)view)->replace( pattern, replacement, f );
    00816     return true;
    00817   }
    00818
    00819   return false;
    00820 }
    00821
    00822 bool SearchCommand::help(class Kate::View *, const QString &cmd, QString &msg)
    00823 {
    00824   if ( cmd == "find" )
    00825     msg = i18n("<p>Usage: <code>find[:bcersw] PATTERN</code></p>");
    00826
    00827   else if ( cmd == "ifind" )
    00828     msg = i18n("<p>Usage: <code>ifind:[:bcrs] PATTERN</code>"
    00829         "<br>ifind does incremental or 'as-you-type' search</p>");
    00830
    00831   else
    00832     msg = i18n("<p>Usage: <code>replace[:bceprsw] PATTERN REPLACEMENT</code></p>");
    00833
    00834   msg += i18n(
    00835       "<h4><caption>Options</h4><p>"
    00836       "<b>b</b> - Search backward"
    00837       "<br><b>c</b> - Search from cursor"
    00838       "<br><b>r</b> - Pattern is a regular expression"
    00839       "<br><b>s</b> - Case sensitive search"
    00840              );
    00841
    00842   if ( cmd == "find" )
    00843     msg += i18n(
    00844         "<br><b>e</b> - Search in selected text only"
    00845         "<br><b>w</b> - Search whole words only"
    00846                );
    00847
    00848   if ( cmd == "replace" )
    00849     msg += i18n(
    00850         "<br><b>p</b> - Prompt for replace</p>"
    00851         "<p>If REPLACEMENT is not present, an empty string is used.</p>"
    00852         "<p>If you want to have whitespace in your PATTERN, you need to "
    00853         "quote both PATTERN and REPLACEMENT with either single or double "
    00854         "quotes. To have the quote characters in the strings, prepend them "
    00855         "with a backslash.");
    00856
    00857   msg += "</p>";
    00858   return true;
    00859 }
    00860
    00861 QStringList SearchCommand::cmds()
    00862 {
    00863   QStringList l;
    00864   l << "find" << "replace" << "ifind";
    00865   return l;
    00866 }
    00867
    00868 bool SearchCommand::wantsToProcessText( const QString &cmdname )
    00869 {
    00870   return  cmdname == "ifind";
    00871 }
    00872
    00873 void SearchCommand::processText( Kate::View *view, const QString &cmd )
    00874 {
    00875   static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)");
    00876   if ( re_ifind.search( cmd ) > -1 )
    00877   {
    00878     QString flags = re_ifind.cap( 1 );
    00879     QString pattern = re_ifind.cap( 2 );
    00880
    00881
    00882     // if there is no setup, or the text length is 0, set up the properties
    00883     if ( ! m_ifindFlags || pattern.isEmpty() )
    00884       ifindInit( flags );
    00885     // if there is no fromCursor, add it if this is not the first character
    00886     else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
    00887       m_ifindFlags |= KFindDialog::FromCursor;
    00888
    00889     // search..
    00890     if ( ! pattern.isEmpty() )
    00891     {
    00892       KateView *v = (KateView*)view;
    00893
    00894       // If it *looks like* we are continuing, place the cursor
    00895       // at the beginning of the selection, so that the search continues.
    00896       // ### check more carefully, like is  the cursor currently at the end
    00897       // of the selection.
    00898       if ( pattern.startsWith( v->getDoc()->selection() ) &&
    00899            v->getDoc()->selection().length() + 1 == pattern.length() )
    00900         v->setCursorPositionInternal( v->getDoc()->selStartLine(), v->getDoc()->selStartCol() );
    00901
    00902       v->find( pattern, m_ifindFlags, false );
    00903     }
    00904   }
    00905 }
    00906
    00907 void SearchCommand::ifindInit( const QString &flags )
    00908 {
    00909   long f = 0;
    00910   if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
    00911   if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
    00912   if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
    00913   if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
    00914   m_ifindFlags = f;
    00915 }
    00916
    00917 void SearchCommand::ifindClear()
    00918 {
    00919   m_ifindFlags = 0;
    00920 }
    00921 //END SearchCommand
    00922
    00923 // kate: space-indent on; indent-width 2; replace-tabs on;

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:38 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003