Code::Blocks  SVN r11506
find_replace.cpp
Go to the documentation of this file.
1 #include "sdk.h"
2 
3 #include "find_replace.h"
4 
5 #ifndef CB_PRECOMP
6  #include <wx/dir.h>
7  #include <wx/regex.h>
8 
9  #include "cbauibook.h"
10  #include "cbeditor.h"
11  #include "cbproject.h"
12  #include "editormanager.h"
13  #include "infowindow.h"
14  #include "projectfile.h"
15 #endif
16 
17 #include <wx/progdlg.h>
18 
19 #include "annoyingdialog.h"
20 #include "cbstyledtextctrl.h"
21 #include "confirmreplacedlg.h"
22 #include "encodingdetector.h"
23 #include "findreplacedlg.h"
24 #include "searchresultslog.h"
25 
27 {
28  int start;
29  int end;
36  bool matchWord;
37  bool startWord;
38  bool startFile;
39  bool matchCase;
40  bool regEx;
43  int scope;
50  bool NewSearch;
55  bool multiLine;
56  bool fixEOLs;
57  int eolMode;
58 
59  void ConvertEOLs(int newmode);
60  bool IsMultiLine();
61 
63  {
64  eolMode = wxSCI_EOL_LF;
65  fixEOLs = false;
66  }
67 };
68 
70 {
71  if (eolMode != newmode)
72  {
73  const wxChar* eol_lf = _T("\n");
74  const wxChar* eol_crlf = _T("\r\n");
75  const wxChar* eol_cr = _T("\r");
76 
77  const wxChar* eol_from = eol_lf;
78  const wxChar* eol_to = eol_lf;
79  switch(eolMode)
80  {
81  case wxSCI_EOL_CR: eol_from = eol_cr; break;
82  case wxSCI_EOL_CRLF: eol_from = eol_crlf; break;
83  default: ;
84  }
85  switch(newmode)
86  {
87  case wxSCI_EOL_CR: eol_to = eol_cr; break;
88  case wxSCI_EOL_CRLF: eol_to = eol_crlf; break;
89  default: newmode = wxSCI_EOL_LF;
90  }
91  findText.Replace(eol_from, eol_to, true);
92  replaceText.Replace(eol_from, eol_to, true);
93  eolMode = newmode;
94  }
95 }
96 
98 {
99  if (regEx) // For regex always assume multiline if the multiline checkbox is enabled because the user can enter "\n" to search for newlines
100  return multiLine;
101  // otherwise only treat the search as a multiline search only if there are newline characters in the search string
102  return ((findText.Find(_T("\n")) != wxNOT_FOUND) || (findText.Find(_T("\r")) != wxNOT_FOUND));
103 }
104 
106  m_LastFindReplaceData(nullptr)
107 {
108 }
109 
111 {
112  delete m_LastFindReplaceData;
113 }
114 
116 {
117  if (Manager::IsBatchBuild())
118  return;
119 
120  wxArrayInt widths;
121  wxArrayString titles;
122  titles.Add(_("File"));
123  titles.Add(_("Line"));
124  titles.Add(_("Text"));
125  widths.Add(128);
126  widths.Add(48);
127  widths.Add(640);
128 
129  wxString prefix = ConfigManager::GetDataFolder() + _T("/images/16x16/");
130  wxBitmap * bmp = new wxBitmap(cbLoadBitmap(prefix + _T("filefind.png"), wxBITMAP_TYPE_PNG));
131 
132  m_pSearchLog = new cbSearchResultsLog(titles, widths);
133  CodeBlocksLogEvent evt(cbEVT_ADD_LOG_WINDOW, m_pSearchLog, _("Search results"), bmp);
134  Manager::Get()->ProcessEvent(evt);
136 }
137 
138 void FindReplace::LogSearch(const wxString& file, int line, const wxString& lineText)
139 {
140  wxArrayString values;
141  wxString lineTextL;
142  wxString lineStr;
143 
144  // line number -1 is used for empty string
145  if (line != -1)
146  lineStr.Printf(_T("%d"), line);
147  else
148  lineStr.Printf(_T(" "));
149 
150  lineTextL = lineText;
151  lineTextL.Replace(_T("\t"), _T(" "));
152  lineTextL.Replace(_T("\r"), _T(" "));
153  lineTextL.Replace(_T("\n"), _T(" "));
154  lineTextL.Trim(false);
155  lineTextL.Trim(true);
156  if (lineTextL.Length() > 300)
157  lineTextL.Truncate(280) += _T("...");
158 
159  values.Add(file);
160  values.Add(lineStr);
161  values.Add(lineTextL);
162 
163  m_pSearchLog->Append(values, line == -1 ? Logger::caption : Logger::info);
164 }
165 
166 int FindReplace::ShowFindDialog(bool replace, bool explicitly_find_in_files)
167 {
168  wxString phraseAtCursor;
169  bool hasSelection = false;
170  cbStyledTextCtrl* control = nullptr;
171 
172  EditorManager *editorMgr = Manager::Get()->GetEditorManager();
173 
174  cbEditor* ed = editorMgr->GetBuiltinEditor(editorMgr->GetActiveEditor());
175  if (ed)
176  {
177  control = ed->GetControl();
178 
179  hasSelection = control->GetSelectionStart() != control->GetSelectionEnd();
180  int wordStart = control->WordStartPosition(control->GetCurrentPos(), true);
181  int wordEnd = control->WordEndPosition(control->GetCurrentPos(), true);
182  wxString wordAtCursor = control->GetTextRange(wordStart, wordEnd);
183  phraseAtCursor = control->GetSelectedText();
184  // if selected text is part of a single line, don't suggest "search in selection"
185  if (control->LineFromPosition(control->GetSelectionStart())
186  == control->LineFromPosition(control->GetSelectionEnd()))
187  hasSelection = false;
188 
189  if ( phraseAtCursor.IsEmpty())
190  phraseAtCursor = wordAtCursor;
191 
192  int selstartline = control->LineFromPosition(control->GetSelectionStart());
193  int selendline = control->LineFromPosition(control->GetSelectionEnd());
194  // the selection of several lines is not proposed as search pattern
195  if ( selstartline != selendline )
196  phraseAtCursor = wxEmptyString;
197 
198  }
199 
200  FindReplaceBase* dlg = new FindReplaceDlg(Manager::Get()->GetAppWindow(), phraseAtCursor, hasSelection,
201  !replace, !ed, explicitly_find_in_files);
202 
203  PlaceWindow(dlg);
204  if (dlg->ShowModal() == wxID_CANCEL)
205  {
206  dlg->Destroy();
207  return -2;
208  }
209 
210  // Don't look for empty strings:
211  if (dlg->GetFindString().empty())
212  {
213  dlg->Destroy();
214  cbMessageBox(_("Can't look for an empty search criterion!"), _("Error"), wxOK | wxICON_EXCLAMATION, Manager::Get()->GetAppWindow());
215  return -2;
216  }
217 
220 
229 
232  {
233  //AutoWrapSearch does not exist in FindInFiles dialog
235 
236  //FindUsesSelectedText does not exist in Replace dialogs
237  if (!replace)
239  }
257 
258  if (control)
259  { // if editor : store the selection start/end
260  // only use this in case of !findInFiles and scope==1 (search in selection)
263  }
264  dlg->Destroy();
265 
267  {
268  // Match nasty regexes
270  {
271  cbMessageBox(_T("Bad regex entered!\nPlease correct regex and try again!"), _T("Error!"), wxICON_ERROR);
272  return 0;
273  }
274  }
275 
276  int ReturnValue = 0;
277  if (!replace)
278  {
280  ReturnValue = FindInFiles(m_LastFindReplaceData);
281  else
282  ReturnValue = Find(control, m_LastFindReplaceData);
283  }
284  else
285  {
287 
289  ReturnValue = ReplaceInFiles(m_LastFindReplaceData);
290  else
291  ReturnValue = Replace(control, m_LastFindReplaceData);
292  }
293  m_LastFindReplaceData->NewSearch = false; // we have searched, so no longer new search
294 
295  //Default back to find or replace in Editor
297  {
299  }
300  return ReturnValue;
301 }
302 
304 {
305  if (!control || !data)
306  return;
307  if (data->startFile) // Beginning-of-file needs the entire scope
308  {
309  int clen = control->GetLength();
310  int slen = data->findText.Len();
311 
312  data->start = 0;
313  data->end = std::min(slen, clen);
314  }
315  else if (!data->findInFiles) // Find in current Editor
316  {
317  int ssta = control->GetSelectionStart();
318  int send = control->GetSelectionEnd();
319  int cpos = control->GetCurrentPos();
320  int clen = control->GetLength();
321 
322  // when the user initially had a selection, but then changed the scope
323  // to entire scope, the values of ssta and send will have a bad influence in
324  // the following calculations, therefor check for the scenario
325  // and set the ssta en send to cpos (in the case there would be no selection
326  // that's the value they have [no selection : ssta=send=cpos])
327  // only do this when it's a new search (when the search is continued (F3/Shift-F3)
328  // there can be a selection, the last found match)
329  if ((data->scope == 0) && data->NewSearch && (ssta != cpos || send != cpos))
330  {
331  // Don't do this in replace mode, because we want to start the replacement
332  // with the current selection, not the first match after the selection.
333  if (!replace)
334  {
335  ssta = cpos;
336  send = cpos;
337  }
338  }
339 
340 
341 
342  data->start = 0;
343  data->end = clen;
344 
345  if (!data->originEntireScope || !data->NewSearch) // from pos or next/prev search
346  {
347  if (!data->directionDown) // up
348  // initial replacing mode - include selection end : normal mode - skip until selection start
349  data->start = (data->initialreplacing)? std::max(send, cpos) : std::min(ssta, cpos);
350  else // down
351  // initial replacing mode - include selection start : normal mode - skip until selection end
352  data->start = (data->initialreplacing)? std::min(ssta, cpos) : std::max(send, cpos);
353  }
354  else // entire scope
355  {
356  if (!data->directionDown) // up
357  data->start = clen;
358  }
359 
360  if (!data->directionDown) // up
361  data->end = 0;
362 
363  // selected text, if user has deslected since last, then change scope
364  if (data->scope == 1 &&
365  control->GetSelectionStart()==control->GetSelectionEnd())
366  data->scope = 0; // global
367 
368  if (data->scope == 1) // selected text
369  {
370  if (data->NewSearch)
371  {
372  if (!data->directionDown) // up
373  {
374  data->start = std::max(ssta, send);
375  data->end = std::min(ssta, send);
376  }
377  else // down
378  {
379  data->start = std::min(ssta, send);
380  data->end = std::max(ssta, send);
381  }
382  }
383  else
384  { // this is the result of a next/previous search
385  // rebase depending on the cursor position
386  ssta = data->SearchInSelectionStart;
387  send = data->SearchInSelectionEnd;
388  if (cpos < ssta || cpos > send)
389  { // regular reset (this also provide some sort of wrap around) (other editors also did it like that)
390  data->start = ssta;
391  data->end = send;
392  }
393  else
394  {
395  data->start = cpos;
396  data->end = (data->directionDown)?send:ssta;
397  }
398  }
399  }
400  }
401  else // FindInFiles
402  { // searching direction down, entire scope
403  //Replace needs the entire scope, while find can wrap around.
404  data->start = ( replace ? 0 : control->GetCurrentPos() );
405  data->end = control->GetLength();
406  }
407 }
408 
410 {
411  if (!control || !data)
412  return -1;
413 
414  if (control->GetReadOnly())
415  {
416  cbMessageBox(_("This file is read-only.\nReplacing in a read-only file is not possible."),
417  _("Warning"), wxICON_EXCLAMATION);
418  return -1;
419  }
420 
421  bool advRegex = false;
422  bool advRegexNewLinePolicy =! data->IsMultiLine();
423  int replacecount = 0;
424  int foundcount = 0;
425  int flags = 0;
426 
427  {
428  int eolMode = control->GetEOLMode();
429  data->ConvertEOLs(eolMode); // Convert our S&R data to the file's EOL mode.
430  if (data->IsMultiLine() && data->fixEOLs)
431  {
432  // First we must ensure that the file has consistent line endings.
433  // As all the file's lines are affected, we disable change history for this step.
434 
435  control->BeginUndoAction();
436  control->SetChangeCollection(false);
437  control->ConvertEOLs(eolMode);
438  control->SetChangeCollection(true);
439  control->EndUndoAction();
440  }
441  }
442  control->BeginUndoAction(); // The undo is set at this point in case we need to convert the EOLs.
443 
444  CalculateFindReplaceStartEnd(control, data, true);
445 
446  if (data->matchWord)
447  flags |= wxSCI_FIND_WHOLEWORD;
448  if (data->startWord)
449  flags |= wxSCI_FIND_WORDSTART;
450  if (data->matchCase)
451  flags |= wxSCI_FIND_MATCHCASE;
452  if (data->regEx)
453  {
454  flags |= wxSCI_FIND_REGEXP;
455  if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
456  flags |= wxSCI_FIND_POSIX;
457  #ifdef wxHAS_REGEX_ADVANCED
458  advRegex = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
459  #endif
460  }
461 
462  wxRegEx re;
463  #ifdef wxHAS_REGEX_ADVANCED
464  if (advRegex)
465  {
466  if (data->matchCase)
467  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy));
468  else
469  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy)|wxRE_ICASE);
470  }
471  #endif
472 
473  int pos = -1;
474  bool replace = false;
475  bool confirm = true;
476  bool stop = false;
477  wxPoint LastDlgPosition;
478  bool HaveLastDlgPosition = false;
479  bool wrapAround = false;
480  int data_start_initial = data->start;
481  bool wrapAroundNotification = false;
482 
483  while (!stop)
484  {
485  int lengthFound = 0;
486  if (!advRegex)
487  {
488  pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
489  lengthFound -= pos;
490  }
491  else
492  {
493  wxString text=control->GetTextRange(data->start, data->end);
494  if (re.Matches(text))
495  {
496  size_t start,len;
497  re.GetMatch(&start,&len,0);
498  pos=start+data->start;
499  lengthFound=len;
500  if ((start==0) && (len==0)) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
501  {
502  text=text.Mid(1);
503  if (re.Matches(text))
504  {
505  re.GetMatch(&start, &len, 0);
506  pos = start+data->start + 1;
507  lengthFound = len;
508  } else
509  pos=-1;
510  }
511  } else
512  pos=-1;
513  }
514 
515  if (data->startFile && pos > 0)
516  pos = -1; // Not found at the beginning of file
517 
518  if (pos != -1 && data->start!=data->end)
519  {
520  control->GotoPos(pos);
521  control->EnsureVisible(control->LineFromPosition(pos));
522  control->SetSelectionVoid(pos, pos + lengthFound);
523  data->start = pos;
524  data->initialreplacing = false; // special treatment only necessary the first time
525  }
526  else if (!wrapAround)
527  {
528  if ( (data->scope == 0) && // scope = global text
529  ((data->directionDown && data_start_initial != 0) ||
530  (!data->directionDown && data_start_initial != control->GetLength())))
531  {
532  wxString msg;
533  if (data->directionDown)
534  msg = _("Text not found.\nSearch from the start of the document?");
535  else
536  msg = _("Text not found.\nSearch from the end of the document?");
537 
538  bool auto_wrap_around = data->autoWrapSearch;
539  if (auto_wrap_around)
540  wrapAroundNotification = true;
541  if (auto_wrap_around || cbMessageBox(msg, _("Result"), wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
542  {
543  data->end = data_start_initial;
544  data->start = (data->directionDown)? 0 : control->GetLength();
545  wrapAround = true; // signal the wrap-around
546  continue;
547  }
548  else
549  break; // done - user doesn't want to wrap around
550  }
551  else
552  break; // done - we're replacing in a selection of text
553  }
554  else
555  break; // done - already wrapped around once
556 
557  if (wrapAroundNotification)
558  {
559  wxBell();
560  InfoWindow::Display(_("Find action"), _("Reached the end of the document"), 1000);
561  wrapAroundNotification = false;
562  }
563 
564  foundcount++;
565 
566  if (confirm)
567  {
568  ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow());
569  // dlg.CalcPosition(control);
570  // TODO (thomas#1#): Check whether the existing code actually works with twin view
571  // else, we need something like:
572  // PlaceWindow(&dlg, pdlRelative);
573 
574  // NOTE (Tiwag#1#): dlg.CalcPosition doesn't work for me with dual monitor setup,
575  // workaround : remember last dialog position, user can position
576  // it outside of text where he wants
577  // Move dialog to last position if already available,
578  // else place it according to environments settings
579  if ( HaveLastDlgPosition )
580  dlg.Move(LastDlgPosition);
581  else
582  dlg.CalcPosition(control);
583 
584  int ans = dlg.ShowModal();
585  LastDlgPosition = dlg.GetPosition();
586  HaveLastDlgPosition = true;
587  switch (ans)
588  {
589  case crYes:
590  replace = true;
591  break;
592  case crNo:
593  replace = false;
594  break;
595  case crAll:
596  replace = true;
597  confirm = false;
598  control->Freeze();
599  break;
600  case crCancel:
601  stop = true;
602  break;
603  default:
604  break;
605  }
606  }
607 
608  if (!stop)
609  {
610  if (replace)
611  {
612  int lengthReplace = data->replaceText.Length();
613  replacecount++;
614  if (data->regEx)
615  {
616  // set target same as selection
617  control->SetTargetStart(control->GetSelectionStart());
618  control->SetTargetEnd(control->GetSelectionEnd());
619  if (advRegex)
620  {
621  wxString text=control->GetSelectedText();
622  re.Replace(&text,data->replaceText,1);
623  lengthReplace=text.Len();
624  control->ReplaceSelection(text);
625  }
626  else
627  {
628  // replace with regEx support
629  lengthReplace = control->ReplaceTargetRE(data->replaceText);
630  }
631 
632  // reset target
633  control->SetTargetStart(0);
634  control->SetTargetEnd(0);
635  }
636  else
637  control->ReplaceSelection(data->replaceText);
638  if (data->directionDown)
639  data->start += lengthReplace;
640 
641  // adjust end pos by adding the length difference between find and replace strings
642  int diff = lengthReplace - lengthFound;
643  if (data->directionDown)
644  data->end += diff;
645  else
646  {
647  if (data->end < diff)
648  data->end = 0;
649  else
650  data->end -= diff;
651  }
652  }
653  else
654  {
655  if (data->directionDown)
656  data->start += lengthFound;
657  else
658  data->start -= lengthFound;
659  }
660  }
661  }
662  if (control->IsFrozen())
663  control->Thaw();
664  control->EndUndoAction();
665  wxString msg;
666  if (foundcount == 0)
667  msg = _T("No matches found for \"") + data->findText + _T("\"");
668  else if (replacecount == 0 && foundcount == 1)
669  msg = _T("One match found but not replaced");
670  else
671  msg.Printf(_("Replaced %i of %i matches"), replacecount, foundcount);
672  cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
673  control->SetSCIFocus(true);
674 
675  return pos;
676 }
677 
679 {
680  if (!data) return 0;
681  if (data->findText.IsEmpty()) return 0;
682 
683  EditorManager *editorMgr = Manager::Get()->GetEditorManager();
684 
685  bool IsMultiLine = data->IsMultiLine();
686 
687  // let's make a list of all the files to search in
688  wxArrayString filesList;
689 
690  if (data->scope == 0) // find in open files
691  {
692  // fill the search list with the open files
693  for (int i = 0; i < editorMgr->GetEditorsCount(); ++i)
694  {
695  cbEditor* ed = editorMgr->GetBuiltinEditor(i);
696  if (ed)
697  filesList.Add(ed->GetFilename());
698  }
699  }
700  else if (data->scope == 1) // find in project files
701  {
702  // fill the search list with all the project files
703  if (data->searchProject<0)
704  {
705  cbMessageBox(_("No project to search in!"), _("Error"), wxICON_WARNING);
706  return 0;
707  }
709  wxString target;
710  wxString fullpath = _T("");
711  if (data->searchTarget >= 0)
712  target = prj->GetBuildTarget(data->searchTarget)->GetTitle();
713  for (FilesList::iterator it = prj->GetFilesList().begin(); it != prj->GetFilesList().end(); ++it)
714  {
715  ProjectFile* pf = *it;
716  if (pf)
717  {
718  if (target!=wxEmptyString && pf->buildTargets.Index(target)<0)
719  continue;
720  fullpath = pf->file.GetFullPath();
721  if (filesList.Index(fullpath) >= 0) // avoid adding duplicates
722  continue;
723  if (wxFileExists(fullpath)) // Does the file exist?
724  filesList.Add(fullpath);
725  }
726  }
727  }
728  else if (data->scope == 2) // find in workspace
729  {
730  // loop over all the projects in the workspace (they are contained in the ProjectManager)
731  const ProjectsArray* pProjects = Manager::Get()->GetProjectManager()->GetProjects();
732  if (pProjects)
733  {
734  int count = pProjects->GetCount();
735  for (int idxProject = 0; idxProject < count; ++idxProject)
736  {
737  cbProject* pProject = pProjects->Item(idxProject);
738  if (pProject)
739  {
740  wxString fullpath = _T("");
741 
742  for (FilesList::iterator it = pProject->GetFilesList().begin(); it != pProject->GetFilesList().end(); ++it)
743  {
744  ProjectFile* pf = *it;
745  if (pf)
746  {
747  fullpath = pf->file.GetFullPath();
748  if (filesList.Index(fullpath) == -1) // avoid adding duplicates
749  {
750  if (wxFileExists(fullpath)) // Does the file exist?
751  filesList.Add(fullpath);
752  }
753  }
754  } // end for : idx : idxFile
755  }
756  } // end for : idx : idxProject
757  }
758  }
759  else if (data->scope == 3) // replace in custom search path and mask
760  {
761  // fill the search list with the files found under the search path
762  int flags = wxDIR_FILES |
763  (data->recursiveSearch ? wxDIR_DIRS : 0) |
764  (data->hiddenSearch ? wxDIR_HIDDEN : 0);
766  if (!masks.GetCount())
767  masks.Add(_T("*"));
768  unsigned int count = masks.GetCount();
769  wxLogNull ln; // no logging
770  for (unsigned int i = 0; i < count; ++i)
771  {
772  // wxDir::GetAllFiles() does *not* clear the array, so it suits us just fine ;)
773  wxDir::GetAllFiles(data->searchPath, &filesList, masks[i], flags);
774  }
775  }
776  // if the list is empty, leave
777  int filesCount = filesList.GetCount();
778  if (filesCount == 0)
779  {
780  cbMessageBox(_("No files to search in!"), _("Error"), wxICON_WARNING);
781  return 0;
782  }
783 
784  bool advRegex=false;
785  bool advRegexNewLinePolicy =! data->IsMultiLine();
786  int flags = 0;
787  if (data->matchWord)
788  flags |= wxSCI_FIND_WHOLEWORD;
789  if (data->startWord)
790  flags |= wxSCI_FIND_WORDSTART;
791  if (data->matchCase)
792  flags |= wxSCI_FIND_MATCHCASE;
793  if (data->regEx)
794  {
795  flags |= wxSCI_FIND_REGEXP;
796  if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
797  flags |= wxSCI_FIND_POSIX;
798  #ifdef wxHAS_REGEX_ADVANCED
799  advRegex = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
800  #endif
801  }
802 
803  wxRegEx re;
804  #ifdef wxHAS_REGEX_ADVANCED
805  if (advRegex)
806  {
807  if (data->matchCase)
808  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy));
809  else
810  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy)|wxRE_ICASE);
811  }
812  #endif
813 
814 
815  bool replace = false;
816  bool confirm = true;
817  bool stop = false;
818  bool wholeFile = false;
819  bool all = false;
820  int pos = -1;
821 
822  wxPoint LastDlgPosition;
823  bool HaveLastDlgPosition = false;
824 
825  wxProgressDialog* progress = nullptr;
826  wxString fileContents;
827  wxString enc_name = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/default_encoding"), wxLocale::GetSystemEncodingName());
828  wxFontEncoding def_encoding = wxFontMapper::GetEncodingFromName(enc_name);
829 
830  // keep a copy of the find struct
831  cbFindReplaceData dataCopy = *data;
832 
833  int read_only_files_skipped = 0;
834  for (int i = 0; i<filesCount && !stop; ++i)
835  {
836  cbEditor* ed = NULL;
837  cbStyledTextCtrl* control = NULL;
838  bool fileWasNotOpen = false;
839 
840  if (progress)
841  {
842  if (!progress->Update(i))
843  {
844  if (cbMessageBox(_("Are you sure you want to stop replacing in files?"), _("Confirmation"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
845  break;
846  else
847  progress->Resume();
848  }
849  }
850 
851  //Check if this file is already open
852  EditorBase *eb = editorMgr->IsOpen(filesList[i]);
853  if (eb)
854  {
855  //File was already open
856  fileWasNotOpen = false;
857 
858  ed = editorMgr->GetBuiltinEditor(eb);
859  if (ed) control = ed->GetControl();
860  }
861 
862  //If it's still NULL, open a new editor
863  if (!control)
864  {
865  wxFile file(filesList[i]);
866  if (!file.IsOpened())
867  continue;
868  fileContents = cbReadFileContents(file, def_encoding);
869  if (advRegex)
870  {
871  if (!re.Matches(fileContents))
872  continue;
873  } else
874  {
875  int pos_str;
876  if (!data->matchCase)
877  pos_str = fileContents.Upper().Find(data->findText.Upper());
878  else
879  pos_str = fileContents.Find(data->findText);
880  if (pos_str == -1)
881  continue;
882  //TODO: handling to skip file if data->matchWord or data->startWord are set
883  }
884 
885  //File was not open, i opened it.
886  fileWasNotOpen = true;
887 
888  ed = editorMgr->Open(filesList[i]);
889  if (ed) control = ed->GetControl();
890  }
891  //Still NULL?
892  if (!control || !ed)
893  continue;
894 
895  if (control->GetReadOnly())
896  {
897  read_only_files_skipped++;
898  continue;
899  }
900 
901  editorMgr->SetActiveEditor(ed);
902 
903  *data = dataCopy;
904 
905  bool replacementsWereMade = false;
906  // If we fix the file's EOLs for multi-line S&R, we're actually modifying it.
907  // What we really want to know is whether we actually did a replacement.
908  // If not (and the file was not open in the first place), we can safely close the file.
909 
910  {
911  // We should be checking if the data has EOLs before converting them. But searching is
912  // just as expensive as doing the conversion itself, so we just convert.
913  int eolMode = control->GetEOLMode();
914  data->ConvertEOLs(eolMode);
915 
916  if (IsMultiLine && data->fixEOLs)
917  {
918  control->BeginUndoAction(); //undo
919  control->SetChangeCollection(false);
920  control->ConvertEOLs(eolMode);
921  control->SetChangeCollection(true);
922  control->EndUndoAction();
923  }
924  }
925 
926  control->BeginUndoAction(); // undo
927  CalculateFindReplaceStartEnd(control, data, true);
928 
929  //reset bools
930  wholeFile = false;
931  if (!all) confirm = true;
932 
933  //Replace in this file
934  while (!stop || wholeFile)
935  {
936  int lengthFound = 0;
937  if (!advRegex)
938  {
939  pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
940  lengthFound -= pos;
941  }
942  else
943  {
944  wxString text=control->GetTextRange(data->start, data->end);
945  if (re.Matches(text))
946  {
947  size_t start,len;
948  re.GetMatch(&start, &len, 0);
949  pos = start + data->start;
950  lengthFound = len;
951  if ((start==0) && (len==0)) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
952  {
953  text = text.Mid(1);
954  if (re.Matches(text))
955  {
956  re.GetMatch(&start, &len, 0);
957  pos = start + data->start + 1;
958  lengthFound = len;
959  } else
960  pos = -1;
961  }
962  } else
963  pos = -1;
964  }
965 
966  if (data->startFile && (pos > 0))
967  pos = -1; // Not found at the beginning of file
968 
969  if ((pos == -1) || (data->start == data->end))
970  break;
971 
972  if (confirm)
973  {
974  control->GotoPos(pos);
975  control->EnsureVisible(control->LineFromPosition(pos));
976  }
977  control->SetSelectionVoid(pos, pos + lengthFound);
978  data->start = pos;
979  data->initialreplacing = false; // special treatment only necessary the first time
980 
981  if (confirm)
982  {
983  ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow(), true);
984  // dlg.CalcPosition(control);
985  // TODO (thomas#1#): Check whether the existing code actually works with twin view
986  // else, we need something like:
987  // PlaceWindow(&dlg, pdlRelative);
988 
989  // NOTE (Tiwag#1#): dlg.CalcPosition doesn't work for me with dual monitor setup,
990  // workaround : remember last dialog position, user can position
991  // it outside of text where he wants
992  // Move dialog to last position if already available,
993  // else place it according to environments settings
994  if ( HaveLastDlgPosition )
995  dlg.Move(LastDlgPosition);
996  else
997  dlg.CalcPosition(control);
998 
999  int ans = dlg.ShowModal();
1000  LastDlgPosition = dlg.GetPosition();
1001  HaveLastDlgPosition = true;
1002  switch (ans)
1003  {
1004  case crYes:
1005  replace = true;
1006  break;
1007  case crNo:
1008  replace = false;
1009  break;
1010  case crAllInFile:
1011  confirm = false;
1012  replace = true;
1013  wholeFile = true;
1014  break;
1015  case crSkipFile:
1016  confirm = false;
1017  replace = false;
1018  wholeFile = true;
1019  break;
1020  case crAll:
1021  replace = true;
1022  confirm = false;
1023  all = true;
1024  // let's create a progress dialog because it might take some time depending on the files count
1025  progress = new wxProgressDialog(_("Replace in files"),
1026  _("Please wait while replacing in files..."),
1027  filesCount,
1028  Manager::Get()->GetAppWindow(),
1030  PlaceWindow(progress);
1031  // now that we need no confirmation, freeze the app window
1032  Manager::Get()->GetAppWindow()->Freeze();
1033  break;
1034  case crCancel:
1035  stop = true;
1036  break;
1037  default:
1038  break;
1039  }
1040  }// if
1041 
1042  if (!stop)
1043  {
1044  if (replace)
1045  {
1046  replacementsWereMade = true;
1047  int lengthReplace = data->replaceText.Length();
1048  if (data->regEx)
1049  {
1050  // set target same as selection
1051  control->SetTargetStart(control->GetSelectionStart());
1052  control->SetTargetEnd(control->GetSelectionEnd());
1053  if (advRegex)
1054  {
1055  wxString text=control->GetSelectedText();
1056  re.Replace(&text,data->replaceText,1);
1057  lengthReplace=text.Len();
1058  control->ReplaceSelection(text);
1059  }
1060  else // replace with regEx support
1061  lengthReplace = control->ReplaceTargetRE(data->replaceText);
1062 
1063  // reset target
1064  control->SetTargetStart(0);
1065  control->SetTargetEnd(0);
1066  }
1067  else
1068  control->ReplaceSelection(data->replaceText);
1069 
1070  data->start += lengthReplace;
1071 
1072  // adjust end pos by adding the length difference
1073  // between find and replace strings
1074  int diff = lengthReplace - lengthFound;
1075  if (data->directionDown)
1076  data->end += diff;
1077  else
1078  data->end -= diff;
1079  }
1080  else
1081  {
1082  if (data->directionDown)
1083  data->start += lengthFound;
1084  else
1085  data->start -= lengthFound;
1086  }
1087  }// if
1088  }// while
1089 
1090  control->EndUndoAction(); // undo
1091 
1092  // If opened the file and no replacement was made, close the editor
1093  if (!replacementsWereMade && fileWasNotOpen)
1094  editorMgr->Close(ed, true);
1095  }// for
1096 
1097  if (read_only_files_skipped)
1098  {
1099  wxString msg;
1100  msg.Printf(_("Skipped %d read-only file(s)."), read_only_files_skipped);
1101  InfoWindow::Display(_("Warning"), msg);
1102  }
1103 
1104  // if we showed the progress, the app window is frozen; unfreeze it
1105  if (progress)
1106  Manager::Get()->GetAppWindow()->Thaw();
1107 
1108  delete progress;
1109  AnnoyingDialog dlg(_("Replace in files"),
1110  _("Replace in files has finished all operations."),
1112  dlg.ShowModal();
1113 
1114  return pos;
1115 }
1116 
1118 {
1119  if (!control || !data)
1120  return -1;
1121 
1122  bool advRegex = false;
1123  bool advRegexNewLinePolicy =! data->IsMultiLine();
1124  int flags = 0;
1125  data->ConvertEOLs(control->GetEOLMode());
1126  CalculateFindReplaceStartEnd(control, data);
1127 
1128  if (data->matchWord)
1129  flags |= wxSCI_FIND_WHOLEWORD;
1130  if (data->startWord)
1131  flags |= wxSCI_FIND_WORDSTART;
1132  if (data->matchCase)
1133  flags |= wxSCI_FIND_MATCHCASE;
1134  if (data->regEx)
1135  {
1136  flags |= wxSCI_FIND_REGEXP;
1137  if (Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_posix_style_regexes"), false))
1138  flags |= wxSCI_FIND_POSIX;
1139  #ifdef wxHAS_REGEX_ADVANCED
1140  advRegex = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/use_advanced_regexes"), false);
1141  #endif
1142  }
1143 
1144  wxRegEx re;
1145  #ifdef wxHAS_REGEX_ADVANCED
1146  if (advRegex)
1147  {
1148  if (data->matchCase)
1149  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy));
1150  else
1151  re.Compile(data->findText,wxRE_ADVANCED|(wxRE_NEWLINE*advRegexNewLinePolicy)|wxRE_ICASE);
1152  }
1153  #endif
1154 
1155  int pos = -1;
1156  // avoid infinite loop when wrapping search around, eventually crashing WinLogon O.O
1157  bool wrapAround = false;
1158  int StartPos = 0;
1159  int EndPos = control->GetLength();
1160  if (data->scope == 1) // selectd text
1161  {
1162  StartPos = data->SearchInSelectionStart;
1163  EndPos = data->SearchInSelectionEnd;
1164  }
1165  bool wrapAroundNotification = false;
1166  while (true) // loop while not found and user selects to start again from the top
1167  {
1168  int lengthFound = 0;
1169  if (!advRegex)
1170  {
1171  pos = control->FindText(data->start, data->end, data->findText, flags, &lengthFound);
1172  lengthFound -= pos;
1173  }
1174  else
1175  {
1176  wxString text = control->GetTextRange(data->start, data->end);
1177  if (re.Matches(text))
1178  {
1179  size_t start, len;
1180  re.GetMatch(&start, &len, 0);
1181  pos = start + data->start;
1182  lengthFound = len;
1183  if ((start==0) && (len==0)) //For searches for "^" or "$" (and null returning variants on this) need to make sure we have forward progress and not simply matching on a previous BOL/EOL find
1184  {
1185  text = text.Mid(1);
1186  if (re.Matches(text))
1187  {
1188  re.GetMatch(&start, &len, 0);
1189  pos = start + data->start + 1;
1190  lengthFound = len;
1191  }
1192  else
1193  pos=-1;
1194  }
1195  }
1196  else
1197  pos=-1;
1198  }
1199  if (pos != -1 && data->start!=data->end)
1200  {
1201  int line = control->LineFromPosition(pos);
1202  int onScreen = control->LinesOnScreen() >> 1;
1203  int l1 = line - onScreen;
1204  int l2 = line + onScreen;
1205  for (int l=l1; l<=l2; l+=2) // unfold visible lines on screen
1206  control->EnsureVisible(l);
1207  control->GotoLine(l1); // center selection on screen
1208  control->GotoLine(l2);
1209  control->GotoLine(line);
1210  control->SetSelectionVoid(pos, pos + lengthFound);
1211 // Manager::Get()->GetLogManager()->DebugLog("pos=%d, selLen=%d, length=%d", pos, data->end - data->start, lengthFound);
1212  data->start = pos;
1213  break; // done
1214  }
1215  else if (!wrapAround && !data->findInFiles) // for "find in files" we don't want to show messages
1216  {
1217  if ( (data->directionDown && data->start != StartPos)
1218  || (!data->directionDown && data->start != EndPos) )
1219  {
1220  wxString msg;
1221  if (data->scope == 1) // selected text
1222  {
1223  if (data->directionDown)
1224  msg = _("Text not found.\nSearch from the start of the selection?");
1225  else
1226  msg = _("Text not found.\nSearch from the end of the selection?");
1227  }
1228  else
1229  {
1230  if (data->directionDown)
1231  msg = _("Text not found.\nSearch from the start of the document?");
1232  else
1233  msg = _("Text not found.\nSearch from the end of the document?");
1234  }
1235 
1236  bool auto_wrap_around = data->autoWrapSearch;
1237  if (auto_wrap_around)
1238  wrapAroundNotification = true;
1239 
1240  if (auto_wrap_around || cbMessageBox(msg, _("Result"), wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
1241  {
1242  wrapAround = true; // signal the wrap-around
1243  if (data->scope == 1) // selected text
1244  {
1245  if (data->directionDown)
1246  {
1247  data->start = data->SearchInSelectionStart;
1248  data->end = data->SearchInSelectionEnd;
1249  }
1250  else
1251  {
1252  data->start = data->SearchInSelectionEnd;
1253  data->end = data->SearchInSelectionStart;
1254  }
1255  }
1256  else // global
1257  {
1258  if (data->directionDown)
1259  {
1260  data->start = 0;
1261  data->end = control->GetLength();
1262  }
1263  else
1264  {
1265  data->start = control->GetLength();
1266  data->end = 0;
1267  }
1268  }
1269  }
1270  else
1271  break; // done
1272  }
1273  else
1274  {
1275  wxString msg;
1276  msg.Printf(_("Not found: %s"), data->findText.c_str());
1277  cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
1278  control->SetSCIFocus(true);
1279  wrapAroundNotification = false;
1280  break; // done
1281  }
1282  }
1283  else if (wrapAround)
1284  {
1285  wxString msg;
1286  msg.Printf(_("Not found: %s"), data->findText.c_str());
1287  cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
1288  wrapAroundNotification = false;
1289  break; // done
1290  }
1291  else
1292  break; // done
1293  }
1294 
1295  if (wrapAroundNotification)
1296  {
1297  wxBell();
1298  InfoWindow::Display(_("Find action"), _("Reached the end of the document"), 1000);
1299  }
1300 
1301  return pos;
1302 }
1303 
1305 {
1306  if (!data || data->findText.IsEmpty())
1307  return 0;
1308 
1309  // clear old search results
1310  if ( data->delOldSearches )
1311  {
1312  m_pSearchLog->Clear();
1313  }
1314  int oldcount = m_pSearchLog->GetItemsCount();
1315 
1316  EditorManager *editorMgr = Manager::Get()->GetEditorManager();
1317 
1318  // let's make a list of all the files to search in
1319  wxArrayString filesList;
1320 
1321  if (data->scope == 0) // find in open files
1322  {
1323  // fill the search list with the open files
1324  for (int i = 0; i < editorMgr->GetEditorsCount(); ++i)
1325  {
1326  cbEditor* ed = editorMgr->GetBuiltinEditor(i);
1327  if (ed)
1328  filesList.Add(ed->GetFilename());
1329  }
1330  }
1331  else if (data->scope == 1) // find in project files
1332  {
1333  // fill the search list with all the project files
1334  if(data->searchProject<0)
1335  {
1336  cbMessageBox(_("No project to search in!"), _("Error"), wxICON_WARNING);
1337  return 0;
1338  }
1340  wxString target;
1341  wxString fullpath = _T("");
1342  if(data->searchTarget >= 0)
1343  target = prj->GetBuildTarget(data->searchTarget)->GetTitle();
1344  for (FilesList::iterator it = prj->GetFilesList().begin(); it != prj->GetFilesList().end(); ++it)
1345  {
1346  ProjectFile* pf = *it;
1347  if (pf)
1348  {
1349  if(target!=wxEmptyString && pf->buildTargets.Index(target)<0)
1350  continue;
1351  fullpath = pf->file.GetFullPath();
1352  if (filesList.Index(fullpath) >= 0) // avoid adding duplicates
1353  continue;
1354  if (wxFileExists(fullpath)) // Does the file exist?
1355  filesList.Add(fullpath);
1356  }
1357  }
1358  }
1359  else if (data->scope == 2) // find in workspace
1360  {
1361  // loop over all the projects in the workspace (they are contained in the ProjectManager)
1362  const ProjectsArray* pProjects = Manager::Get()->GetProjectManager()->GetProjects();
1363  int count = 0;
1364  if (pProjects)
1365  count = pProjects->GetCount();
1366  if (!count)
1367  {
1368  cbMessageBox(_("No workspace to search in!"), _("Error"), wxICON_WARNING);
1369  return 0;
1370  }
1371  for (int idxProject = 0; idxProject < count; ++idxProject)
1372  {
1373  cbProject* pProject = pProjects->Item(idxProject);
1374  if (pProject)
1375  {
1376  wxString fullpath = _T("");
1377  for (FilesList::iterator it = pProject->GetFilesList().begin(); it != pProject->GetFilesList().end(); ++it)
1378  {
1379  ProjectFile* pf = *it;
1380  if (pf)
1381  {
1382  fullpath = pf->file.GetFullPath();
1383  if (filesList.Index(fullpath) == -1) // avoid adding duplicates
1384  {
1385  if (wxFileExists(fullpath)) // Does the file exist?
1386  filesList.Add(fullpath);
1387  }
1388  }
1389  } // end for : idx : idxFile
1390  }
1391  } // end for : idx : idxProject
1392  }
1393  else if (data->scope == 3) // find in custom search path and mask
1394  {
1395  // fill the search list with the files found under the search path
1396  int flags = wxDIR_FILES |
1397  (data->recursiveSearch ? wxDIR_DIRS : 0) |
1398  (data->hiddenSearch ? wxDIR_HIDDEN : 0);
1400  if (!masks.GetCount())
1401  masks.Add(_T("*"));
1402  unsigned int count = masks.GetCount();
1403 
1404  for (unsigned int i = 0; i < count; ++i)
1405  {
1406  // wxDir::GetAllFiles() does *not* clear the array, so it suits us just fine ;)
1407  wxDir::GetAllFiles(data->searchPath, &filesList, masks[i], flags);
1408  }
1409  }
1410  else if (data->scope == 4) // find in current file only
1411  {
1412  cbEditor* ed = editorMgr->GetBuiltinActiveEditor();
1413  if (ed)
1414  filesList.Add(ed->GetFilename());
1415  }
1416 
1417 
1418  // if the list is empty, leave
1419  if (filesList.GetCount() == 0)
1420  {
1421  cbMessageBox(_("No files to search in!"), _("Error"), wxICON_WARNING);
1422  return 0;
1423  }
1424 
1425  // sort search results alphabetically if option is on
1427  filesList.Sort();
1428 
1429  // now that list is filled, we'll search
1430  // but first we'll create a hidden cbStyledTextCtrl to do the search for us ;)
1431  cbStyledTextCtrl* control = new cbStyledTextCtrl(editorMgr->GetNotebook(), -1, wxDefaultPosition, wxSize(0, 0));
1432  control->Show(false); //hidden
1433 
1434  // let's create a progress dialog because it might take some time depending on the files count
1435  wxProgressDialog* progress = new wxProgressDialog(_("Find in files"),
1436  _("Please wait while searching inside the files..."),
1437  filesList.GetCount(),
1440 
1441  PlaceWindow(progress);
1442 
1443  // keep a copy of the find struct
1444  cbFindReplaceData localData = *data;
1445 
1446  if ( !data->delOldSearches )
1447  {
1448  LogSearch(_T("=========="), -1, _T("=== \"") + data->findText + _T("\" ==="));
1449  oldcount++;
1450  }
1451 
1452  int lastline = -1;
1453  int count = 0;
1454  for (size_t i = 0; i < filesList.GetCount(); ++i)
1455  {
1456  // update the progress bar
1457  if (!progress->Update(i))
1458  break; // user pressed "Cancel"
1459 
1460  // re-initialize the find struct for every file searched
1461  *data = localData;
1462 
1463  // check if the file is already opened in built-in editor and do search in it
1464  cbEditor* ed = editorMgr->IsBuiltinOpen(filesList[i]);
1465  if (ed)
1466  control->SetText(ed->GetControl()->GetText());
1467  else // else load the file in the control
1468  {
1469  EncodingDetector detector(filesList[i]);
1470  if (!detector.IsOK())
1471  {
1472  continue; // failed
1473  }
1474  control->SetText(detector.GetWxStr());
1475  }
1476 
1477  // now search for first occurence
1478  if (Find(control, data) == -1)
1479  {
1480  lastline = -1;
1481  continue;
1482  }
1483 
1484  int line = control->LineFromPosition(control->GetSelectionStart());
1485  lastline = line;
1486 
1487  // make the filename relative
1488  wxString filename = filesList[i];
1489  if (filename.StartsWith(data->searchPath))
1490  {
1491  wxFileName fname(filename);
1492  fname.MakeRelativeTo(data->searchPath);
1493  filename = fname.GetFullPath();
1494  }
1495 
1496  // log it
1497  LogSearch(filename, line + 1, control->GetLine(line));
1498  ++count;
1499 
1500  // now loop finding the next occurence
1501  while ( FindNext(true, control, data, false) != -1 )
1502  {
1503  if (data->startFile) // we already found it, so break and avoid possible infinite loop
1504  break;
1505 // // log it
1506  line = control->LineFromPosition(control->GetSelectionStart());
1507  if (line == lastline) // avoid multiple hits on the same line (try search for "manager")
1508  continue;
1509 
1510  lastline = line;
1511  LogSearch(filename, line + 1, control->GetLine(line));
1512  ++count;
1513  }
1514  }
1515  delete control; // done with it
1516  delete progress; // done here too
1517 
1518  if (count > 0)
1519  {
1521  if (Manager::Get()->GetConfigManager(_T("message_manager"))->ReadBool(_T("/auto_show_search"), true))
1522  {
1525 
1526  Manager::Get()->ProcessEvent(evtSwitch);
1527  Manager::Get()->ProcessEvent(evtShow);
1528  }
1529  m_pSearchLog->FocusEntry(oldcount);
1530  }
1531  else
1532  {
1533  wxString msg;
1534  if ( data->delOldSearches )
1535  {
1536  msg.Printf(_("Not found: %s"), data->findText.c_str());
1537  cbMessageBox(msg, _("Result"), wxICON_INFORMATION);
1539  if (ed)
1540  ed->GetControl()->SetSCIFocus(true);
1541  }
1542  else
1543  {
1544  msg.Printf(_("not found in %lu files"), static_cast<unsigned long>(filesList.GetCount()));
1545  LogSearch(_T(""), -1, msg );
1546  m_pSearchLog->FocusEntry(oldcount);
1547  }
1548  }
1549 
1550  return count;
1551 }
1552 
1553 int FindReplace::FindNext(bool goingDown, cbStyledTextCtrl* control, cbFindReplaceData* data, bool selected)
1554 {
1555  if (!control)
1556  {
1558  if (ed)
1559  control = ed->GetControl();
1560  }
1561 
1562  if (!control)
1563  return -1;
1564 
1565  if (!data)
1566  {
1567  data = m_LastFindReplaceData;
1568  // FindNext/Previous called from Search menu (F3/Shift-F3)
1569  if (data) data->findInFiles = false;
1570  }
1571 
1572  if (!data)
1573  {
1574  if (selected)
1575  {
1577  data = m_LastFindReplaceData;
1578  data->findInFiles = false;
1579  }
1580  else
1581  return ShowFindDialog(false, false);
1582  }
1583 
1584  if (!data->findInFiles)
1585  {
1586  if (selected)
1587  {
1588  data->start = 0;
1589  data->end = 0;
1590  data->findText = control->GetSelectedText();
1591  data->replaceText = wxEmptyString;
1592  data->eolMode = wxSCI_EOL_LF;
1593  data->multiLine = false;
1594  data->fixEOLs = false;
1595  data->startFile = false;
1596  data->findInFiles = false;
1597  data->matchWord = false;
1598  data->startWord = false;
1599  data->matchCase = false;
1600  data->regEx = false;
1601  data->originEntireScope = false;
1602  data->scope = 0; // global
1603  data->searchPath = wxEmptyString;
1604  data->searchMask = wxEmptyString;
1605  data->recursiveSearch = false;
1606  data->searchProject = false;
1607  data->searchTarget = false;
1608  data->hiddenSearch = false;
1609  data->initialreplacing = false;
1610  data->NewSearch = false;
1611  }
1612 
1613  wxString phraseAtCursor = control->GetSelectedText();
1614 
1615  if (!data->findUsesSelectedText && !selected)
1616  { // The mandrav find behavior
1617  // change findText to selected text (if any text is selected and no search text was set before)
1618  if (!phraseAtCursor.IsEmpty() && data->findText.IsEmpty())
1619  data->findText = phraseAtCursor;
1620  }
1621  else
1622  { // The tiwag find behavior
1623  // change findText to selected text (if any text is selected)
1624  if (!phraseAtCursor.IsEmpty())
1625  {
1626  data->findText = phraseAtCursor;
1627  data->originEntireScope = false; //search from cursor
1628  data->scope = 0; // global ("selected text" is useful only from Find Dialog)
1629  }
1630  }
1631  }
1632  data->directionDown = goingDown;
1633  return Find(control, data);
1634 }
1635 
1637 {
1639  if (ed)
1640  {
1641  cbStyledTextCtrl *stc = ed->GetControl();
1642  wxString text = stc->GetSelectedText();
1643  if (!text.size())
1644  {
1645  //selecting word at current cursor position
1646  int iCurrentPos = stc->GetCurrentPos();
1647 
1648  stc->SetSelectionStart(stc->WordStartPosition(iCurrentPos, true));
1649  stc->SetSelectionEnd(stc->WordEndPosition(iCurrentPos, true));
1650  }
1651 
1652  return FindNext(goingDown, nullptr, nullptr, true);
1653  }
1654 
1655  return -1;
1656 }
static wxFontEncoding GetEncodingFromName(const wxString &encoding)
DLLIMPORT wxArrayString GetArrayFromString(const wxString &text, const wxString &separator=DEFAULT_ARRAY_SEP, bool trimSpaces=true)
Definition: globals.cpp:134
cbEditor * IsBuiltinOpen(const wxString &filename)
Definition: editormanager.h:92
static void Display(const wxString &title, const wxString &message, unsigned int delay=5000, unsigned int hysteresis=1)
Definition: infowindow.cpp:294
virtual bool GetAutoWrapSearch() const =0
#define wxSCI_FIND_REGEXP
Definition: wxscintilla.h:260
int Replace(cbStyledTextCtrl *control, cbFindReplaceData *data)
void Append(const wxString &msg, Logger::level lv=info) override
Definition: loggers.cpp:363
void ReplaceSelection(const wxString &text)
Replace the selected text with the argument text.
virtual bool Update(int value, const wxString &newmsg=wxEmptyString, bool *skip=NULL)
void SetSelectionVoid(int startPos, int endPos)
Select a range of text.
int WordEndPosition(int pos, bool onlyWordCharacters)
Get position of end of word.
void EnsureVisible(int line)
Ensure a particular line is visible by expanding any header line hiding it.
#define wxICON_QUESTION
#define wxICON_WARNING
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
virtual bool IsFindInFiles() const =0
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
#define wxSCI_EOL_CR
Definition: wxscintilla.h:84
int ReplaceInFiles(cbFindReplaceData *data)
bool fixEOLs
for multi-line S&R. Fixes EOLs in all the files searched.
#define wxICON_ERROR
DLLIMPORT wxBitmap cbLoadBitmap(const wxString &filename, wxBitmapType bitmapType=wxBITMAP_TYPE_PNG)
This function loads a bitmap from disk.
Definition: globals.cpp:1102
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
Definition: cbproject.h:685
bool wxFileExists(const wxString &filename)
wxFileName file
The full filename of this file.
Definition: projectfile.h:126
virtual int GetDirection() const =0
virtual bool GetFixEOLs() const =0
#define wxSCI_EOL_LF
Definition: wxscintilla.h:85
virtual bool GetHidden() const =0
#define wxSCI_FIND_WHOLEWORD
Definition: wxscintilla.h:257
int ShowFindDialog(bool replace, bool explicitly_find_in_files=false)
virtual int GetOrigin() const =0
bool ReadBool(const wxString &name, bool defaultVal=false)
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
bool multiLine
for multi-line S&R.
virtual bool GetFindUsesSelectedText() const =0
virtual int GetScope() const =0
#define wxCANCEL
Event used to request from the main app to add a log.
Definition: sdk_events.h:182
size_t Length() const
wxCStrData c_str() const
void SetText(const wxString &text)
Replace the contents of the document with the argument text.
wxString GetLine(int line) const
Retrieve the contents of a line.
bool Matches(const wxString &text, int flags=0) const
#define _T(string)
void SetActiveEditor(EditorBase *ed)
int GetSelectionStart() const
Returns the position at the start of the selection.
virtual wxString GetSearchMask() const =0
#define wxYES_NO
bool Close(const wxString &filename, bool dontsave=false)
void wxBell()
virtual size_t GetItemsCount() const
Definition: loggers.cpp:394
#define wxICON_INFORMATION
virtual bool GetSortSearchResult() const =0
static size_t GetAllFiles(const wxString &dirname, wxArrayString *files, const wxString &filespec=wxEmptyString, int flags=wxDIR_DEFAULT)
wxFontEncoding
#define wxPD_CAN_ABORT
void CreateSearchLog()
#define wxNOT_FOUND
cbSearchResultsLog * m_pSearchLog
Definition: find_replace.h:32
Represents a file in a Code::Blocks project.
Definition: projectfile.h:39
bool empty() const
void SetBasePath(const wxString base)
wxWindow * GetAppWindow() const
Definition: manager.cpp:424
#define wxICON_EXCLAMATION
int WordStartPosition(int pos, bool onlyWordCharacters)
Get position of start of word.
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
void SetSelectionEnd(int caret)
Sets the position that ends the selection - this becomes the caret.
virtual int GetTarget() const =0
Try to detect the encoding of a file on disk.
wxUSE_UNICODE_dependent wxChar
virtual wxString GetReplaceString() const =0
void Clear() override
Definition: loggers.cpp:399
wxString GetSelectedText()
Retrieve the selected text.
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
bool MakeRelativeTo(const wxString &pathBase=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
DLLIMPORT wxString cbReadFileContents(wxFile &file, wxFontEncoding encoding=wxFONTENCODING_SYSTEM)
Reads a wxString from a non-unicode file. File must be open. File is closed automatically.
Definition: globals.cpp:697
int Replace(wxString *text, const wxString &replacement, size_t maxMatches=0) const
virtual const wxString & GetFilename() const
Get the editor&#39;s filename (if applicable).
Definition: editorbase.h:45
Represents a Code::Blocks project.
Definition: cbproject.h:96
int GetEOLMode() const
Retrieve the current end of line mode - one of wxSCI_EOL_CRLF, wxSCI_EOL_CR, or wxSCI_EOL_LF.
EditorBase * GetActiveEditor()
#define wxSCI_FIND_MATCHCASE
Definition: wxscintilla.h:258
EVTIMPORT const wxEventType cbEVT_ADD_LOG_WINDOW
Definition: sdk_events.cpp:162
null_pointer_t nullptr
Definition: nullptr.cpp:16
cbStyledTextCtrl * GetControl() const
Returns a pointer to the underlying cbStyledTextCtrl object (which itself is the wxWindows implementa...
Definition: cbeditor.cpp:842
void FocusEntry(size_t index)
virtual const wxString & GetTitle() const
Read the target&#39;s title.
#define wxPD_AUTO_HIDE
static wxString GetSystemEncodingName()
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
cbEditor * GetBuiltinActiveEditor()
Definition: editormanager.h:95
const wxPoint wxDefaultPosition
void SetChangeCollection(bool collectChange)
Choose between collecting actions into the changes history and discarding them.
bool IsSameAs(const wxString &s, bool caseSensitive=true) const
static bool IsBatchBuild()
Definition: manager.h:66
bool GetMatch(size_t *start, size_t *len, size_t index=0) const
int FindText(int minPos, int maxPos, const wxString &text, int flags=0, int *findEnd=NULL)
Find some text in the document.
#define wxPD_APP_MODAL
Base class that all "editors" should inherit from.
Definition: editorbase.h:30
void ConvertEOLs(int newmode)
int GetCurrentPos() const
Returns the position of the caret.
EVTIMPORT const wxEventType cbEVT_SWITCH_TO_LOG_WINDOW
Definition: sdk_events.cpp:165
wxString & Truncate(size_t len)
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
int SearchInSelectionEnd
keep track of the end of a &#39;search&#39; selection
int GetLength() const
Returns the number of bytes in the document.
void CalculateFindReplaceStartEnd(cbStyledTextCtrl *control, cbFindReplaceData *data, bool replace=false)
bool IsOpened() const
wxString GetWxStr() const
int Find(cbStyledTextCtrl *control, cbFindReplaceData *data)
int SearchInSelectionStart
keep track of the start of a &#39;search&#39; selection
virtual int ShowModal()
void CalcPosition(cbStyledTextCtrl *ed)
wxString GetTextRange(int startPos, int endPos)
Retrieve a range of text.
virtual bool GetStartWord() const =0
virtual bool GetDeleteOldSearches() const =0
wxString wxEmptyString
bool startFile
To be implemented.
#define wxOK
virtual bool GetMatchCase() const =0
cbEditor * Open(const wxString &filename, int pos=0, ProjectFile *data=nullptr)
const wxString & _(const wxString &string)
wxString & Trim(bool fromRight=true)
int GetSelectionEnd() const
Returns the position at the end of the selection.
cbEditor * GetBuiltinEditor(EditorBase *eb)
virtual bool GetRecursive() const =0
wxArray< int > wxArrayInt
static wxString GetDataFolder(bool global=true)
ProjectBuildTarget * GetBuildTarget(int index)
Access a build target.
Definition: cbproject.cpp:1392
virtual bool GetRegEx() const =0
bool GetReadOnly() const
In read-only mode?
virtual bool GetMultiLine() const =0
A file editor.
Definition: cbeditor.h:43
bool IsEmpty() const
DLLIMPORT void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode=pdlBest, bool enforce=false)
Definition: globals.cpp:1177
size_type size() const
void EndUndoAction()
End a sequence of actions that is undone and redone as a unit.
#define wxSCI_FIND_POSIX
Definition: wxscintilla.h:261
wxString Upper() const
cbAuiNotebook * GetNotebook()
Definition: editormanager.h:73
size_t Len() const
void GotoPos(int caret)
Set caret to a position and ensure it is visible.
bool NewSearch
only true when a new search has been started
bool ProcessEvent(CodeBlocksEvent &event)
Definition: manager.cpp:246
int ShowModal() override
void SetSearchResultLogger(cbSearchResultsLog *log)
Sets the pointer to the search result logger, users must not call this method.
Definition: manager.h:163
void SetSCIFocus(bool focus)
Change internal focus flag.
size_t Add(const wxString &str, size_t copies=1)
int FindNext(bool goingDown, cbStyledTextCtrl *control, cbFindReplaceData *data, bool selected)
void SetTargetStart(int start)
Sets the position that starts the target which is used for updating the document without affecting th...
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
#define wxSCI_EOL_CRLF
Definition: wxscintilla.h:83
int LineFromPosition(int pos) const
Retrieve the line containing a position.
void Sort(bool reverseOrder=false)
bool Compile(const wxString &pattern, int flags=wxRE_DEFAULT)
wxString GetText() const
Retrieve all the text in the document.
size_t GetCount() const
int LinesOnScreen() const
Retrieves the number of lines completely visible.
int Find(wxUniChar ch, bool fromEnd=false) const
void SetTargetEnd(int end)
Sets the position that ends the target which is used for updating the document without affecting the ...
ProjectsArray * GetProjects()
Retrieve an array of all the opened projects.
int ReplaceTargetRE(const wxString &text)
Replace the target text with the argument text after \d processing.
virtual wxString GetFindString() const =0
int FindInFiles(cbFindReplaceData *data)
virtual bool GetMatchWord() const =0
virtual wxString GetSearchPath() const =0
void BeginUndoAction()
Start a sequence of actions that is undone and redone as a unit.
int Printf(const wxString &pszFormat,...)
void LogSearch(const wxString &file, int line, const wxString &lineText)
EditorBase * IsOpen(const wxString &filename)
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
#define NULL
Definition: prefix.cpp:59
wxArtID wxART_INFORMATION
wxString Mid(size_t first, size_t nCount=wxString::npos) const
virtual int GetProject() const =0
void GotoLine(int line)
Set caret to start of a line and ensure it is visible.
Dialog that contains a "Don&#39;t annoy me" checkbox.
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395
void SetSelectionStart(int anchor)
Sets the position that starts the selection - this becomes the anchor.
int eolMode
for multi-line S&R
void ConvertEOLs(int eolMode)
Convert all line endings in the document to one mode.
EVTIMPORT const wxEventType cbEVT_SHOW_LOG_MANAGER
Definition: sdk_events.cpp:167
wxArrayString buildTargets
An array of strings, containing the names of all the build targets this file belongs to...
Definition: projectfile.h:190
virtual bool GetStartFile() const =0
int FindSelectedText(bool goingDown)
#define wxSCI_FIND_WORDSTART
Definition: wxscintilla.h:259
cbFindReplaceData * m_LastFindReplaceData
Definition: find_replace.h:31