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+kMax(br.matchedLength(), (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
00639 {
00640 line = foundLine;
00641 col = foundCol + 1;
00642 }
00643 }
00644 } while ( maybefound );
00645 }
00646 else {
00647 found = doc()->searchText( line, col, text,
00648 &foundLine, &foundCol,
00649 &matchLen, caseSensitive, backward );
00650 }
00651
00652 if ( found && s.flags.selected )
00653 {
00654 KateTextCursor start (s.selBegin);
00655 KateTextCursor end (s.selEnd);
00656
00657
00658 if (m_view->blockSelectionMode())
00659 {
00660 start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
00661 end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
00662 }
00663
00664 if ( !s.flags.backward && KateTextCursor( foundLine, foundCol ) >= end
00665 || s.flags.backward && KateTextCursor( foundLine, foundCol ) < start )
00666 {
00667 found = false;
00668 }
00669 else if (m_view->blockSelectionMode())
00670 {
00671 if ((int)foundCol >= start.col() && (int)foundCol < end.col())
00672 break;
00673 }
00674 }
00675
00676 line = foundLine;
00677 col = foundCol+1;
00678 }
00679 while (s.flags.selected && m_view->blockSelectionMode() && found);
00680
00681
00682 if( !found ) return false;
00683
00684
00685 s.cursor.setPos(foundLine, foundCol);
00686 s.matchedLength = matchLen;
00687
00688
00689 if (s.wrapped)
00690 {
00691 if (s.flags.backward)
00692 {
00693 if ( (s.cursor.line() < s.wrappedEnd.line())
00694 || ( (s.cursor.line() == s.wrappedEnd.line()) && ((s.cursor.col()+matchLen) <= uint(s.wrappedEnd.col())) ) )
00695 return false;
00696 }
00697 else
00698 {
00699 if ( (s.cursor.line() > s.wrappedEnd.line())
00700 || ( (s.cursor.line() == s.wrappedEnd.line()) && (s.cursor.col() > s.wrappedEnd.col()) ) )
00701 return false;
00702 }
00703 }
00704
00705
00706
00707
00708
00709
00710 if (arbitraryHLExample) {
00711 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);
00712 hl->setBold();
00713 hl->setTextColor(Qt::white);
00714 hl->setBGColor(Qt::black);
00715
00716 connect(hl, SIGNAL(contentsChanged()), hl, SIGNAL(eliminated()));
00717 m_arbitraryHLList->append(hl);
00718 }
00719
00720 return true;
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 }
00734
00735 void KateSearch::exposeFound( KateTextCursor &cursor, int slen )
00736 {
00737 view()->setCursorPositionInternal ( cursor.line(), cursor.col() + slen, 1 );
00738 view()->setSelection( cursor.line(), cursor.col(), cursor.line(), cursor.col() + slen );
00739 view()->syncSelectionCache();
00740 }
00741
00742
00743
00744
00745 KateReplacePrompt::KateReplacePrompt ( QWidget *parent )
00746 : KDialogBase ( parent, 0L, false, i18n( "Replace Confirmation" ),
00747 User3 | User2 | User1 | Close | Ok , Ok, true,
00748 i18n("Replace &All"), i18n("Re&place && Close"), i18n("&Replace") )
00749 {
00750 setButtonOK( i18n("&Find Next") );
00751 QWidget *page = new QWidget(this);
00752 setMainWidget(page);
00753
00754 QBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
00755 QLabel *label = new QLabel(i18n("Found an occurrence of your search term. What do you want to do?"),page);
00756 topLayout->addWidget(label );
00757 }
00758
00759 void KateReplacePrompt::slotOk ()
00760 {
00761 done(KateSearch::srNo);
00762 actionButton(Ok)->setFocus();
00763 }
00764
00765 void KateReplacePrompt::slotClose ()
00766 {
00767 done(KateSearch::srCancel);
00768 actionButton(Close)->setFocus();
00769 }
00770
00771 void KateReplacePrompt::slotUser1 ()
00772 {
00773 done(KateSearch::srAll);
00774 actionButton(User1)->setFocus();
00775 }
00776
00777 void KateReplacePrompt::slotUser2 ()
00778 {
00779 done(KateSearch::srLast);
00780 actionButton(User2)->setFocus();
00781 }
00782
00783 void KateReplacePrompt::slotUser3 ()
00784 {
00785 done(KateSearch::srYes);
00786 actionButton(User3)->setFocus();
00787 }
00788
00789 void KateReplacePrompt::done (int result)
00790 {
00791 setResult(result);
00792
00793 emit clicked();
00794 }
00795
00796
00797
00798 bool SearchCommand::exec(class Kate::View *view, const QString &cmd, QString &msg)
00799 {
00800 QString flags, pattern, replacement;
00801 if ( cmd.startsWith( "find" ) )
00802 {
00803
00804 static QRegExp re_find("find(?::([bcersw]*))?\\s+(.+)");
00805 if ( re_find.search( cmd ) < 0 )
00806 {
00807 msg = i18n("Usage: find[:[bcersw]] PATTERN");
00808 return false;
00809 }
00810 flags = re_find.cap( 1 );
00811 pattern = re_find.cap( 2 );
00812 }
00813
00814 else if ( cmd.startsWith( "ifind" ) )
00815 {
00816 static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s+(.*)");
00817 if ( re_ifind.search( cmd ) < 0 )
00818 {
00819 msg = i18n("Usage: ifind[:[bcrs]] PATTERN");
00820 return false;
00821 }
00822 ifindClear();
00823 return true;
00824 }
00825
00826 else if ( cmd.startsWith( "replace" ) )
00827 {
00828
00829 static QRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00830
00831 QRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00832
00833 QRegExp re_rep2("replace(?::([bceprsw]*))?\\s+(\\S+)(.*)");
00834 #define unbackslash(s) p=0;\
00835 while ( (p = pattern.find( '\\' + delim, p )) > -1 )\
00836 {\
00837 if ( !p || pattern[p-1] != '\\' )\
00838 pattern.remove( p, 1 );\
00839 p++;\
00840 }
00841
00842 if ( re_rep.search( cmd ) >= 0 )
00843 {
00844 flags = re_rep.cap(1);
00845 pattern = re_rep.cap( 3 );
00846 replacement = re_rep.cap( 4 );
00847
00848 int p(0);
00849
00850
00851 QString delim = re_rep.cap( 2 );
00852 unbackslash(pattern);
00853
00854 unbackslash(replacement);
00855 }
00856 else if ( re_rep1.search( cmd ) >= 0 )
00857 {
00858 flags = re_rep1.cap(1);
00859 pattern = re_rep1.cap( 3 );
00860
00861 int p(0);
00862 QString delim = re_rep1.cap( 2 );
00863 unbackslash(pattern);
00864 }
00865 else if ( re_rep2.search( cmd ) >= 0 )
00866 {
00867 flags = re_rep2.cap( 1 );
00868 pattern = re_rep2.cap( 2 );
00869 replacement = re_rep2.cap( 3 ).stripWhiteSpace();
00870 }
00871 else
00872 {
00873 msg = i18n("Usage: replace[:[bceprsw]] PATTERN [REPLACEMENT]");
00874 return false;
00875 }
00876 kdDebug()<<"replace '"<<pattern<<"' with '"<<replacement<<"'"<<endl;
00877 #undef unbackslash
00878 }
00879
00880 long f = 0;
00881 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
00882 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
00883 if ( flags.contains( 'e' ) ) f |= KFindDialog::SelectedText;
00884 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
00885 if ( flags.contains( 'p' ) ) f |= KReplaceDialog::PromptOnReplace;
00886 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
00887 if ( flags.contains( 'w' ) ) f |= KFindDialog::WholeWordsOnly;
00888
00889 if ( cmd.startsWith( "find" ) )
00890 {
00891 ((KateView*)view)->find( pattern, f );
00892 return true;
00893 }
00894 else if ( cmd.startsWith( "replace" ) )
00895 {
00896 f |= KReplaceDialog::BackReference;
00897 ((KateView*)view)->replace( pattern, replacement, f );
00898 return true;
00899 }
00900
00901 return false;
00902 }
00903
00904 bool SearchCommand::help(class Kate::View *, const QString &cmd, QString &msg)
00905 {
00906 if ( cmd == "find" )
00907 msg = i18n("<p>Usage: <code>find[:bcersw] PATTERN</code></p>");
00908
00909 else if ( cmd == "ifind" )
00910 msg = i18n("<p>Usage: <code>ifind:[:bcrs] PATTERN</code>"
00911 "<br>ifind does incremental or 'as-you-type' search</p>");
00912
00913 else
00914 msg = i18n("<p>Usage: <code>replace[:bceprsw] PATTERN REPLACEMENT</code></p>");
00915
00916 msg += i18n(
00917 "<h4><caption>Options</h4><p>"
00918 "<b>b</b> - Search backward"
00919 "<br><b>c</b> - Search from cursor"
00920 "<br><b>r</b> - Pattern is a regular expression"
00921 "<br><b>s</b> - Case sensitive search"
00922 );
00923
00924 if ( cmd == "find" )
00925 msg += i18n(
00926 "<br><b>e</b> - Search in selected text only"
00927 "<br><b>w</b> - Search whole words only"
00928 );
00929
00930 if ( cmd == "replace" )
00931 msg += i18n(
00932 "<br><b>p</b> - Prompt for replace</p>"
00933 "<p>If REPLACEMENT is not present, an empty string is used.</p>"
00934 "<p>If you want to have whitespace in your PATTERN, you need to "
00935 "quote both PATTERN and REPLACEMENT with either single or double "
00936 "quotes. To have the quote characters in the strings, prepend them "
00937 "with a backslash.");
00938
00939 msg += "</p>";
00940 return true;
00941 }
00942
00943 QStringList SearchCommand::cmds()
00944 {
00945 QStringList l;
00946 l << "find" << "replace" << "ifind";
00947 return l;
00948 }
00949
00950 bool SearchCommand::wantsToProcessText( const QString &cmdname )
00951 {
00952 return cmdname == "ifind";
00953 }
00954
00955 void SearchCommand::processText( Kate::View *view, const QString &cmd )
00956 {
00957 static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)");
00958 if ( re_ifind.search( cmd ) > -1 )
00959 {
00960 QString flags = re_ifind.cap( 1 );
00961 QString pattern = re_ifind.cap( 2 );
00962
00963
00964
00965 if ( ! m_ifindFlags || pattern.isEmpty() )
00966 ifindInit( flags );
00967
00968 else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
00969 m_ifindFlags |= KFindDialog::FromCursor;
00970
00971
00972 if ( ! pattern.isEmpty() )
00973 {
00974 KateView *v = (KateView*)view;
00975
00976
00977
00978
00979
00980 if ( pattern.startsWith( v->selection() ) &&
00981 v->selection().length() + 1 == pattern.length() )
00982 v->setCursorPositionInternal( v->selStartLine(), v->selStartCol() );
00983
00984 v->find( pattern, m_ifindFlags, false );
00985 }
00986 }
00987 }
00988
00989 void SearchCommand::ifindInit( const QString &flags )
00990 {
00991 long f = 0;
00992 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
00993 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
00994 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
00995 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
00996 m_ifindFlags = f;
00997 }
00998
00999 void SearchCommand::ifindClear()
01000 {
01001 m_ifindFlags = 0;
01002 }
01003
01004
01005