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