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