• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
katesearch.cpp
1/* This file is part of the KDE libraries
2 Copyright (C) 2004-2005 Anders Lund <anders@alweb.dk>
3 Copyright (C) 2003 Clarence Dang <dang@kde.org>
4 Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
5 Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
6 Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
7 Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License version 2 as published by the Free Software Foundation.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24#include "katesearch.h"
25#include "katesearch.moc"
26
27#include "kateview.h"
28#include "katedocument.h"
29#include "katesupercursor.h"
30#include "katearbitraryhighlight.h"
31#include "kateconfig.h"
32#include "katehighlight.h"
33
34#include <tdelocale.h>
35#include <kstdaction.h>
36#include <tdemessagebox.h>
37#include <kstringhandler.h>
38#include <kdebug.h>
39#include <kfinddialog.h>
40#include <kreplacedialog.h>
41#include <kpushbutton.h>
42
43#include <tqlayout.h>
44#include <tqlabel.h>
45
46//BEGIN KateSearch
47TQStringList KateSearch::s_searchList = TQStringList();
48TQStringList KateSearch::s_replaceList = TQStringList();
49TQString KateSearch::s_pattern = TQString();
50static const bool arbitraryHLExample = false;
51
52KateSearch::KateSearch( KateView* view )
53 : TQObject( view, "kate search" )
54 , m_view( view )
55 , m_doc( view->doc() )
56 , replacePrompt( new KateReplacePrompt( view ) )
57{
58 m_arbitraryHLList = new KateSuperRangeList();
59 if (arbitraryHLExample) m_doc->arbitraryHL()->addHighlightToView(m_arbitraryHLList, m_view);
60
61 connect(replacePrompt,TQ_SIGNAL(clicked()),this,TQ_SLOT(replaceSlot()));
62}
63
64KateSearch::~KateSearch()
65{
66 delete m_arbitraryHLList;
67}
68
69void KateSearch::createActions( TDEActionCollection* ac )
70{
71 KStdAction::find( this, TQ_SLOT(find()), ac )->setWhatsThis(
72 i18n("Look up the first occurrence of a piece of text or regular expression."));
73 KStdAction::findNext( this, TQ_SLOT(slotFindNext()), ac )->setWhatsThis(
74 i18n("Look up the next occurrence of the search phrase."));
75 KStdAction::findPrev( this, TQ_SLOT(slotFindPrev()), ac, "edit_find_prev" )->setWhatsThis(
76 i18n("Look up the previous occurrence of the search phrase."));
77 KStdAction::replace( this, TQ_SLOT(replace()), ac )->setWhatsThis(
78 i18n("Look up a piece of text or regular expression and replace the result with some given text."));
79}
80
81void KateSearch::addToList( TQStringList& list, const TQString& s )
82{
83 if( list.count() > 0 ) {
84 TQStringList::Iterator it = list.find( s );
85 if( *it != 0L )
86 list.remove( it );
87 if( list.count() >= 16 )
88 list.remove( list.fromLast() );
89 }
90 list.prepend( s );
91}
92
93void KateSearch::find()
94{
95 // if multiline selection around, search in it
96 long searchf = KateViewConfig::global()->searchFlags();
97 if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
98 searchf |= KFindDialog::SelectedText;
99
100 KFindDialog *findDialog = new KFindDialog ( m_view, "", searchf,
101 s_searchList, m_view->hasSelection() );
102
103 findDialog->setPattern (getSearchText());
104
105
106 if( findDialog->exec() == TQDialog::Accepted ) {
107 s_searchList = findDialog->findHistory () ;
108 // Do *not* remove the TQString() wrapping, it fixes a nasty crash
109 find( TQString(s_searchList.first()), findDialog->options(), true, true );
110 }
111
112 delete findDialog;
113 m_view->repaintText ();
114}
115
116void KateSearch::find( const TQString &pattern, long flags, bool add, bool shownotfound )
117{
118 KateViewConfig::global()->setSearchFlags( flags );
119 if( add )
120 addToList( s_searchList, pattern );
121
122 s_pattern = pattern;
123
124 SearchFlags searchFlags;
125
126 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
127 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
128 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
129 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
130 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
131 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
132 searchFlags.prompt = false;
133 searchFlags.replace = false;
134 searchFlags.finished = false;
135 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
136 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
137
138 if ( searchFlags.selected )
139 {
140 s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
141 s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
142 s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
143 } else {
144 s.cursor = getCursor( searchFlags );
145 }
146
147 s.wrappedEnd = s.cursor;
148 s.wrapped = false;
149 s.showNotFound = shownotfound;
150
151 search( searchFlags );
152}
153
154void KateSearch::replace()
155{
156 if (!doc()->isReadWrite()) return;
157
158 // if multiline selection around, search in it
159 long searchf = KateViewConfig::global()->searchFlags();
160 if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
161 searchf |= KFindDialog::SelectedText;
162
163 KReplaceDialog *replaceDialog = new KReplaceDialog ( m_view, "", searchf,
164 s_searchList, s_replaceList, m_view->hasSelection() );
165
166 replaceDialog->setPattern (getSearchText());
167
168 if( replaceDialog->exec() == TQDialog::Accepted ) {
169 long opts = replaceDialog->options();
170 m_replacement = replaceDialog->replacement();
171 s_searchList = replaceDialog->findHistory () ;
172 s_replaceList = replaceDialog->replacementHistory () ;
173
174 // Do *not* remove the TQString() wrapping, it fixes a nasty crash
175 replace( TQString(s_searchList.first()), m_replacement, opts );
176 }
177
178 delete replaceDialog;
179 m_view->update ();
180}
181
182void KateSearch::replace( const TQString& pattern, const TQString &replacement, long flags )
183{
184 if (!doc()->isReadWrite()) return;
185
186 addToList( s_searchList, pattern );
187 s_pattern = pattern;
188 addToList( s_replaceList, replacement );
189 m_replacement = replacement;
190 KateViewConfig::global()->setSearchFlags( flags );
191
192 SearchFlags searchFlags;
193 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
194 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
195 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
196 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
197 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
198 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
199 searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
200 searchFlags.replace = true;
201 searchFlags.finished = false;
202 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
203 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
204 if ( searchFlags.selected )
205 {
206 s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
207 s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
208 s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
209 } else {
210 s.cursor = getCursor( searchFlags );
211 }
212
213 s.wrappedEnd = s.cursor;
214 s.wrapped = false;
215
216 search( searchFlags );
217}
218
219void KateSearch::findAgain( bool reverseDirection )
220{
221 SearchFlags searchFlags;
222 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
223 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
224 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
225 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
226 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
227 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
228 searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
229 searchFlags.replace = false;
230 searchFlags.finished = false;
231 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
232 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
233
234 if (reverseDirection)
235 searchFlags.backward = !searchFlags.backward;
236
237 searchFlags.fromBeginning = false;
238 searchFlags.prompt = true; // ### why is the above assignment there?
239
240 s.cursor = getCursor( searchFlags );
241 search( searchFlags );
242}
243
244void KateSearch::search( SearchFlags flags )
245{
246 s.flags = flags;
247
248 if( s.flags.fromBeginning ) {
249 if( !s.flags.backward ) {
250 s.cursor.setPos(0, 0);
251 } else {
252 s.cursor.setLine(doc()->numLines() - 1);
253 s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
254 }
255 }
256
257 if((!s.flags.backward &&
258 s.cursor.col() == 0 &&
259 s.cursor.line() == 0 ) ||
260 ( s.flags.backward &&
261 s.cursor.col() == doc()->lineLength( s.cursor.line() ) &&
262 s.cursor.line() == (((int)doc()->numLines()) - 1) ) ) {
263 s.flags.finished = true;
264 }
265
266 if( s.flags.replace ) {
267 replaces = 0;
268 if( s.flags.prompt )
269 promptReplace();
270 else
271 replaceAll();
272 } else {
273 findAgain();
274 }
275}
276
277void KateSearch::wrapSearch()
278{
279 if( s.flags.selected )
280 {
281 KateTextCursor start (s.selBegin);
282 KateTextCursor end (s.selEnd);
283
284 // recalc for block sel, to have start with lowest col, end with highest
285 if (m_view->blockSelectionMode())
286 {
287 start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
288 end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
289 }
290
291 s.cursor = s.flags.backward ? end : start;
292 }
293 else
294 {
295 if( !s.flags.backward ) {
296 s.cursor.setPos(0, 0);
297 } else {
298 s.cursor.setLine(doc()->numLines() - 1);
299 s.cursor.setCol(doc()->lineLength( s.cursor.line() ) );
300 }
301 }
302
303 // oh, we wrapped around one time allready now !
304 // only check that on replace
305 s.wrapped = s.flags.replace;
306
307 replaces = 0;
308 s.flags.finished = true;
309}
310
311void KateSearch::findAgain()
312{
313 if( s_pattern.isEmpty() ) {
314 find();
315 return;
316 }
317
318 if ( doSearch( s_pattern ) ) {
319 exposeFound( s.cursor, s.matchedLength );
320 } else if( !s.flags.finished ) {
321 if( askContinue() ) {
322 wrapSearch();
323 findAgain();
324 } else {
325 if (arbitraryHLExample) m_arbitraryHLList->clear();
326 }
327 } else {
328 if (arbitraryHLExample) m_arbitraryHLList->clear();
329 if ( s.showNotFound )
330 KMessageBox::sorry( view(),
331 i18n("Search string '%1' not found!")
332 .arg( KStringHandler::csqueeze( s_pattern ) ),
333 i18n("Find"));
334 }
335}
336
337void KateSearch::replaceAll()
338{
339 doc()->editStart ();
340
341 while( doSearch( s_pattern ) )
342 replaceOne();
343
344 doc()->editEnd ();
345
346 if( !s.flags.finished ) {
347 if( askContinue() ) {
348 wrapSearch();
349 replaceAll();
350 }
351 } else {
352 KMessageBox::information( view(),
353 i18n("%n replacement made.","%n replacements made.",replaces),
354 i18n("Replace") );
355 }
356}
357
358void KateSearch::promptReplace()
359{
360 if ( doSearch( s_pattern ) ) {
361 exposeFound( s.cursor, s.matchedLength );
362 replacePrompt->show();
363 replacePrompt->setFocus ();
364 } else if( !s.flags.finished && askContinue() ) {
365 wrapSearch();
366 promptReplace();
367 } else {
368 if (arbitraryHLExample) m_arbitraryHLList->clear();
369 replacePrompt->hide();
370 KMessageBox::information( view(),
371 i18n("%n replacement made.","%n replacements made.",replaces),
372 i18n("Replace") );
373 }
374}
375
376void KateSearch::replaceOne()
377{
378 TQString replaceWith = m_replacement;
379 if ( s.flags.regExp && s.flags.useBackRefs ) {
380 // Replace each "\0"..."\9" with the corresponding capture,
381 // "\n" and "\t" with newline and tab,
382 // "\\" with "\",
383 // and remove the "\" for any other sequence.
384 TQRegExp br("\\\\(.)");
385 int pos = br.search( replaceWith );
386 int ncaps = m_re.numCaptures();
387 while ( pos >= 0 ) {
388 TQString substitute;
389 TQChar argument = TQString(br.cap(1)).at(0);
390 if ( argument.isDigit() ) {
391 // the second character is a digit, this is a backreference
392 int ccap = argument.digitValue();
393 if (ccap <= ncaps ) {
394 substitute = m_re.cap( ccap );
395 } else {
396 kdDebug()<<"KateSearch::replaceOne(): you don't have "<<ccap<<" backreferences in regexp '"<<TQString(m_re.pattern())<<"'"<<endl;
397 break;
398 }
399 } else if ( argument == 'n' ) {
400 substitute = '\n';
401 } else if ( argument == 't' ) {
402 substitute = '\t';
403 } else {
404 // handle a validly escaped backslash, or an invalid escape.
405 substitute = argument;
406 }
407 replaceWith.replace( pos, br.matchedLength(), substitute );
408 pos = br.search( replaceWith, pos + substitute.length() );
409 }
410 }
411
412 doc()->editStart();
413 doc()->removeText( s.cursor.line(), s.cursor.col(),
414 s.cursor.line(), s.cursor.col() + s.matchedLength );
415 doc()->insertText( s.cursor.line(), s.cursor.col(), replaceWith );
416 doc()->editEnd(),
417
418 replaces++;
419
420 // if we inserted newlines, we better adjust.
421 uint newlines = replaceWith.contains('\n');
422 if ( newlines )
423 {
424 if ( ! s.flags.backward )
425 {
426 s.cursor.setLine( s.cursor.line() + newlines );
427 s.cursor.setCol( replaceWith.length() - replaceWith.findRev('\n') );
428 }
429 // selection?
430 if ( s.flags.selected )
431 s.selEnd.setLine( s.selEnd.line() + newlines );
432 }
433
434
435 // adjust selection endcursor if needed
436 if( s.flags.selected && s.cursor.line() == s.selEnd.line() )
437 {
438 s.selEnd.setCol(s.selEnd.col() + replaceWith.length() - s.matchedLength );
439 }
440
441 // adjust wrap cursor if needed
442 if( s.cursor.line() == s.wrappedEnd.line() && s.cursor.col() <= s.wrappedEnd.col())
443 {
444 s.wrappedEnd.setCol(s.wrappedEnd.col() + replaceWith.length() - s.matchedLength );
445 }
446
447 if( !s.flags.backward ) {
448 s.cursor.setCol(s.cursor.col() + replaceWith.length());
449 } else if( s.cursor.col() > 0 ) {
450 s.cursor.setCol(s.cursor.col() - 1);
451 } else {
452 s.cursor.setLine(s.cursor.line() - 1);
453 if( s.cursor.line() >= 0 ) {
454 s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
455 }
456 }
457}
458
459void KateSearch::skipOne()
460{
461 if( !s.flags.backward ) {
462 s.cursor.setCol(s.cursor.col() + s.matchedLength);
463 } else if( s.cursor.col() > 0 ) {
464 s.cursor.setCol(s.cursor.col() - 1);
465 } else {
466 s.cursor.setLine(s.cursor.line() - 1);
467 if( s.cursor.line() >= 0 ) {
468 s.cursor.setCol(doc()->lineLength(s.cursor.line()));
469 }
470 }
471}
472
473void KateSearch::replaceSlot() {
474 switch( (Dialog_results)replacePrompt->result() ) {
475 case srCancel: replacePrompt->hide(); break;
476 case srAll: replacePrompt->hide(); replaceAll(); break;
477 case srYes: replaceOne(); promptReplace(); break;
478 case srLast: replacePrompt->hide(), replaceOne(); break;
479 case srNo: skipOne(); promptReplace(); break;
480 }
481}
482
483bool KateSearch::askContinue()
484{
485 TQString made =
486 i18n( "%n replacement made.",
487 "%n replacements made.",
488 replaces );
489
490 TQString reached = !s.flags.backward ?
491 i18n( "End of document reached." ) :
492 i18n( "Beginning of document reached." );
493
494 if (KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText)
495 {
496 reached = !s.flags.backward ?
497 i18n( "End of selection reached." ) :
498 i18n( "Beginning of selection reached." );
499 }
500
501 TQString question = !s.flags.backward ?
502 i18n( "Continue from the beginning?" ) :
503 i18n( "Continue from the end?" );
504
505 TQString text = s.flags.replace ?
506 made + "\n" + reached + "\n" + question :
507 reached + "\n" + question;
508
509 return KMessageBox::Yes == KMessageBox::questionYesNo(
510 view(), text, s.flags.replace ? i18n("Replace") : i18n("Find"),
511 KStdGuiItem::cont(), i18n("&Stop") );
512}
513
514TQString KateSearch::getSearchText()
515{
516 // SelectionOnly: use selection
517 // WordOnly: use word under cursor
518 // SelectionWord: use selection if available, else use word under cursor
519 // WordSelection: use word if available, else use selection
520 TQString str;
521
522 int getFrom = view()->config()->textToSearchMode();
523 switch (getFrom)
524 {
525 case KateViewConfig::SelectionOnly: // (Windows)
526 //kdDebug() << "getSearchText(): SelectionOnly" << endl;
527 if( m_view->hasSelection() )
528 str = m_view->selection();
529 break;
530
531 case KateViewConfig::SelectionWord: // (classic Kate behavior)
532 //kdDebug() << "getSearchText(): SelectionWord" << endl;
533 if( m_view->hasSelection() )
534 str = m_view->selection();
535 else
536 str = view()->currentWord();
537 break;
538
539 case KateViewConfig::WordOnly: // (weird?)
540 //kdDebug() << "getSearchText(): WordOnly" << endl;
541 str = view()->currentWord();
542 break;
543
544 case KateViewConfig::WordSelection: // (persistent selection lover)
545 //kdDebug() << "getSearchText(): WordSelection" << endl;
546 str = view()->currentWord();
547 if (str.isEmpty() && m_view->hasSelection() )
548 str = m_view->selection();
549 break;
550
551 default: // (nowhere)
552 //kdDebug() << "getSearchText(): Nowhere" << endl;
553 break;
554 }
555
556 str.replace( TQRegExp("^\\n"), "" );
557 str.replace( TQRegExp("\\n.*"), "" );
558
559 return str;
560}
561
562KateTextCursor KateSearch::getCursor( SearchFlags flags )
563{
564 if (flags.backward && !flags.selected && view()->hasSelection())
565 {
566 // We're heading backwards (and not within a selection),
567 // the selection might start before the cursor.
568 return kMin( KateTextCursor(view()->selStartLine(), view()->selStartCol()),
569 KateTextCursor(view()->cursorLine(), view()->cursorColumnReal()));
570 }
571 return KateTextCursor(view()->cursorLine(), view()->cursorColumnReal());
572}
573
574bool KateSearch::doSearch( const TQString& text )
575{
576/*
577 rodda: Still Working on this... :)
578
579 bool result = false;
580
581 if (m_searchResults.count()) {
582 m_resultIndex++;
583 if (m_resultIndex < (int)m_searchResults.count()) {
584 s = m_searchResults[m_resultIndex];
585 result = true;
586 }
587
588 } else {
589 int temp = 0;
590 do {*/
591
592#if 0
593 static int oldLine = -1;
594 static int oldCol = -1;
595#endif
596
597 uint line = s.cursor.line();
598 uint col = s.cursor.col();// + (result ? s.matchedLength : 0);
599 bool backward = s.flags.backward;
600 bool caseSensitive = s.flags.caseSensitive;
601 bool regExp = s.flags.regExp;
602 bool wholeWords = s.flags.wholeWords;
603 uint foundLine, foundCol, matchLen;
604 bool found = false;
605 //kdDebug() << "Searching at " << line << ", " << col << endl;
606// kdDebug()<<"KateSearch::doSearch: "<<line<<", "<<col<<", "<<backward<<endl;
607
608 if (backward)
609 {
610 KateDocCursor docCursor(line, col, doc());
611
612 // If we're at the top of the document, we're not gonna find anything, so bail.
613 if (docCursor.line() == 0 && docCursor.col() == 0)
614 return false;
615
616 // Move one step backward before searching, if this is a "find again", we don't
617 // want to find the same match.
618 docCursor.moveBackward(1);
619 line = docCursor.line();
620 col = docCursor.col();
621 }
622
623 do {
624 if( regExp ) {
625 m_re = TQRegExp( text, caseSensitive );
626 found = doc()->searchText( line, col, m_re,
627 &foundLine, &foundCol,
628 &matchLen, backward );
629 }
630 else if ( wholeWords )
631 {
632 bool maybefound = false;
633 do
634 {
635 maybefound = doc()->searchText( line, col, text,
636 &foundLine, &foundCol,
637 &matchLen, caseSensitive, backward );
638 if ( maybefound )
639 {
640 found = (
641 ( foundCol == 0 ||
642 ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol - 1 ) ) ) &&
643 ( foundCol + matchLen == doc()->lineLength( foundLine ) ||
644 ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol + matchLen ) ) )
645 );
646 if ( found )
647 {
648 break;
649 }
650 else if ( backward && foundCol == 0 ) // we are done on this line and want to avoid endless loops like in #137312
651 {
652 if ( line == 0 ) // we are completely done...
653 break;
654 else
655 line--;
656 }
657 else
658 {
659 line = foundLine;
660 col = foundCol + 1;
661 }
662 }
663 } while ( maybefound );
664 }
665 else {
666 found = doc()->searchText( line, col, text,
667 &foundLine, &foundCol,
668 &matchLen, caseSensitive, backward );
669 }
670
671 if ( found && s.flags.selected )
672 {
673 KateTextCursor start (s.selBegin);
674 KateTextCursor end (s.selEnd);
675
676 // recalc for block sel, to have start with lowest col, end with highest
677 if (m_view->blockSelectionMode())
678 {
679 start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
680 end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
681 }
682
683 if ( !s.flags.backward && KateTextCursor( foundLine, foundCol ) >= end
684 || s.flags.backward && KateTextCursor( foundLine, foundCol ) < start )
685 {
686 found = false;
687 }
688 else if (m_view->blockSelectionMode())
689 {
690 if ((int)foundCol >= start.col() && (int)foundCol < end.col())
691 break;
692 }
693 }
694
695 line = foundLine;
696 col = foundCol+1;
697 }
698 while (s.flags.selected && m_view->blockSelectionMode() && found);
699 // in the case we want to search in selection + blockselection we need to loop
700
701 if( !found ) return false;
702
703 // save the search result
704 s.cursor.setPos(foundLine, foundCol);
705 s.matchedLength = matchLen;
706
707 // we allready wrapped around one time
708 if (s.wrapped)
709 {
710 if (s.flags.backward)
711 {
712 if ( (s.cursor.line() < s.wrappedEnd.line())
713 || ( (s.cursor.line() == s.wrappedEnd.line()) && ((s.cursor.col()+matchLen) <= uint(s.wrappedEnd.col())) ) )
714 return false;
715 }
716 else
717 {
718 if ( (s.cursor.line() > s.wrappedEnd.line())
719 || ( (s.cursor.line() == s.wrappedEnd.line()) && (s.cursor.col() > s.wrappedEnd.col()) ) )
720 return false;
721 }
722 }
723
724// kdDebug() << "Found at " << s.cursor.line() << ", " << s.cursor.col() << endl;
725
726
727 //m_searchResults.append(s);
728
729 if (arbitraryHLExample) {
730 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);
731 hl->setBold();
732 hl->setTextColor(TQt::white);
733 hl->setBGColor(TQt::black);
734 // destroy the highlight upon change
735 connect(hl, TQ_SIGNAL(contentsChanged()), hl, TQ_SIGNAL(eliminated()));
736 m_arbitraryHLList->append(hl);
737 }
738
739 return true;
740
741 /* rodda: more of my search highlighting work
742
743 } while (++temp < 100);
744
745 if (result) {
746 s = m_searchResults.first();
747 m_resultIndex = 0;
748 }
749 }
750
751 return result;*/
752}
753
754void KateSearch::exposeFound( KateTextCursor &cursor, int slen )
755{
756 view()->setCursorPositionInternal ( cursor.line(), cursor.col() + slen, 1 );
757 view()->setSelection( cursor.line(), cursor.col(), cursor.line(), cursor.col() + slen );
758 view()->syncSelectionCache();
759}
760//END KateSearch
761
762//BEGIN KateReplacePrompt
763// this dialog is not modal
764KateReplacePrompt::KateReplacePrompt ( TQWidget *parent )
765 : KDialogBase ( parent, 0L, false, i18n( "Replace Confirmation" ),
766 User3 | User2 | User1 | Close | Ok , Ok, true,
767 i18n("Replace &All"), i18n("Re&place && Close"), i18n("&Replace") )
768{
769 setButtonOK( i18n("&Find Next") );
770 TQWidget *page = new TQWidget(this);
771 setMainWidget(page);
772
773 TQBoxLayout *topLayout = new TQVBoxLayout( page, 0, spacingHint() );
774 TQLabel *label = new TQLabel(i18n("Found an occurrence of your search term. What do you want to do?"),page);
775 topLayout->addWidget(label );
776}
777
778void KateReplacePrompt::slotOk ()
779{ // Search Next
780 done(KateSearch::srNo);
781 actionButton(Ok)->setFocus();
782}
783
784void KateReplacePrompt::slotClose ()
785{ // Close
786 done(KateSearch::srCancel);
787 actionButton(Close)->setFocus();
788}
789
790void KateReplacePrompt::slotUser1 ()
791{ // Replace All
792 done(KateSearch::srAll);
793 actionButton(User1)->setFocus();
794}
795
796void KateReplacePrompt::slotUser2 ()
797{ // Replace & Close
798 done(KateSearch::srLast);
799 actionButton(User2)->setFocus();
800}
801
802void KateReplacePrompt::slotUser3 ()
803{ // Replace
804 done(KateSearch::srYes);
805 actionButton(User3)->setFocus();
806}
807
808void KateReplacePrompt::done (int result)
809{
810 setResult(result);
811
812 emit clicked();
813}
814//END KateReplacePrompt
815
816//BEGIN SearchCommand
817bool SearchCommand::exec(class Kate::View *view, const TQString &cmd, TQString &msg)
818{
819 TQString flags, pattern, replacement;
820 if ( cmd.startsWith( "find" ) )
821 {
822
823 static TQRegExp re_find("find(?::([bcersw]*))?\\s+(.+)");
824 if ( re_find.search( cmd ) < 0 )
825 {
826 msg = i18n("Usage: find[:[bcersw]] PATTERN");
827 return false;
828 }
829 flags = re_find.cap( 1 );
830 pattern = re_find.cap( 2 );
831 }
832
833 else if ( cmd.startsWith( "ifind" ) )
834 {
835 static TQRegExp re_ifind("ifind(?::([bcrs]*))?\\s+(.*)");
836 if ( re_ifind.search( cmd ) < 0 )
837 {
838 msg = i18n("Usage: ifind[:[bcrs]] PATTERN");
839 return false;
840 }
841 ifindClear();
842 return true;
843 }
844
845 else if ( cmd.startsWith( "replace" ) )
846 {
847 // Try if the pattern and replacement is quoted, using a quote character ["']
848 static TQRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
849 // Or one quoted argument
850 TQRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
851 // Else, it's just one or two (space separated) words
852 TQRegExp re_rep2("replace(?::([bceprsw]*))?\\s+(\\S+)(.*)");
853#define unbackslash(s) p=0;\
854while ( (p = pattern.find( '\\' + delim, p )) > -1 )\
855{\
856 if ( !p || pattern[p-1] != '\\' )\
857 pattern.remove( p, 1 );\
858 p++;\
859}
860
861 if ( re_rep.search( cmd ) >= 0 )
862 {
863 flags = re_rep.cap(1);
864 pattern = re_rep.cap( 3 );
865 replacement = re_rep.cap( 4 );
866
867 int p(0);
868 // unbackslash backslashed delimiter strings
869 // in pattern ..
870 TQString delim = re_rep.cap( 2 );
871 unbackslash(pattern);
872 // .. and in replacement
873 unbackslash(replacement);
874 }
875 else if ( re_rep1.search( cmd ) >= 0 )
876 {
877 flags = re_rep1.cap(1);
878 pattern = re_rep1.cap( 3 );
879
880 int p(0);
881 TQString delim = re_rep1.cap( 2 );
882 unbackslash(pattern);
883 }
884 else if ( re_rep2.search( cmd ) >= 0 )
885 {
886 flags = re_rep2.cap( 1 );
887 pattern = re_rep2.cap( 2 );
888 replacement = TQString(re_rep2.cap( 3 )).stripWhiteSpace();
889 }
890 else
891 {
892 msg = i18n("Usage: replace[:[bceprsw]] PATTERN [REPLACEMENT]");
893 return false;
894 }
895 kdDebug()<<"replace '"<<pattern<<"' with '"<<replacement<<"'"<<endl;
896#undef unbackslash
897 }
898
899 long f = 0;
900 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
901 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
902 if ( flags.contains( 'e' ) ) f |= KFindDialog::SelectedText;
903 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
904 if ( flags.contains( 'p' ) ) f |= KReplaceDialog::PromptOnReplace;
905 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
906 if ( flags.contains( 'w' ) ) f |= KFindDialog::WholeWordsOnly;
907
908 if ( cmd.startsWith( "find" ) )
909 {
910 ((KateView*)view)->find( pattern, f );
911 return true;
912 }
913 else if ( cmd.startsWith( "replace" ) )
914 {
915 f |= KReplaceDialog::BackReference; // mandatory here?
916 ((KateView*)view)->replace( pattern, replacement, f );
917 return true;
918 }
919
920 return false;
921}
922
923bool SearchCommand::help(class Kate::View *, const TQString &cmd, TQString &msg)
924{
925 if ( cmd == "find" )
926 msg = i18n("<p>Usage: <code>find[:bcersw] PATTERN</code></p>");
927
928 else if ( cmd == "ifind" )
929 msg = i18n("<p>Usage: <code>ifind:[:bcrs] PATTERN</code>"
930 "<br>ifind does incremental or 'as-you-type' search</p>");
931
932 else
933 msg = i18n("<p>Usage: <code>replace[:bceprsw] PATTERN REPLACEMENT</code></p>");
934
935 msg += i18n(
936 "<h4><caption>Options</h4><p>"
937 "<b>b</b> - Search backward"
938 "<br><b>c</b> - Search from cursor"
939 "<br><b>r</b> - Pattern is a regular expression"
940 "<br><b>s</b> - Case sensitive search"
941 );
942
943 if ( cmd == "find" )
944 msg += i18n(
945 "<br><b>e</b> - Search in selected text only"
946 "<br><b>w</b> - Search whole words only"
947 );
948
949 if ( cmd == "replace" )
950 msg += i18n(
951 "<br><b>p</b> - Prompt for replace</p>"
952 "<p>If REPLACEMENT is not present, an empty string is used.</p>"
953 "<p>If you want to have whitespace in your PATTERN, you need to "
954 "quote both PATTERN and REPLACEMENT with either single or double "
955 "quotes. To have the quote characters in the strings, prepend them "
956 "with a backslash.");
957
958 msg += "</p>";
959 return true;
960}
961
962TQStringList SearchCommand::cmds()
963{
964 TQStringList l;
965 l << "find" << "replace" << "ifind";
966 return l;
967}
968
969bool SearchCommand::wantsToProcessText( const TQString &cmdname )
970{
971 return cmdname == "ifind";
972}
973
974void SearchCommand::processText( Kate::View *view, const TQString &cmd )
975{
976 static TQRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)");
977 if ( re_ifind.search( cmd ) > -1 )
978 {
979 TQString flags = re_ifind.cap( 1 );
980 TQString pattern = re_ifind.cap( 2 );
981
982
983 // if there is no setup, or the text length is 0, set up the properties
984 if ( ! m_ifindFlags || pattern.isEmpty() )
985 ifindInit( flags );
986 // if there is no fromCursor, add it if this is not the first character
987 else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
988 m_ifindFlags |= KFindDialog::FromCursor;
989
990 // search..
991 if ( ! pattern.isEmpty() )
992 {
993 KateView *v = (KateView*)view;
994
995 // If it *looks like* we are continuing, place the cursor
996 // at the beginning of the selection, so that the search continues.
997 // ### check more carefully, like is the cursor currently at the end
998 // of the selection.
999 if ( pattern.startsWith( v->selection() ) &&
1000 v->selection().length() + 1 == pattern.length() )
1001 v->setCursorPositionInternal( v->selStartLine(), v->selStartCol() );
1002
1003 v->find( pattern, m_ifindFlags, false );
1004 }
1005 }
1006}
1007
1008void SearchCommand::ifindInit( const TQString &flags )
1009{
1010 long f = 0;
1011 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
1012 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
1013 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
1014 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
1015 m_ifindFlags = f;
1016}
1017
1018void SearchCommand::ifindClear()
1019{
1020 m_ifindFlags = 0;
1021}
1022//END SearchCommand
KDialogBase
KDialogBase::setButtonOK
void setButtonOK(const KGuiItem &item=KStdGuiItem::ok())
KDialogBase::setMainWidget
void setMainWidget(TQWidget *widget)
KDialogBase::actionButton
TQPushButton * actionButton(ButtonCode id)
KDialogBase::User3
User3
KDialogBase::Close
Close
KDialogBase::User2
User2
KDialogBase::User1
User1
KDialogBase::Ok
Ok
KDialog::spacingHint
static int spacingHint()
KMessageBox::information
static void information(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const TQString &dontShowAgainName=TQString::null, int options=Notify)
KMessageBox::questionYesNo
static int questionYesNo(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonYes=KStdGuiItem::yes(), const KGuiItem &buttonNo=KStdGuiItem::no(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
KMessageBox::sorry
static void sorry(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
KStdGuiItem::cont
static KGuiItem cont()
KStringHandler::csqueeze
static TQString csqueeze(const TQString &str, uint maxlen=40)
KateDocCursor
Cursor class with a pointer to its document.
Definition: katecursor.h:93
KateReplacePrompt
simple replace prompt dialog
Definition: katesearch.h:169
KateReplacePrompt::slotUser3
void slotUser3()
Yes pressed.
Definition: katesearch.cpp:802
KateReplacePrompt::slotUser2
void slotUser2()
last pressed
Definition: katesearch.cpp:796
KateReplacePrompt::slotOk
void slotOk()
ok pressed
Definition: katesearch.cpp:778
KateReplacePrompt::KateReplacePrompt
KateReplacePrompt(TQWidget *parent)
Constructor.
Definition: katesearch.cpp:764
KateReplacePrompt::done
void done(int result)
dialog done
Definition: katesearch.cpp:808
KateReplacePrompt::slotClose
void slotClose()
close pressed
Definition: katesearch.cpp:784
KateReplacePrompt::slotUser1
void slotUser1()
replace all pressed
Definition: katesearch.cpp:790
KateReplacePrompt::clicked
void clicked()
button clicked
KateSuperCursor
Possible additional features:
Definition: katesupercursor.h:46
KateTextCursor
Simple cursor class with no document pointer.
Definition: katecursor.h:34
Kate::View
The Kate::View text editor interface.
Definition: view.h:45
Kate::View::currentWord
virtual TQString currentWord()
Gets the word where the cursor is on.
Definition: view.h:76
Kate::View::replace
virtual void replace()
Presents a replace dialog to the user.
Definition: view.h:184
TDEActionCollection
TDEAction::setWhatsThis
virtual void setWhatsThis(const TQString &text)
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
KStdAction::findPrev
TDEAction * findPrev(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
KStdAction::replace
TDEAction * replace(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
KStdAction::findNext
TDEAction * findNext(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
KStdAction::find
TDEAction * find(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
TDEStdAccel::end
const TDEShortcut & end()
TDEStdAccel::find
const TDEShortcut & find()
TDEStdAccel::replace
const TDEShortcut & replace()
tdelocale.h

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.4
This website is maintained by Timothy Pearson.