• 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
47 TQStringList KateSearch::s_searchList = TQStringList();
48 TQStringList KateSearch::s_replaceList = TQStringList();
49 TQString KateSearch::s_pattern = TQString();
50 static const bool arbitraryHLExample = false;
51 
52 KateSearch::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 
64 KateSearch::~KateSearch()
65 {
66  delete m_arbitraryHLList;
67 }
68 
69 void 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 
81 void 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 
93 void 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 
116 void 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 
154 void 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 
182 void 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 
219 void 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 
244 void 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 
277 void 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 
311 void 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 
337 void 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 
358 void 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 
376 void 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 
459 void 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 
473 void 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 
483 bool 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 
514 TQString 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 
562 KateTextCursor 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 
574 bool 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 
754 void 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
764 KateReplacePrompt::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 
778 void KateReplacePrompt::slotOk ()
779 { // Search Next
780  done(KateSearch::srNo);
781  actionButton(Ok)->setFocus();
782 }
783 
784 void KateReplacePrompt::slotClose ()
785 { // Close
786  done(KateSearch::srCancel);
787  actionButton(Close)->setFocus();
788 }
789 
790 void KateReplacePrompt::slotUser1 ()
791 { // Replace All
792  done(KateSearch::srAll);
793  actionButton(User1)->setFocus();
794 }
795 
796 void KateReplacePrompt::slotUser2 ()
797 { // Replace & Close
798  done(KateSearch::srLast);
799  actionButton(User2)->setFocus();
800 }
801 
802 void KateReplacePrompt::slotUser3 ()
803 { // Replace
804  done(KateSearch::srYes);
805  actionButton(User3)->setFocus();
806 }
807 
808 void KateReplacePrompt::done (int result)
809 {
810  setResult(result);
811 
812  emit clicked();
813 }
814 //END KateReplacePrompt
815 
816 //BEGIN SearchCommand
817 bool 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;\
854 while ( (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 
923 bool 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 
962 TQStringList SearchCommand::cmds()
963 {
964  TQStringList l;
965  l << "find" << "replace" << "ifind";
966  return l;
967 }
968 
969 bool SearchCommand::wantsToProcessText( const TQString &cmdname )
970 {
971  return cmdname == "ifind";
972 }
973 
974 void 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 
1008 void 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 
1018 void 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.1
This website is maintained by Timothy Pearson.