kate Library API Documentation

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