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 // 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;
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 Tue Apr 12 23:40:02 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003