• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Kate

katesearch.cpp

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

Kate

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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