00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
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
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
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;
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
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
00304
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
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
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
00418 if ( s.flags.selected )
00419 s.selEnd.setLine( s.selEnd.line() + newlines );
00420 }
00421
00422
00423
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
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
00505
00506
00507
00508 QString str;
00509
00510 int getFrom = view()->config()->textToSearchMode();
00511 switch (getFrom)
00512 {
00513 case KateViewConfig::SelectionOnly:
00514
00515 if( m_view->hasSelection() )
00516 str = m_view->selection();
00517 break;
00518
00519 case KateViewConfig::SelectionWord:
00520
00521 if( m_view->hasSelection() )
00522 str = m_view->selection();
00523 else
00524 str = view()->currentWord();
00525 break;
00526
00527 case KateViewConfig::WordOnly:
00528
00529 str = view()->currentWord();
00530 break;
00531
00532 case KateViewConfig::WordSelection:
00533
00534 str = view()->currentWord();
00535 if (str.isEmpty() && m_view->hasSelection() )
00536 str = m_view->selection();
00537 break;
00538
00539 default:
00540
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
00555
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
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
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();
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
00594
00595
00596 if (backward)
00597 {
00598 KateDocCursor docCursor(line, col, doc());
00599
00600
00601 if (docCursor.line() == 0 && docCursor.col() == 0)
00602 return false;
00603
00604
00605
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 )
00639 {
00640 if ( line == 0 )
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
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
00688
00689 if( !found ) return false;
00690
00691
00692 s.cursor.setPos(foundLine, foundCol);
00693 s.matchedLength = matchLen;
00694
00695
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
00713
00714
00715
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
00723 connect(hl, SIGNAL(contentsChanged()), hl, SIGNAL(eliminated()));
00724 m_arbitraryHLList->append(hl);
00725 }
00726
00727 return true;
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
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
00749
00750
00751
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 {
00768 done(KateSearch::srNo);
00769 actionButton(Ok)->setFocus();
00770 }
00771
00772 void KateReplacePrompt::slotClose ()
00773 {
00774 done(KateSearch::srCancel);
00775 actionButton(Close)->setFocus();
00776 }
00777
00778 void KateReplacePrompt::slotUser1 ()
00779 {
00780 done(KateSearch::srAll);
00781 actionButton(User1)->setFocus();
00782 }
00783
00784 void KateReplacePrompt::slotUser2 ()
00785 {
00786 done(KateSearch::srLast);
00787 actionButton(User2)->setFocus();
00788 }
00789
00790 void KateReplacePrompt::slotUser3 ()
00791 {
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
00803
00804
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
00836 static QRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00837
00838 QRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00839
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
00857
00858 QString delim = re_rep.cap( 2 );
00859 unbackslash(pattern);
00860
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;
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
00972 if ( ! m_ifindFlags || pattern.isEmpty() )
00973 ifindInit( flags );
00974
00975 else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
00976 m_ifindFlags |= KFindDialog::FromCursor;
00977
00978
00979 if ( ! pattern.isEmpty() )
00980 {
00981 KateView *v = (KateView*)view;
00982
00983
00984
00985
00986
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
01011
01012