Code::Blocks  SVN r11506
editormanager.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 11457 $
6  * $Id: editormanager.cpp 11457 2018-09-06 10:44:12Z fuscated $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/editormanager.cpp $
8  */
9 
10 #include "sdk_precomp.h"
11 
12 #ifndef CB_PRECOMP
13  #include <wx/dir.h>
14  #include <wx/menu.h>
15  #include <wx/notebook.h>
16  #include <wx/settings.h>
17  #include <wx/splitter.h>
18  #include <wx/xrc/xmlres.h>
19 
20  #include "cbeditor.h"
21  #include "cbproject.h"
22  #include "compiler.h"
23  #include "compilerfactory.h"
24  #include "configmanager.h"
25  #include "editormanager.h" // class's header file
26  #include "filemanager.h"
27  #include "logmanager.h"
28  #include "macrosmanager.h"
29  #include "manager.h"
30  #include "pluginmanager.h"
31  #include "projectbuildtarget.h"
32  #include "projectmanager.h"
33  #include "sdk_events.h"
34 #endif
35 
36 #include "annoyingdialog.h"
37 #include "cbstyledtextctrl.h"
38 #include "cbcolourmanager.h"
39 
40 #include <wx/bmpbuttn.h>
41 #include <wx/progdlg.h>
42 #include <wx/tokenzr.h>
43 
44 #include "cbauibook.h"
45 #include "editorcolourset.h"
46 #include "confirmreplacedlg.h"
47 #include "filefilters.h"
48 #include "projectfileoptionsdlg.h"
49 #include "filegroupsandmasks.h"
50 
51 template<> EditorManager* Mgr<EditorManager>::instance = nullptr;
52 template<> bool Mgr<EditorManager>::isShutdown = false;
53 
57 
58 // static
60 
61 // needed for initialization of variables
62 inline int cbRegisterId(int id)
63 {
64  wxRegisterId(id);
65  return id;
66 }
67 
68 static const int idNBTabSplitHorz = wxNewId();
69 static const int idNBTabSplitVert = wxNewId();
70 static const int idNBTabUnsplit = wxNewId();
71 static const int idNBTabClose = wxNewId();
72 static const int idNBTabCloseAll = wxNewId();
73 static const int idNBTabCloseAllOthers = wxNewId();
74 static const int idNBTabCloseToTheLeft = wxNewId();
75 static const int idNBTabCloseToTheRight = wxNewId();
76 static const int idNBTabSave = wxNewId();
77 static const int idNBTabSaveAll = wxNewId();
78 static const int idNBSwapHeaderSource = wxNewId();
79 static const int idNBTabOpenContainingFolder = wxNewId();
80 static const int idNBTabTop = wxNewId();
81 static const int idNBTabBottom = wxNewId();
82 static const int idNBProperties = wxNewId();
83 static const int idNBAddFileToProject = wxNewId();
84 static const int idNBRemoveFileFromProject = wxNewId();
85 static const int idNBShowFileInTree = wxNewId();
86 
87 // The following lines reserve 255 consecutive id's
88 static const int EditorMaxSwitchTo = 255;
89 static const int idNBSwitchFile1 = wxNewId();
91 
92 
100 {
101  /* Methods */
102 
104  : m_pOwner(owner)
105  {}
106 
107  /* Static data */
108 
111 };
112 
113 // *********** End of EditorManagerInternalData **********
114 
115 
116 BEGIN_EVENT_TABLE(EditorManager, wxEvtHandler)
119  EVT_AUINOTEBOOK_PAGE_CHANGED(ID_NBEditorManager, EditorManager::OnPageChanged)
120  EVT_AUINOTEBOOK_PAGE_CHANGING(ID_NBEditorManager, EditorManager::OnPageChanging)
121  EVT_AUINOTEBOOK_PAGE_CLOSE(ID_NBEditorManager, EditorManager::OnPageClose)
122  EVT_AUINOTEBOOK_TAB_RIGHT_UP(ID_NBEditorManager, EditorManager::OnPageContextMenu)
143 END_EVENT_TABLE()
144 
146  : m_pNotebook(nullptr),
147  m_pNotebookStackHead(new cbNotebookStack),
148  m_pNotebookStackTail(m_pNotebookStackHead),
149  m_nNotebookStackSize(0),
150  m_isCheckingForExternallyModifiedFiles(false)
151 {
152  m_pData = new EditorManagerInternalData(this);
153 
154  m_pNotebook = new cbAuiNotebook(Manager::Get()->GetAppWindow(), ID_NBEditorManager, wxDefaultPosition, wxDefaultSize,
155  wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_WINDOWLIST_BUTTON | wxNO_FULL_REPAINT_ON_RESIZE | wxCLIP_CHILDREN);
156 
157  if (Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/editor_tabs_bottom"), false))
158  m_pNotebook->SetWindowStyleFlag(m_pNotebook->GetWindowStyleFlag() | wxAUI_NB_BOTTOM);
159 
160  Manager::Get()->GetLogManager()->DebugLog(_T("Initialize EditColourSet ....."));
161  m_Theme = new EditorColourSet(Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/colour_sets/active_colour_set"), COLORSET_DEFAULT));
162  Manager::Get()->GetLogManager()->DebugLog(_T("Initialize EditColourSet: done."));
163 
164  Manager::Get()->GetAppWindow()->PushEventHandler(this);
165 
166  m_Zoom = Manager::Get()->GetConfigManager(_T("editor"))->ReadInt(_T("/zoom"));
170 
172  colours->RegisterColour(_("Editor"), _("Caret"), wxT("editor_caret"), *wxBLACK);
173  colours->RegisterColour(_("Editor"), _("Right margin"), wxT("editor_gutter"), *wxLIGHT_GREY);
174  colours->RegisterColour(_("Editor"), _("Line numbers foreground colour"), wxT("editor_linenumbers_fg"),
176  colours->RegisterColour(_("Editor"), _("Line numbers background colour"), wxT("editor_linenumbers_bg"),
178 
179  // These two are taken from Platform::Chrome() and Platform::ChromeHightlight()
180  colours->RegisterColour(_("Editor"), _("Margin chrome colour"), wxT("editor_margin_chrome"),
182  colours->RegisterColour(_("Editor"), _("Margin chrome highlight colour"), wxT("editor_margin_chrome_highlight"),
184  colours->RegisterColour(_("Editor"), _("Whitespace"), wxT("editor_whitespace"), wxColor(195, 195, 195));
185 }
186 
188 {
189  DeleteNotebookStack();
190  delete m_pNotebookStackHead;
191  delete m_Theme;
192  delete m_pData;
193  Manager::Get()->GetConfigManager(_T("editor"))->Write(_T("/zoom"), m_Zoom);
194 }
195 
197 {
198  bool found = false;
199  wxWindow* wnd;
200  cbNotebookStack* body;
201  cbNotebookStack* prev_body;
202 
203  while (m_nNotebookStackSize != m_pNotebook->GetPageCount()) // Sync stack with Notebook
204  {
205  if (m_nNotebookStackSize < m_pNotebook->GetPageCount())
206  {
207  for (size_t i = 0; i<m_pNotebook->GetPageCount(); ++i)
208  {
209  wnd = m_pNotebook->GetPage(i);
210  found = false;
211  for (body = m_pNotebookStackHead->next; body != NULL; body = body->next)
212  {
213  if (wnd == body->window)
214  {
215  found = true;
216  break;
217  }
218  }
219  if (!found)
220  {
221  m_pNotebookStackTail->next = new cbNotebookStack(wnd);
222  m_pNotebookStackTail = m_pNotebookStackTail->next;
223  ++m_nNotebookStackSize;
224  }
225  }
226  }
227  if (m_nNotebookStackSize > m_pNotebook->GetPageCount())
228  {
229  for (prev_body = m_pNotebookStackHead, body = prev_body->next; body != NULL; prev_body = body, body = body->next)
230  {
231  if (m_pNotebook->GetPageIndex(body->window) == wxNOT_FOUND)
232  {
233  prev_body->next = body->next;
234  delete body;
235  --m_nNotebookStackSize;
236  body = prev_body;
237  }
238  }
239  }
240  }
241 
242  return m_pNotebookStackHead->next;
243 }
244 
246 {
247  cbNotebookStack* tmp;
248  while(m_pNotebookStackHead->next)
249  {
250  tmp = m_pNotebookStackHead->next;
251  m_pNotebookStackHead->next = tmp->next;
252  delete tmp;
253  }
254  m_pNotebookStackTail = m_pNotebookStackHead;
255  m_nNotebookStackSize = 0;
256 }
257 
259 {
260  DeleteNotebookStack();
261  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
262  {
263  m_pNotebookStackTail->next = new cbNotebookStack(m_pNotebook->GetPage(i));
264  m_pNotebookStackTail = m_pNotebookStackTail->next;
265  ++m_nNotebookStackSize;
266  }
267 }
268 
270 {
271  // tell all open editors to re-create their styles
272  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
273  {
274  cbEditor* ed = InternalGetBuiltinEditor(i);
275  if (ed)
276  {
277  bool saveSuccess = ed->SaveFoldState(); //First Save the old fold levels
278  ed->SetEditorStyle();
279  if (saveSuccess)
280  {
281  ed->FixFoldState(); //Compare old fold levels with new and change the bugs
282  }
283  }
284  }
285 }
286 
288 {
289  return m_pNotebook->GetPageCount();
290 }
291 
293 {
294  if (page >= 0 && page < (int)m_pNotebook->GetPageCount())
295  {
296  return static_cast<EditorBase*>(m_pNotebook->GetPage(page));
297  }
298  return nullptr;
299 }
300 
302 {
303  EditorBase* eb = InternalGetEditorBase(page);
304  if (eb && eb->IsBuiltinEditor())
305  return (cbEditor*)eb;
306  return nullptr;
307 }
308 
310 {
311  return eb && eb->IsBuiltinEditor() ? (cbEditor*)eb : nullptr;
312 }
313 
315 {
316  wxString uFilename = UnixFilename(realpath(filename));
317  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
318  {
319  EditorBase* eb = InternalGetEditorBase(i);
320  if (!eb)
321  continue;
322  wxString fname = eb->GetFilename();
323 
324  // MSW must use case-insensitive comparison
325  if (fname.IsSameAs(uFilename, platform::windows == false) || fname.IsSameAs(g_EditorModified + uFilename, platform::windows == false))
326  return eb;
327  }
328 
329  return NULL;
330 }
331 
333 {
334  return InternalGetEditorBase(index);
335 }
336 
338 {
339  if (m_Theme)
340  delete m_Theme;
341 
342  // copy locally
343  m_Theme = new EditorColourSet(*theme);
344 
345  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
346  {
347  cbEditor* ed = InternalGetBuiltinEditor(i);
348  if (ed)
349  ed->SetColourSet(m_Theme);
350  }
351 }
352 
353 cbEditor* EditorManager::Open(const wxString& filename, int pos, ProjectFile* data)
354 {
355  return Open(nullptr, filename, pos, data);
356 }
357 
358 cbEditor* EditorManager::Open(LoaderBase* fileLdr, const wxString& filename, int /*pos*/, ProjectFile* data)
359 {
360  bool can_updateui = !GetActiveEditor() || !Manager::Get()->GetProjectManager()->IsLoading();
361  wxFileName fn(realpath(filename));
363  wxString fname = UnixFilename(fn.GetFullPath());
364  // Manager::Get()->GetLogManager()->DebugLog("Trying to open '%s'", fname.c_str());
365  if (!wxFileExists(fname))
366  return nullptr;
367  // Manager::Get()->GetLogManager()->DebugLog("File exists '%s'", fname.c_str());
368 
369  // disallow application shutdown while opening files
370  // WARNING: remember to set it to true, when exiting this function!!!
371  s_CanShutdown = false;
372 
373  EditorBase* eb = IsOpen(fname);
374  cbEditor* ed = nullptr;
375  if (eb)
376  {
377  if (eb->IsBuiltinEditor())
378  {
379  ed = (cbEditor*)eb;
380  }
381  else
382  {
383  s_CanShutdown = true;
384  return nullptr; // is open but not a builtin editor
385  }
386  }
387 
388  if (!ed)
389  {
390  if (!fileLdr)
391  fileLdr = Manager::Get()->GetFileManager()->Load(filename);
392  if (fileLdr)
393  {
394  ed = new cbEditor(m_pNotebook, fileLdr, fname, m_Theme);
395  if (ed->IsOK())
396  AddEditorBase(ed);
397  else
398  {
399  ed->Destroy();
400  ed = nullptr;
401  }
402  }
403  }
404 
405  // check for ProjectFile
406  if (ed && !ed->GetProjectFile())
407  {
408  // First checks if we're already being passed a ProjectFile as a parameter
409  if (data)
410  Manager::Get()->GetLogManager()->DebugLog(_T("Project data set for ") + data->file.GetFullPath());
411  else
412  Manager::Get()->GetProjectManager()->FindProjectForFile(ed->GetFilename(), &data, false, false);
413  if (data)
414  ed->SetProjectFile(data,true);
415  }
416 
417  if (can_updateui)
418  {
419  if (ed)
420  {
421  SetActiveEditor(ed); // fires the cbEVT_EDITOR_ACTIVATED event
422  ed->GetControl()->SetFocus();
423  }
424  }
425 
426  // we 're done
427  s_CanShutdown = true;
428 
429  return ed;
430 }
431 
433 {
434  if (m_pNotebook->GetPageCount() > 0)
435  {
436  return InternalGetEditorBase(m_pNotebook->GetSelection());
437  }
438  return nullptr;
439 }
440 
442 {
443  m_pNotebook->AdvanceSelection(true);
444 }
445 
447 {
448  m_pNotebook->AdvanceSelection(false);
449 }
450 
452 {
453  if (!ed)
454  return;
455  int page = FindPageFromEditor(ed);
456  if (page != -1)
457  {
458  // Previously the Activated event was only sent for built-in editors, which makes no sense
459  int sel = m_pNotebook->GetSelection();
460  m_pNotebook->SetSelection(page);
461  EditorBase* eb_old = nullptr;
462  if (sel>=0)
463  eb_old = static_cast<EditorBase*>(m_pNotebook->GetPage(sel));
464 
465  CodeBlocksEvent evt(cbEVT_EDITOR_SWITCHED, -1, nullptr, ed, nullptr, eb_old);
467 
468  CodeBlocksEvent evt2(cbEVT_EDITOR_ACTIVATED, -1, nullptr, ed);
470  }
471 
472  if (ed->IsBuiltinEditor())
473  static_cast<cbEditor*>(ed)->GetControl()->SetFocus();
474 }
475 
477 {
478 // wxString old_title = Manager::Get()->GetAppWindow()->GetTitle(); // Fix for Bug #1389450
479  // create a dummy file
480  if (!newFileName.IsEmpty() && !wxFileExists(newFileName) && wxDirExists(wxPathOnly(newFileName)))
481  {
482  wxFile f(newFileName, wxFile::write);
483  if (!f.IsOpened())
484  return nullptr;
485  }
486  cbEditor* ed = new cbEditor(m_pNotebook, newFileName, m_Theme);
487 // if ((newFileName.IsEmpty() && !ed->SaveAs()) || !ed->Save())
488 // {
489 // //DeletePage(ed->GetPageIndex());
490 // ed->Destroy();
491 // Manager::Get()->GetAppWindow()->SetTitle(old_title); // Though I can't reproduce the bug, this does no harm
492 // return 0;
493 // }
494 
495  // add default text
496  wxString key;
497  key.Printf(_T("/default_code/set%d"), (int)FileTypeOf(ed->GetFilename()));
498  wxString code = Manager::Get()->GetConfigManager(_T("editor"))->Read(key, wxEmptyString);
499  // Allow usage of macros
500  // TODO (Morten#5#): Is it worth making this configurable?!
502  ed->GetControl()->SetText(code);
503 
504  ed->SetColourSet(m_Theme);
505  AddEditorBase(ed);
506 
507  ed->Show(true);
508  SetActiveEditor(ed);
509 
510  CodeBlocksEvent evt(cbEVT_EDITOR_OPEN, -1, nullptr, ed);
512 
513  return ed;
514 }
515 
517 {
518  AddEditorBase(eb);
519 }
520 
522 {
523  RemoveEditorBase(eb, false);
524 }
525 
527 {
528  int page = FindPageFromEditor(eb);
529  if (page == -1)
530  {
531  // use fullname as default, so tabs stay as small as possible
532  wxFileName fn(eb->GetTitle());
533  m_pNotebook->AddPage(eb, fn.GetFullName(), true);
534  }
535 }
536 
537 void EditorManager::RemoveEditorBase(EditorBase* eb, cb_unused bool deleteObject)
538 {
539  int page = FindPageFromEditor(eb);
540  if (page != -1 && !Manager::IsAppShuttingDown())
541  m_pNotebook->RemovePage(page);
542 
543  // if (deleteObject)
544  // eb->Destroy();
545 }
546 
548 {
549  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
550  {
551  cbEditor* ed = InternalGetBuiltinEditor(i);
552  if (!ed)
553  continue;
554  ProjectFile* pf = ed->GetProjectFile();
555  if (!pf)
556  continue;
557  if (pf->GetParentProject() != project)
558  continue;
559 
560  pf->editorTabPos = m_pNotebook->GetTabPositionFromIndex(i) + 1;
561 
562  ed->UpdateProjectFile();
563  }
564  return true;
565 }
566 
567 bool EditorManager::CloseAll(bool dontsave)
568 {
569  EditorBase *startPage = GetEditor(_("Start here"));
570  std::vector<EditorBase*> editors;
571  editors.reserve(m_pNotebook->GetPageCount());
572  for (size_t ii = 0; ii < m_pNotebook->GetPageCount(); ++ii)
573  {
574  EditorBase *eb = static_cast<EditorBase*>(m_pNotebook->GetPage(ii));
575  if (startPage != eb)
576  editors.push_back(eb);
577  }
578  return CloseEditors(editors, dontsave);
579 }
580 
582 {
583  for (int i = m_pNotebook->GetPageCount() - 1; i >= 0; --i)
584  {
585  EditorBase* eb = InternalGetEditorBase(i);
586  if (eb && !QueryClose(eb))
587  return false; // aborted
588  }
589  return true;
590 }
591 
592 bool EditorManager::CloseAllExcept(EditorBase* editor, bool dontsave)
593 {
594  std::vector<EditorBase*> editors;
595  editors.reserve(m_pNotebook->GetPageCount());
596  for (size_t ii = 0; ii < m_pNotebook->GetPageCount(); ++ii)
597  editors.push_back(InternalGetEditorBase(ii));
598 
599  editors.erase(std::remove(editors.begin(), editors.end(), editor), editors.end());
600 
601  return CloseEditors(editors, dontsave);
602 }
603 
605 {
606  std::vector<EditorBase*> editors;
607  GetEditorsInTabCtrl(editors, GetActiveEditor());
608 
609  return CloseEditors(editors, dontsave);
610 }
611 
613 {
614  std::vector<EditorBase*> editors;
615  GetEditorsInTabCtrl(editors, editor);
616 
617  editors.erase(std::remove(editors.begin(), editors.end(), editor), editors.end());
618 
619  return CloseEditors(editors, dontsave);
620 }
621 
623 {
624  std::vector<EditorBase*> editors;
625  GetEditorsInTabCtrl(editors, editor);
626 
627  for (auto it = editors.begin(); it != editors.end(); ++it)
628  {
629  if (*it == editor)
630  {
631  // We want to remove editors we want to preserve opened.
632  editors.erase(it, editors.end());
633  break;
634  }
635  }
636 
637  return CloseEditors(editors, dontsave);
638 }
639 
641 {
642  std::vector<EditorBase*> editors;
643  GetEditorsInTabCtrl(editors, editor);
644 
645  for (auto it = editors.begin(); it != editors.end(); ++it)
646  {
647  if (*it == editor)
648  {
649  // We want to remove editors we want to preserve opened.
650  editors.erase(editors.begin(), it + 1);
651  break;
652  }
653  }
654 
655  return CloseEditors(editors, dontsave);
656 }
657 
658 void EditorManager::GetEditorsInTabCtrl(std::vector<EditorBase*> &editors, EditorBase *editor)
659 {
660  std::vector<wxWindow*> windows;
661  m_pNotebook->GetPagesInTabCtrl(windows, editor);
662  if (!windows.empty())
663  {
664  editors.reserve(windows.size());
665  for (std::vector<wxWindow*>::const_iterator it = windows.begin(); it != windows.end(); ++it)
666  editors.push_back(static_cast<EditorBase*>(*it));
667  }
668 }
669 
670 bool EditorManager::CloseEditors(const std::vector<EditorBase*> &editors, bool dontsave)
671 {
672  if (!dontsave)
673  {
674  for (std::vector<EditorBase*>::const_iterator it = editors.begin(); it != editors.end(); ++it)
675  {
676  EditorBase* eb = *it;
677  if (eb && !QueryClose(eb))
678  return false; // aborted
679  }
680  }
681 
682  m_pNotebook->Freeze();
683  int count = editors.size();
684  for (std::vector<EditorBase*>::const_reverse_iterator it = editors.rbegin(); it != editors.rend(); ++it)
685  {
686  EditorBase* eb = *it;
687  if (eb && Close(eb, true))
688  --count;
689  }
690  m_pNotebook->Thaw();
691  return (count == 0);
692 }
693 
694 bool EditorManager::CloseActive(bool dontsave)
695 {
696  return Close(GetActiveEditor(), dontsave);
697 }
698 
700 {
701  if (!ed)
702  return true;
703 
704  return ed->QueryClose();
705 }
706 
708 {
709  if (!m_pNotebook || !eb)
710  return -1;
711 
712  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
713  {
714  if (m_pNotebook->GetPage(i) == eb)
715  return i;
716  }
717  return -1;
718 }
719 
720 bool EditorManager::Close(const wxString& filename, bool dontsave)
721 {
722  return Close(IsOpen(filename), dontsave);
723 }
724 
725 bool EditorManager::Close(EditorBase* editor, bool dontsave)
726 {
727  if (editor)
728  {
729  int idx = FindPageFromEditor(editor);
730  if (idx != -1)
731  {
732  if (!dontsave)
733  if (!QueryClose(editor))
734  return false;
735  m_pNotebook->DeletePage(idx);
736  }
737  }
738  return true;
739 }
740 
741 bool EditorManager::Close(int index, bool dontsave)
742 {
743  EditorBase* ed = InternalGetEditorBase(index);
744  if (ed)
745  return Close(ed, dontsave);
746  return false;
747 }
748 
749 bool EditorManager::Save(const wxString& filename)
750 {
751  EditorBase* ed = IsOpen(filename);
752  if (ed)
753  {
754  if (!ed->Save())
755  return false;
756  return true;
757  }
758  return true;
759 }
760 
761 bool EditorManager::Save(int index)
762 {
763  EditorBase* ed = InternalGetEditorBase(index);
764  if (ed)
765  {
766  if (!ed->Save())
767  return false;
768  return true;
769  }
770  return false;
771 }
772 
774 {
775  EditorBase* ed = GetActiveEditor();
776  if (ed)
777  {
778  if (!ed->Save())
779  return false;
780  return true;
781  }
782  return true;
783 }
784 
785 bool EditorManager::SaveAs(int index)
786 {
787  EditorBase* eb = InternalGetEditorBase(index);
788  if (!eb)
789  return false;
790  return eb->SaveAs();
791 }
792 
794 {
795  EditorBase* eb = GetActiveEditor();
796  if (eb)
797  {
798  return eb->SaveAs();
799  }
800  return true;
801 }
802 
804 {
805  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
806  {
807  EditorBase* ed = InternalGetEditorBase(i);
808  if (ed && ed->GetModified() && !ed->Save())
809  {
810  wxString msg;
811  msg.Printf(_("File %s could not be saved..."), ed->GetFilename().c_str());
812  cbMessageBox(msg, _("Error saving file"), wxICON_ERROR);
813  }
814  }
815 
816  return true;
817 }
818 
819 void EditorManager::Print(PrintScope ps, PrintColourMode pcm, bool line_numbers)
820 {
821  switch (ps)
822  {
823  case psAllOpenEditors:
824  {
825  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
826  {
827  cbEditor* ed = InternalGetBuiltinEditor(i);
828  if (ed)
829  ed->Print(false, pcm, line_numbers);
830  }
831  break;
832  }
833  case psActiveEditor: // fall through
834  case psSelection: // fall through
835  default:
836  {
837  cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
838  if (ed)
839  ed->Print(ps == psSelection, pcm, line_numbers);
840  break;
841  }
842  }
843 }
844 
846 {
847  if (m_isCheckingForExternallyModifiedFiles) // for some reason, a mutex locker does not work???
848  return;
849  m_isCheckingForExternallyModifiedFiles = true;
850 
851  bool reloadAll = false; // flag to stop bugging the user
852  wxArrayString failedFiles; // list of files failed to reload
853  for (size_t i = 0; i < m_pNotebook->GetPageCount(); ++i)
854  {
855  cbEditor* ed = InternalGetBuiltinEditor(i);
856  bool b_modified = false;
857 
858  // no builtin editor or new file not yet saved
859  if (!ed)
860  {
861  EditorBase* eb = InternalGetEditorBase(i);
862  if (eb)
863  {
864  ProjectFile* pf = nullptr;
865 
866  wxFileName fn(eb->GetFilename());
867  fn.MakeAbsolute();
868  Manager::Get()->GetProjectManager()->FindProjectForFile(fn.GetFullPath(), &pf, false, false);
869 
870  bool readOnly = eb->IsReadOnly() || (fn.FileExists() && !wxFile::Access(fn.GetFullPath(), wxFile::write));
871  MarkReadOnly(i, readOnly);
872 
873  if (pf)
874  {
875  if (!fn.FileExists()) // file was deleted ?
876  {
877  if (pf->GetFileState() != fvsMissing) // already asked
878  {
879  // Find the window, that actually has the mouse-focus and force a release
880  // prevents crash on windows or hang on wxGTK
881  wxWindow* win = wxWindow::GetCapture();
882  if (win)
883  win->ReleaseMouse();
884 
885  wxString msg;
886  msg.Printf(_("%s has been deleted, or is no longer available.\n"
887  "Do you wish to try to save the file to disk?\n"
888  "If you close it, it will most likely be lost !\n"
889  "If you cancel this dialog, you have to take care yourself !\n"
890  "Yes: save the file, No: close it, Cancel: keep your fingers crossed."), eb->GetFilename().c_str());
891  int ret = cbMessageBox(msg, _("File changed!"), wxICON_QUESTION | wxYES_NO | wxCANCEL );
892  switch (ret)
893  {
894  case wxID_YES:
895  {
896  eb->Save();
897  break;
898  }
899  case wxID_NO:
900  {
902  eb->Close();
903  break;
904  }
905  case wxID_CANCEL: // fall through
906  default:
907  eb->SetModified(true); // some editors might implement it
909  break;
910  }
911  }
912  }
913  else
914  pf->SetFileState(readOnly?fvsReadOnly:fvsNormal);
915  }
916  continue;
917  }
918  }
919  if (!ed->IsOK())
920  continue;
921 
922  ProjectFile* pf = ed->GetProjectFile();
923  if (pf)
924  {
925  cbProject* prj = pf->GetParentProject();
926  if (prj && !prj->GetCheckForExternallyModifiedFiles())
927  continue;
928  }
929 
930  // File was deleted?
931  if (!wxFileExists(ed->GetFilename()))
932  {
933  if (ed->GetModified()) // Already set the flag
934  continue;
935 
936  // Find the window, that actually has the mouse-focus and force a release
937  // prevents crash on windows or hang on wxGTK
938  wxWindow* win = wxWindow::GetCapture();
939  if (win)
940  win->ReleaseMouse();
941 
942  wxString msg;
943  msg.Printf(_("%s has been deleted, or is no longer available.\n"
944  "Do you wish to keep the file open?\n"
945  "Yes to keep the file, No to close it."), ed->GetFilename().c_str());
946  if (cbMessageBox(msg, _("File changed!"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
947  ed->SetModified(true);
948  else
949  {
950  if (pf)
952  ed->Close();
953  }
954  continue;
955  }
956 
957  wxFileName fname(ed->GetFilename());
958  wxDateTime last = fname.GetModificationTime();
959 
960  //File changed from RO -> RW?
961  if (ed->GetControl()->GetReadOnly() &&
963  {
964  b_modified = false;
965  ed->SetReadOnly(false);
966  MarkReadOnly(i, false);
967  if (pf)
968  pf->SetFileState(fvsNormal);
969  }
970  //File changed from RW -> RO?
971  if (!ed->GetControl()->GetReadOnly() &&
973  {
974  b_modified = false;
975  ed->SetReadOnly(true);
976  MarkReadOnly(i);
977  if (pf)
979  }
980  //File content changed?
981  if (last.IsLaterThan(ed->GetLastModificationTime()))
982  b_modified = true;
983 
984  if (b_modified)
985  {
986  // modified; ask to reload
987  int ret = -1;
988  if (!reloadAll)
989  {
990  wxString msg;
991  msg.Printf(_("File %s is modified outside the IDE...\nDo you want to reload it (you will lose any unsaved work)?"),
992  ed->GetFilename().c_str());
993  ConfirmReplaceDlg dlg(Manager::Get()->GetAppWindow(), false, msg);
994  dlg.SetTitle(_("Reload file?"));
995  dlg.GetSizer()->SetSizeHints(&dlg);
996  PlaceWindow(&dlg);
997 
998  // Find the window, that actually has the mouse-focus and force a release
999  // prevents crash on windows or hang on wxGTK
1000  wxWindow* win = wxWindow::GetCapture();
1001  if (win)
1002  win->ReleaseMouse();
1003 
1004  ret = dlg.ShowModal();
1005  reloadAll = ret == crAll;
1006  }
1007  if (reloadAll || ret == crYes)
1008  {
1009  if (!ed->Reload())
1010  failedFiles.Add(ed->GetFilename());
1011  }
1012  else if (ret == crCancel)
1013  break;
1014  else if (ret == crNo)
1015  ed->Touch();
1016  }
1017  }
1018 
1019  // this will emmit a EVT_EDITOR_ACTIVATED event, which in turn will notify
1020  // the app to update the currently active file's info
1021  // (we 're interested in updating read-write state)
1022  SetActiveEditor(GetActiveEditor());
1023 
1024  if (failedFiles.GetCount())
1025  {
1026  // Find the window, that actually has the mouse-focus and force a release
1027  // prevents crash on windows or hang on wxGTK
1028  wxWindow* win = wxWindow::GetCapture();
1029  if (win)
1030  win->ReleaseMouse();
1031 
1032  wxString msg;
1033  msg.Printf(_("Could not reload all files:\n\n%s"), GetStringFromArray(failedFiles, _T("\n")).c_str());
1034  cbMessageBox(msg, _("Error"), wxICON_ERROR);
1035  }
1036  m_isCheckingForExternallyModifiedFiles = false;
1037 }
1038 
1039 void EditorManager::MarkReadOnly(int page, bool readOnly)
1040 {
1041  if (page > -1)
1042  {
1043  wxBitmap bmp = readOnly ? cbLoadBitmap(ConfigManager::GetDataFolder() + _T("/images/") + _T("readonly.png")) : wxNullBitmap;
1044  if (m_pNotebook)
1045  m_pNotebook->SetPageBitmap(page, bmp);
1046  }
1047 }
1048 
1049 bool EditorManager::IsHeaderSource(const wxFileName& candidateFile, const wxFileName& activeFile, FileType ftActive, bool& isCandidate)
1050 {
1051  // Verify the base name matches
1052  if (candidateFile.GetName().CmpNoCase(activeFile.GetName()) == 0)
1053  {
1054  // matching case has priority over case-insensitive
1055  isCandidate = (candidateFile.GetName() != activeFile.GetName());
1056 
1057  // Verify:
1058  // If looking for a header we have a source OR
1059  // If looking for a source we have a header
1060  FileType ftTested = FileTypeOf(candidateFile.GetFullName());
1061  if ( ((ftActive == ftHeader) && (ftTested == ftSource))
1062  || ((ftActive == ftSource) && (ftTested == ftHeader))
1063  || ((ftActive == ftHeader) && (ftTested == ftTemplateSource))
1064  || ((ftActive == ftTemplateSource) && (ftTested == ftHeader)) )
1065  {
1066  // Handle the case where two files (in different directories) have the same name:
1067  // Example: A project file with three files dir1/file.h dir1/file.cpp dir2/file.h
1068  // If you are in dir2/file.h and you want to swap Code::Blocks will first look if there
1069  // isn't a file.h in that directory, which is in this case and would then ask the user
1070  // to create a new file.cpp in dir2
1071  if (candidateFile.GetPath() != activeFile.GetPath()) // Check if we are not in the same Directory
1072  {
1073  wxArrayString fileArray;
1074  wxDir::GetAllFiles(candidateFile.GetPath(wxPATH_GET_VOLUME), &fileArray, candidateFile.GetName() + _T(".*"), wxDIR_FILES | wxDIR_HIDDEN);
1075  for (unsigned i=0; i<fileArray.GetCount(); i++) // if in this directory there is already
1076  if (wxFileName(fileArray[i]).GetFullName() == activeFile.GetFullName()) // a header file (or source file) for our candidate
1077  return false; // file it can't be our candidate file
1078  }
1079  if (candidateFile.FileExists())
1080  return true;
1081  }
1082  }
1083  return false;
1084 }
1085 
1086 wxFileName EditorManager::FindHeaderSource(const wxArrayString& candidateFilesArray, const wxFileName& activeFile, bool& isCandidate)
1087 {
1088  FileType ftActive = FileTypeOf(activeFile.GetFullName());
1089 
1090  // Because ftActive == ftHeader || ftSource, the extension has at least 1 character
1091  bool extStartsWithCapital = wxIsupper(activeFile.GetExt()[0]);
1092 
1093  wxFileName candidateFile;
1094  for (unsigned i = 0; i < candidateFilesArray.GetCount(); ++i)
1095  {
1096  wxFileName currentCandidateFile(candidateFilesArray[i]);
1097 
1098  if (IsHeaderSource(currentCandidateFile, activeFile, ftActive, isCandidate))
1099  {
1100  bool isUpper = wxIsupper(currentCandidateFile.GetExt()[0]);
1101  if (isUpper == extStartsWithCapital && !isCandidate)
1102  {
1103  // we definitely found the header/source we were searching for
1104  return currentCandidateFile;
1105  }
1106  else
1107  {
1108  // the header/source has a different capitalization of its extension
1109  // use this if nothing better is found
1110  candidateFile = currentCandidateFile;
1111  }
1112  }
1113  }
1114 
1115  isCandidate = true;
1116 
1117  // may be invalid (empty) file name
1118  return candidateFile;
1119 }
1120 
1122 {
1125 
1126  OpenContainingFolderData() : supportSelect(false) {}
1127  OpenContainingFolderData(const wxString &command, bool select) : command(command), supportSelect(select) {}
1128 };
1129 
1130 #if !defined(__WXMSW__) && !defined(__WXMAC__)
1131 static OpenContainingFolderData detectNautilus(const wxString &command, ConfigManager* appConfig)
1135 {
1136  wxString fileManager;
1137 
1138  // If the user hasn't changed the command, try to detect nautilus using xdg-mime.
1139  if (command == cbDEFAULT_OPEN_FOLDER_CMD)
1140  {
1141  const wxString shell = appConfig->Read(_T("/console_shell"), DEFAULT_CONSOLE_SHELL);
1142  const wxString cmdGetManager = shell + wxT(" 'xdg-mime query default inode/directory'");
1143  wxArrayString output, errors;
1144  wxExecute(cmdGetManager, output, errors, wxEXEC_SYNC);
1145  if (output.empty())
1146  return OpenContainingFolderData(command, false);
1147  fileManager = output[0];
1148  }
1149  else
1150  fileManager = command;
1151 
1152  Manager::Get()->GetLogManager()->DebugLog(F(wxT("File manager is: '%s'"), fileManager.wx_str()));
1153  if (fileManager.find(wxT("nautilus")) == wxString::npos)
1154  return OpenContainingFolderData(command, false);
1155  // If the file manager ends with desktop then this is produced by xdg-mime.
1156  // This means that we could use the system nautilus (not entirely correct).
1157  if (fileManager.EndsWith(wxT(".desktop")))
1158  fileManager = wxT("nautilus");
1159 
1160  wxArrayString output, errors;
1161  wxExecute(fileManager + wxT(" --version"), output, errors, wxEXEC_SYNC);
1162  if (output.empty())
1163  return OpenContainingFolderData(command, false);
1164  // It is assumed that the output looks like GNOME nautilus 3.20.4
1165  const wxString prefix(wxT("GNOME nautilus "));
1166 
1167  const wxString firstLine = output[0].Trim(true).Trim(false);
1168  Manager::Get()->GetLogManager()->DebugLog(F(wxT("Nautilus version is: '%s'"), firstLine.wx_str()));
1169 
1170  if (firstLine.StartsWith(prefix))
1171  {
1172  wxArrayString versionTokens = wxStringTokenize(firstLine.substr(prefix.length()), wxT("."));
1173  int fullVersion = 0;
1174  int multiplier = 1;
1175  for (int ii = versionTokens.GetCount() - 1; ii >= 0; --ii)
1176  {
1177  long number;
1178  versionTokens[ii].ToLong(&number);
1179  fullVersion += number * multiplier;
1180  multiplier *= 100;
1181  }
1182  if (fullVersion >= 30002)
1183  return OpenContainingFolderData(fileManager + wxT(" --select"), true);
1184  }
1185  return OpenContainingFolderData(command, false);
1186 }
1187 #endif // !__WXMSW__ && !__WXMAC__
1188 
1190 {
1191  cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
1192  if (!ed)
1193  return false;
1194 
1195  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("app"));
1196  const wxString &command = cfg->Read(_T("open_containing_folder"), cbDEFAULT_OPEN_FOLDER_CMD);
1197 #if defined __WXMSW__ || defined __WXMAC__
1198  OpenContainingFolderData cmdData(command, true);
1199 #else
1200  OpenContainingFolderData cmdData=detectNautilus(command, cfg);
1201 #endif
1202 
1203  const wxString& fullPath = ed->GetFilename();
1204  wxString path;
1205  if (!cmdData.supportSelect)
1206  {
1207  // Cannot select the file with with most editors, so just extract the folder name
1208  wxFileName::SplitPath(fullPath, &path, nullptr, nullptr);
1209  }
1210  else
1211  path = fullPath;
1212 
1213  QuoteStringIfNeeded(path);
1214  cmdData.command << wxT(" ") << path;
1215 
1216  wxExecute(cmdData.command);
1217  Manager::Get()->GetLogManager()->DebugLog(F(wxT("Executing command to open folder: '%s'"),
1218  cmdData.command.wx_str()));
1219  return true;
1220 }
1221 
1223 {
1224  cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
1225  if (!ed)
1226  return false;
1227 
1229  if (!pm)
1230  return false;
1231 
1232  FileType ft = FileTypeOf(ed->GetFilename());
1233  if (ft != ftHeader && ft != ftSource && ft != ftTemplateSource)
1234  return false;
1235 
1236  cbProject* project = nullptr;
1237 
1238  // if the file in question belongs to a different open project,
1239  // then use that project instead.
1240  // this fixes locating the file's pair in a workspace when the active file
1241  // does not belong to the active project.
1242  ProjectFile* opf = ed->GetProjectFile();
1243  if (opf)
1244  project = opf->GetParentProject();
1245 
1246  // if we didn't get a valid project, try the active one
1247  if (!project)
1248  project = pm->GetActiveProject();
1249 
1250  wxFileName theFile(ed->GetFilename());
1251  wxFileName candidateFile;
1252  bool isCandidate;
1253  wxArrayString fileArray;
1254 
1255  // find all files with the same name as the active file, but with possibly different extension
1256  // search in the directory of the active file:
1257  wxDir::GetAllFiles(theFile.GetPath(wxPATH_GET_VOLUME), &fileArray, theFile.GetName() + _T(".*"), wxDIR_FILES | wxDIR_HIDDEN);
1258 
1259  // try to find the header/source in the list
1260  wxFileName currentCandidateFile = FindHeaderSource(fileArray, theFile, isCandidate);
1261 
1262  if (isCandidate)
1263  {
1264  candidateFile = currentCandidateFile;
1265  }
1266  else if (currentCandidateFile.IsOk())
1267  {
1268  cbEditor* newEd = Open(currentCandidateFile.GetFullPath());
1269  if (newEd!=nullptr) // we found and were able to open it
1270  return true; // --> RETURN;
1271  }
1272 
1273  // try to find the file among the opened files
1274 
1275  // build a list of opened files
1276  fileArray.Clear();
1277  for (int i = 0; i < GetEditorsCount(); ++i)
1278  {
1279  cbEditor* edit = GetBuiltinEditor(GetEditor(i));
1280  if (!edit)
1281  continue;
1282 
1283  ProjectFile* pf = edit->GetProjectFile();
1284  if (!pf)
1285  continue;
1286 
1287  fileArray.Add(pf->file.GetFullPath());
1288  }
1289 
1290  // try to find the header/source in the list
1291  currentCandidateFile = FindHeaderSource(fileArray, theFile, isCandidate);
1292 
1293  if (!isCandidate && currentCandidateFile.IsOk())
1294  {
1295  cbEditor* newEd = Open(currentCandidateFile.GetFullPath());
1296  if (newEd!=nullptr) // we found and were able to open it
1297  return true; // --> RETURN;
1298  }
1299 
1300  if (project)
1301  {
1302  // try to find in the project files
1303 
1304  // build a list of project files
1305  fileArray.Clear();
1306  for (FilesList::iterator it = project->GetFilesList().begin(); it != project->GetFilesList().end(); ++it)
1307  {
1308  ProjectFile* pf = *it;
1309  if (!pf)
1310  continue;
1311 
1312  fileArray.Add(pf->file.GetFullPath());
1313  }
1314 
1315  // try to find the header/source in the list
1316  currentCandidateFile = FindHeaderSource(fileArray, theFile, isCandidate);
1317 
1318  if (isCandidate && !candidateFile.IsOk())
1319  {
1320  candidateFile = currentCandidateFile;
1321  }
1322  else if (currentCandidateFile.IsOk())
1323  {
1324  cbEditor* newEd = Open(currentCandidateFile.GetFullPath());
1325  if (newEd!=nullptr) // we found and were able to open it
1326  return true; // --> RETURN;
1327  }
1328 
1329  // if not found, build the list of directories for further searching
1330 
1331  // get project's include dirs
1332  wxArrayString dirs = project->GetIncludeDirs();
1333 
1334  // get targets include dirs
1335  for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
1336  {
1337  ProjectBuildTarget* target = project->GetBuildTarget(i);
1338  if (target)
1339  {
1340  for (unsigned int ti = 0; ti < target->GetIncludeDirs().GetCount(); ++ti)
1341  {
1342  // TODO (Morten#5#): target include dirs might override project include dirs, take append/prepend option into account
1343  wxString dir = target->GetIncludeDirs()[ti];
1344  if (dirs.Index(dir) == wxNOT_FOUND)
1345  dirs.Add(dir);
1346  }
1347  }
1348  }
1349 
1350  // go through the directories and try to find the header/source there
1351  for (unsigned int i = 0; i < dirs.GetCount(); ++i)
1352  {
1353  wxString dir = dirs[i]; // might contain macros -> replace them
1355 
1356  wxFileName dname(dir);
1357  if (!dname.IsAbsolute())
1358  {
1359  dname.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, project->GetBasePath());
1360  // Manager::Get()->GetLogManager()->DebugLog(F(_T("Normalizing dir to '%s'."), dname.GetFullPath().c_str()));
1361  }
1362 
1363  fileArray.Clear();
1364  // find all files inside the directory with the same name as the active file, but with possibly different extension
1365  wxDir::GetAllFiles(dname.GetPath(), &fileArray, theFile.GetName() + _T(".*"), wxDIR_FILES | wxDIR_HIDDEN);
1366  // try to find the header/source in the list
1367  currentCandidateFile = FindHeaderSource(fileArray, theFile, isCandidate);
1368 
1369  if (isCandidate)
1370  {
1371  candidateFile = currentCandidateFile;
1372  }
1373  else if (currentCandidateFile.IsOk())
1374  {
1375  cbEditor* newEd = Open(currentCandidateFile.GetFullPath());
1376  if (newEd!=nullptr) // we found and were able to open it
1377  return true; // --> RETURN;
1378  }
1379  }
1380  }
1381 
1382  // candidateFile is header/source whose extension does not match the capitalization of the active file
1383  // - open it if nothing better is found
1384  if (candidateFile.IsOk())
1385  {
1386  cbEditor* newEd = Open(candidateFile.GetFullPath());
1387  if (newEd!=nullptr) // we found and were able to open it
1388  return true; // --> RETURN;
1389  }
1390 
1391  // nothing else worked, try to find source-source pairs of auto-generated files
1392  if (opf)
1393  {
1394  ProjectFile* candidatePF = opf->AutoGeneratedBy();
1395  if (!candidatePF && !opf->generatedFiles.empty())
1396  candidatePF = opf->generatedFiles.front();
1397  if (candidatePF)
1398  {
1399  cbEditor* newEd = Open(candidatePF->file.GetFullPath());
1400  if (newEd!=nullptr) // we found and were able to open it
1401  return true; // --> RETURN;
1402  }
1403  }
1404 
1405  // We couldn't find the file, maybe it does not exist. Ask the user if we
1406  // should create it:
1407  if (cbMessageBox(_("The file seems not to exist. Do you want to create it?"),
1408  _("Error"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
1409  {
1411  if (project)
1412  wxSetWorkingDirectory(project->GetBasePath());
1413 
1414  // Create a suggestion for the new file name:
1415  if (ft == ftHeader)
1416  theFile.SetExt(FileFilters::CPP_EXT);
1417  else if (ft == ftSource || ft == ftTemplateSource)
1418  theFile.SetExt(FileFilters::H_EXT);
1419  // else? Well, if the filename is not changed we could possibly
1420  // overwrite an existing file with our suggestion.
1421 
1422  cbEditor* newEd = New(theFile.GetFullPath());
1423  if (project)
1424  {
1425  if (cbMessageBox(_("Do you want to add this new file in the active project?"),
1426  _("Add file to project"),
1428  {
1429  wxArrayInt targets;
1430  if (Manager::Get()->GetProjectManager()->AddFileToProject(newEd->GetFilename(), project, targets) != 0)
1431  {
1432  ProjectFile* pf = project->GetFileByFilename(newEd->GetFilename(), false);
1433  newEd->SetProjectFile(pf);
1435  }
1436  }
1437  }
1438 
1439  // verify that the open files are still in sync
1440  // the new file might have overwritten an existing one)
1441  CheckForExternallyModifiedFiles();
1442  }
1443 
1444  return false;
1445 }
1446 
1448 {
1449  EditorBase* eb = GetActiveEditor();
1450  cbEditor* ed = GetBuiltinEditor(eb);
1451  int id = event.GetId();
1452 
1453  if (id == idNBTabSplitHorz && ed)
1455  else if (id == idNBTabSplitVert && ed)
1457  else if (id == idNBTabUnsplit && ed)
1458  ed->Unsplit();
1459  else if (id >= idNBSwitchFile1 && id <= idNBSwitchFileMax)
1460  {
1461  eb = GetEditor(id - idNBSwitchFile1);
1462  if (eb)
1463  SetActiveEditor(eb);
1464  }
1465 }
1466 
1468 {
1469  EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(event.GetSelection()));
1470  EditorBase* eb_old = nullptr;
1471  if (event.GetOldSelection()!=-1)
1472  eb_old = static_cast<EditorBase*>(m_pNotebook->GetPage(event.GetOldSelection()));
1473 
1474  CodeBlocksEvent evt(cbEVT_EDITOR_SWITCHED, -1, nullptr, eb, nullptr, eb_old);
1476 
1477  CodeBlocksEvent evt2(cbEVT_EDITOR_ACTIVATED, -1, nullptr, eb);
1479 
1480  if (Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/tabs_stacked_based_switching")))
1481  {
1482  wxWindow* wnd;
1483  cbNotebookStack* body;
1484  cbNotebookStack* tmp;
1485  wnd = m_pNotebook->GetPage(event.GetSelection());
1486  for (body = m_pNotebookStackHead; body->next != nullptr; body = body->next)
1487  {
1488  if (wnd == body->next->window)
1489  {
1490  if (m_pNotebookStackTail == body->next)
1491  m_pNotebookStackTail = body;
1492  tmp = body->next;
1493  body->next = tmp->next;
1494  tmp->next = m_pNotebookStackHead->next;
1495  m_pNotebookStackHead->next = tmp;
1496  break;
1497  }
1498  }
1499  if ( (m_pNotebookStackHead->next == nullptr)
1500  || (wnd != m_pNotebookStackHead->next->window) )
1501  {
1502  body = new cbNotebookStack(wnd);
1503  body->next = m_pNotebookStackHead->next;
1504  m_pNotebookStackHead->next = body;
1505  ++m_nNotebookStackSize;
1506  }
1507  }
1508 
1509  // focus editor on next update event
1510  m_pData->m_SetFocusFlag = true;
1511 
1512  event.Skip(); // allow others to process it too
1513 }
1514 
1516 {
1517  int old_sel = event.GetOldSelection();
1518  if (old_sel != -1 && static_cast<size_t>(old_sel) < m_pNotebook->GetPageCount())
1519  {
1520  EditorBase* eb = static_cast<EditorBase*>(m_pNotebook->GetPage(old_sel));
1521  CodeBlocksEvent evt(cbEVT_EDITOR_DEACTIVATED, -1, nullptr, eb);
1523  }
1524  event.Skip(); // allow others to process it too
1525 }
1526 
1528 {
1529  int sel = event.GetSelection();
1530  bool doClose = false;
1531  EditorBase* eb = nullptr;
1532  if (sel != -1)
1533  {
1534  // veto it in any case, so we can handle the page delete or remove ourselves
1535  event.Veto();
1536  eb = static_cast<EditorBase*>(m_pNotebook->GetPage(sel));
1537  if (QueryClose(eb))
1538  {
1539  doClose = true;
1540  if (m_pNotebook->GetPageCount()<=1)
1541  {
1542  CodeBlocksEvent evt(cbEVT_EDITOR_SWITCHED, -1, nullptr, nullptr, nullptr, eb);
1544  }
1545  }
1546  }
1547 
1548  if (Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/tabs_stacked_based_switching")))
1549  {
1550  wxWindow* wnd;
1551  cbNotebookStack* body;
1552  cbNotebookStack* tmp;
1553  wnd = m_pNotebook->GetPage(event.GetSelection());
1554  for (body = m_pNotebookStackHead; body->next != nullptr; body = body->next)
1555  {
1556  if (wnd == body->next->window)
1557  {
1558  tmp = body->next;
1559  body->next = tmp->next;
1560  delete tmp;
1561  --m_nNotebookStackSize;
1562  break;
1563  }
1564  }
1565  }
1566 
1567  if (doClose && eb != nullptr)
1568  Close(eb);
1569  else
1570  event.Skip(); // allow others to process it too
1571 }
1572 
1574 {
1575  if (event.GetSelection() == -1)
1576  return;
1577 
1578  if (wxGetKeyState(WXK_CONTROL) && GetEditorsCount() > 1)
1579  {
1580  wxMenu* pop = new wxMenu;
1581  EditorBase* current = GetActiveEditor();
1582  for (int i = 0; i < EditorMaxSwitchTo && i < GetEditorsCount(); ++i)
1583  {
1584  EditorBase* other = GetEditor(i);
1585  if (!other)
1586  continue;
1587  const wxString name = (other->GetModified() ? wxT("*") : wxEmptyString) + other->GetShortName();
1588  if (other == current)
1589  {
1590  pop->AppendCheckItem(wxID_ANY, name); // do nothing if the current tab is selected
1591  pop->FindItemByPosition(pop->GetMenuItemCount() - 1)->Check(); // and mark it as active
1592  }
1593  else
1594  pop->Append(idNBSwitchFile1 + i, name);
1595  }
1596  m_pNotebook->PopupMenu(pop);
1597  delete pop;
1598  return;
1599  }
1600 
1601  // select the notebook that sends the event, because the context menu-entries act on the actual selected tab
1602  m_pNotebook->SetSelection(event.GetSelection());
1603  wxMenu* pop = new wxMenu;
1604  pop->Append(idNBTabClose, _("Close"));
1605  pop->Append(idNBTabCloseAll, _("Close all"));
1606  pop->Append(idNBTabCloseAllOthers, _("Close all others"));
1607  pop->Append(idNBTabCloseToTheLeft, _("Close to the left"));
1608  pop->Append(idNBTabCloseToTheRight, _("Close to the right"));
1609 
1610  EditorBase *activeEditor = GetActiveEditor();
1611  wxAuiTabCtrl *activeTabCtrl = m_pNotebook->GetTabCtrl(activeEditor);
1612  if (!activeTabCtrl || activeTabCtrl->GetPageCount() <= 1)
1613  {
1614  pop->Enable(idNBTabCloseAll, false);
1615  pop->Enable(idNBTabCloseAllOthers, false);
1616  pop->Enable(idNBTabCloseToTheLeft, false);
1617  pop->Enable(idNBTabCloseToTheRight, false);
1618  }
1619  else
1620  {
1621  const int pageCount = activeTabCtrl->GetPageCount();
1622  const int tabIndex = activeTabCtrl->GetIdxFromWindow(activeEditor);
1623  if (tabIndex == 0)
1624  pop->Enable(idNBTabCloseToTheLeft, false);
1625  if (tabIndex == pageCount - 1)
1626  pop->Enable(idNBTabCloseToTheRight, false);
1627  }
1628 
1629  int any_modified = 0;
1630  for (int i = 0; i<GetEditorsCount(); ++i)
1631  {
1632  EditorBase* ed = GetEditor(i);
1633  if (ed && ed->GetModified())
1634  {
1635  if (++any_modified > 1)
1636  break; // more than one editor is modified -> enable "Save all"
1637  }
1638  }
1639 
1640  pop->AppendSeparator();
1641  pop->Append(idNBTabSave, _("Save"));
1642  pop->Append(idNBTabSaveAll, _("Save all"));
1643  pop->Enable(idNBTabSave, false);
1644  pop->Enable(idNBTabSaveAll, false);
1645 
1646  if (any_modified > 0)
1647  {
1648  if (GetEditor(event.GetSelection())->GetModified())
1649  pop->Enable(idNBTabSave, true);
1650  if (any_modified > 1 || !GetEditor(event.GetSelection())->GetModified())
1651  pop->Enable(idNBTabSaveAll, true);
1652  }
1653 
1654  pop->AppendSeparator();
1655  cbEditor* ed = GetBuiltinEditor(event.GetSelection());
1656  if (ed)
1657  {
1658  pop->Append(idNBSwapHeaderSource, _("Swap header/source"));
1659  pop->Append(idNBTabOpenContainingFolder, _("Open containing folder"));
1660  pop->AppendSeparator();
1661  }
1662 
1663  if (Manager::Get()->GetConfigManager(_T("app"))->ReadBool(_T("/environment/editor_tabs_bottom"), false))
1664  pop->Append(idNBTabTop, _("Tabs at top"));
1665  else
1666  pop->Append(idNBTabBottom, _("Tabs at bottom"));
1667 
1668  if (ed)
1669  {
1670  wxMenu* splitMenu = new wxMenu;
1671  if (ed->GetSplitType() != cbEditor::stHorizontal)
1672  splitMenu->Append(idNBTabSplitHorz, _("Horizontally (top-bottom)"));
1673  if (ed->GetSplitType() != cbEditor::stVertical)
1674  splitMenu->Append(idNBTabSplitVert, _("Vertically (left-right)"));
1675  if (ed->GetSplitType() != cbEditor::stNoSplit)
1676  {
1677  splitMenu->AppendSeparator();
1678  splitMenu->Append(idNBTabUnsplit, _("Unsplit"));
1679  }
1680  pop->Append(-1, _("Split view"), splitMenu);
1681 
1682  if (Manager::Get()->GetProjectManager()->GetActiveProject()) // project must be open
1683  {
1684  pop->AppendSeparator();
1685 
1686  ProjectFile *projectFile = ed->GetProjectFile();
1687  if (projectFile)
1688  {
1689  pop->Append(idNBRemoveFileFromProject, _("Remove file from project"));
1690  pop->Append(idNBShowFileInTree, _("Show file in the project tree"));
1691  }
1692  else
1693  pop->Append(idNBAddFileToProject, _("Add file to active project"));
1694  }
1695 
1696  pop->AppendSeparator();
1697  pop->Append(idNBProperties, _("Properties..."));
1698  }
1699 
1700  // allow plugins to use this menu
1702 
1703  m_pNotebook->PopupMenu(pop);
1704  delete pop;
1705 }
1706 
1708 {
1709  Close(GetActiveEditor());
1710 }
1711 
1713 {
1714  CloseAllInTabCtrl();
1715 }
1716 
1718 {
1719  if (event.GetId() == idNBTabCloseAllOthers)
1720  CloseAllInTabCtrlExcept(GetActiveEditor());
1721  else if (event.GetId() == idNBTabCloseToTheLeft)
1722  CloseAllInTabCtrlToTheLeft(GetActiveEditor());
1723  else if (event.GetId() == idNBTabCloseToTheRight)
1724  CloseAllInTabCtrlToTheRight(GetActiveEditor());
1725 }
1726 
1728 {
1729  Save(m_pNotebook->GetSelection());
1730 }
1731 
1733 {
1734  SaveAll();
1735 }
1736 
1738 {
1739  SwapActiveHeaderSource();
1740 }
1741 
1743 {
1744  OpenContainingFolder();
1745 }
1746 
1748 {
1749  long style = m_pNotebook->GetWindowStyleFlag();
1750  style &= ~wxAUI_NB_BOTTOM;
1751 
1752  if (event.GetId() == idNBTabBottom)
1753  style |= wxAUI_NB_BOTTOM;
1754  m_pNotebook->SetWindowStyleFlag(style);
1755  m_pNotebook->Refresh();
1756 
1757  // (style & wxAUI_NB_BOTTOM) saves info only about the the tabs position
1758  Manager::Get()->GetConfigManager(_T("app"))->Write(_T("/environment/editor_tabs_bottom"), (bool)(style & wxAUI_NB_BOTTOM));
1759 }
1760 
1762 {
1763  cbEditor* ed = GetBuiltinActiveEditor();
1764  ProjectFile* pf = nullptr;
1765  if (ed)
1766  pf = ed->GetProjectFile();
1767  if (pf)
1768  pf->ShowOptions(Manager::Get()->GetAppWindow());
1769  else
1770  {
1771  ProjectFileOptionsDlg dlg(Manager::Get()->GetAppWindow(), GetActiveEditor()->GetFilename());
1772  PlaceWindow(&dlg);
1773  dlg.ShowModal();
1774  }
1775 }
1776 
1778 {
1780  wxString fname = GetBuiltinActiveEditor()->GetFilename();
1781 
1782  wxArrayInt targets;
1783  if (Manager::Get()->GetProjectManager()->AddFileToProject(fname, project, targets) != 0)
1784  {
1785  ProjectFile* pf = project->GetFileByFilename(fname, false);
1786  GetBuiltinActiveEditor()->SetProjectFile(pf);
1788  }
1789 }
1790 
1792 {
1793  ProjectFile* pf = GetBuiltinActiveEditor()->GetProjectFile();
1794  if (pf) // should be in any case, otherwise something went wrong between popup menu creation and here
1795  {
1796  cbProject *project = pf->GetParentProject();
1799  }
1800 }
1801 
1803 {
1804  ProjectFile* pf = GetBuiltinActiveEditor()->GetProjectFile();
1805  if (pf)
1806  {
1808  ui.SwitchToProjectsPage();
1809  ui.ShowFileInTree(*pf);
1810  }
1811 }
1812 
1814 {
1815  event.Skip(); // allow others to process it too
1816 }
1817 
1819 {
1820  event.Skip(); // allow others to process it too
1821 }
1822 
1824 {
1825  CheckForExternallyModifiedFiles();
1826 }
1827 
1829 {
1830  if (m_pNotebook)
1831  m_pNotebook->Hide();
1832 }
1833 
1835 {
1836  if (m_pNotebook)
1837  m_pNotebook->Show();
1838 }
1839 
1841 {
1842  /* Don't process UpdateUI event when the app is closing.
1843  * It may crash C::B */
1844  if (!Manager::Get()->IsAppShuttingDown() && m_pData->m_SetFocusFlag)
1845  {
1846  cbEditor* ed = GetBuiltinActiveEditor();
1847  if (ed)
1848  ed->GetControl()->SetFocus();
1849  m_pData->m_SetFocusFlag = false;
1850  }
1851 
1852  // allow other UpdateUI handlers to process this event
1853  // *very* important! don't forget it...
1854  event.Skip();
1855 }
1856 
1858 {
1860  if ( !prj
1861  || !Manager::Get()->GetConfigManager(wxT("editor"))->ReadBool(wxT("/track_preprocessor"), true)
1862  || !Manager::Get()->GetConfigManager(wxT("editor"))->ReadBool(wxT("/collect_prj_defines"), true) )
1863  {
1864  event.Skip();
1865  return;
1866  }
1867 
1868  wxArrayString compilerFlags = prj->GetCompilerOptions();
1870  FilesList* lst;
1871  wxString id;
1872  if (tgt)
1873  {
1874  AppendArray(tgt->GetCompilerOptions(), compilerFlags);
1875  lst = &tgt->GetFilesList();
1876  id = tgt->GetCompilerID();
1877  }
1878  else
1879  {
1880  lst = &prj->GetFilesList();
1881  id = prj->GetCompilerID();
1882  }
1883 
1884  Compiler* comp = CompilerFactory::GetCompiler(id); // get global flags
1885  if (comp)
1886  AppendArray(comp->GetCompilerOptions(), compilerFlags);
1887 
1888  wxArrayString defines;
1889  for (size_t i = 0; i < compilerFlags.GetCount(); ++i)
1890  {
1891  if ( compilerFlags[i].StartsWith(wxT("-D"))
1892  || compilerFlags[i].StartsWith(wxT("/D")) )
1893  {
1894  defines.Add(compilerFlags[i].Mid(2));
1895  }
1896  else if (compilerFlags[i].Find(wxT("`")) != wxNOT_FOUND)
1897  {
1898  wxString str = compilerFlags[i];
1899  ExpandBackticks(str);
1900  str.Replace(wxT("`"), wxT(" ")); // remove any leftover backticks to prevent an infinite loop
1901  AppendArray(GetArrayFromString(str, wxT(" ")), compilerFlags);
1902  }
1903  else if ( compilerFlags[i] == wxT("-ansi")
1904  || compilerFlags[i] == wxT("-std=c90")
1905  || compilerFlags[i] == wxT("-std=c++98"))
1906  {
1907  defines.Add(wxT("__STRICT_ANSI__"));
1908  }
1909  }
1910 
1911  defines.Add(wxT("__cplusplus"));
1912  for (FilesList::iterator it = lst->begin(); it != lst->end(); ++it)
1913  {
1914  if ((*it)->relativeFilename.EndsWith(wxT(".c")))
1915  {
1916  defines.RemoveAt(defines.GetCount() - 1); // do not define '__cplusplus' if even a single C file is found
1917  break;
1918  }
1919  }
1920 
1921  if (id.Find(wxT("gcc")) != wxNOT_FOUND)
1922  {
1923  defines.Add(wxT("__GNUC__"));
1924  defines.Add(wxT("__GNUG__"));
1925  }
1926  else if (id.Find(wxT("msvc")) != wxNOT_FOUND)
1927  {
1928  defines.Add(wxT("_MSC_VER"));
1929  defines.Add(wxT("__VISUALC__"));
1930  }
1931 
1932  if (Manager::Get()->GetConfigManager(wxT("editor"))->ReadBool(wxT("/platform_defines"), false))
1933  {
1934  if (platform::windows)
1935  {
1936  defines.Add(wxT("_WIN32"));
1937  defines.Add(wxT("__WIN32"));
1938  defines.Add(wxT("__WIN32__"));
1939  defines.Add(wxT("WIN32"));
1940  defines.Add(wxT("__WINNT"));
1941  defines.Add(wxT("__WINNT__"));
1942  defines.Add(wxT("WINNT"));
1943  defines.Add(wxT("__WXMSW__"));
1944  defines.Add(wxT("__WINDOWS__"));
1945  if (platform::bits == 64)
1946  {
1947  defines.Add(wxT("_WIN64"));
1948  defines.Add(wxT("__WIN64__"));
1949  }
1950  }
1951  else if (platform::macosx)
1952  {
1953  defines.Add(wxT("__WXMAC__"));
1954  defines.Add(wxT("__WXOSX__"));
1955  defines.Add(wxT("__WXCOCOA__"));
1956  defines.Add(wxT("__WXOSX_MAC__"));
1957  defines.Add(wxT("__APPLE__"));
1958  }
1959  else if (platform::Linux)
1960  {
1961  defines.Add(wxT("LINUX"));
1962  defines.Add(wxT("linux"));
1963  defines.Add(wxT("__linux"));
1964  defines.Add(wxT("__linux__"));
1965  }
1966  else if (platform::freebsd)
1967  {
1968  defines.Add(wxT("FREEBSD"));
1969  defines.Add(wxT("__FREEBSD__"));
1970  }
1971  else if (platform::netbsd)
1972  {
1973  defines.Add(wxT("NETBSD"));
1974  defines.Add(wxT("__NETBSD__"));
1975  }
1976  else if (platform::openbsd)
1977  {
1978  defines.Add(wxT("OPENBSD"));
1979  defines.Add(wxT("__OPENBSD__"));
1980  }
1981  else if (platform::darwin)
1982  {
1983  defines.Add(wxT("DARWIN"));
1984  defines.Add(wxT("__APPLE__"));
1985  }
1986  else if (platform::solaris)
1987  {
1988  defines.Add(wxT("sun"));
1989  defines.Add(wxT("__sun"));
1990  defines.Add(wxT("__SUN__"));
1991  defines.Add(wxT("__SUNOS__"));
1992  defines.Add(wxT("__SOLARIS__"));
1993  }
1994  if (platform::Unix)
1995  {
1996  defines.Add(wxT("unix"));
1997  defines.Add(wxT("__unix"));
1998  defines.Add(wxT("__unix__"));
1999  defines.Add(wxT("__UNIX__"));
2000  }
2001  if (platform::gtk)
2002  defines.Add(wxT("__WXGTK__"));
2003  if (platform::bits == 32)
2004  {
2005  defines.Add(wxT("i386"));
2006  defines.Add(wxT("__i386"));
2007  defines.Add(wxT("__i386__"));
2008  defines.Add(wxT("__i386__"));
2009  defines.Add(wxT("_X86_"));
2010  defines.Add(wxT("__INTEL__"));
2011  }
2012  else if (platform::bits == 64)
2013  {
2014  defines.Add(wxT("__amd64"));
2015  defines.Add(wxT("__amd64__"));
2016  defines.Add(wxT("__x86_64"));
2017  defines.Add(wxT("__x86_64__"));
2018  defines.Add(wxT("__IA64__"));
2019  }
2020  }
2021 
2022  const wxString keywords = GetStringFromArray(MakeUniqueArray(defines, true), wxT(" "), false);
2023  const HighlightLanguage hlCpp = m_Theme->GetHighlightLanguage(wxT("C/C++"));
2024  if (m_Theme->GetKeywords(hlCpp, 4) == keywords)
2025  return; // no change
2026 
2027  m_Theme->SetKeywords(hlCpp, 4, keywords);
2028  const wxString key = wxT("/colour_sets/") + m_Theme->GetName() + wxT("/cc/");
2029  Manager::Get()->GetConfigManager(wxT("editor"))->Write(key + wxT("editor/keywords/set4"), keywords);
2030  Manager::Get()->GetConfigManager(wxT("editor"))->Write(key + wxT("name"), wxT("C/C++"));
2031 
2032  // update open editors
2033  for (int index = 0; index < GetEditorsCount(); ++index)
2034  {
2035  cbEditor* ed = GetBuiltinEditor(index);
2036  if ( ed && (ed->GetLanguage() == hlCpp) )
2037  {
2038  cbStyledTextCtrl* stc = ed->GetControl();
2039  stc->SetKeyWords(4, keywords);
2040  }
2041  }
2042  event.Skip();
2043 }
2044 
2046 {
2047  m_Zoom = zoom;
2048 }
2049 
2051 {
2052  return m_Zoom;
2053 }
2054 
ProjectFile * GetFileByFilename(const wxString &filename, bool isRelative=true, bool isUnixFilename=false)
Access a file of the project.
Definition: cbproject.cpp:1049
#define EVT_APP_STARTUP_DONE(fn)
Definition: sdk_events.h:252
void ActivatePrevious()
bool CloseAll(bool dontsave=false)
Closes all opened editors.
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
EditorBase * InternalGetEditorBase(int page)
bool CloseAllInTabCtrlExcept(EditorBase *editor, bool dontsave=false)
Closes all editors in the same tab control as the active editor, except the editor passed as paramete...
DLLIMPORT wxArrayString GetArrayFromString(const wxString &text, const wxString &separator=DEFAULT_ARRAY_SEP, bool trimSpaces=true)
Definition: globals.cpp:134
int editorTabPos
The position of the editor-tab for this file.
Definition: projectfile.h:178
virtual const wxString & GetShortName() const
Returns the editor&#39;s short name.
Definition: editorbase.h:58
static const int idNBSwitchFileMax
int GetSelection() const
wxColour * wxBLACK
static const int idNBRemoveFileFromProject
int wxNewId()
PluginManager * GetPluginManager() const
Definition: manager.cpp:444
#define wxICON_QUESTION
cbEditor * New(const wxString &newFileName=wxEmptyString)
bool CloseAllInTabCtrl(bool dontsave=false)
Closes all editors in the same tab control as the active editor.
void RemoveEditorBase(EditorBase *eb, bool deleteObject=true)
wxDateTime GetLastModificationTime() const
Returns the last modification time for the file.
Definition: cbeditor.h:185
void OnProperties(wxCommandEvent &event)
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
#define COLORSET_DEFAULT
bool IsHeaderSource(const wxFileName &candidateFile, const wxFileName &activeFile, FileType ftActive, bool &isCandidate)
virtual const wxString & GetTitle()
The editor&#39;s title.
Definition: editorbase.cpp:144
int ReadInt(const wxString &name, int defaultVal=0)
virtual void RebuildTree()=0
Rebuild the project manager&#39;s tree.
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
wxMenuItem * FindItemByPosition(size_t position) const
bool FixFoldState()
Fix fold states by comparing foldBackup with m_pControl.
Definition: cbeditor.cpp:1935
wxString substr(size_t nStart=0, size_t nLen=npos) const
virtual bool QueryClose()
Can this be closed (destroyed)?
Definition: editorbase.cpp:180
bool IsOK() const
Returns true if editor is OK, i.e.
Definition: cbeditor.h:101
DLLIMPORT const wxString cbDEFAULT_OPEN_FOLDER_CMD
Definition: globals.cpp:66
static const int idNBProperties
const DLLIMPORT wxString H_EXT
bool ShowOptions(wxWindow *parent)
Show the file properties dialog.
static bool IsAppShuttingDown()
Definition: manager.cpp:333
size_t length() const
void SetColourSet(EditorColourSet *theme)
int cbRegisterId(int id)
cbNotebookStack * GetNotebookStack()
void CollectDefines(CodeBlocksEvent &event)
#define wxICON_ERROR
void RegisterColour(const wxString &category, const wxString &name, const wxString &id, const wxColour &defaultColour)
DLLIMPORT wxBitmap cbLoadBitmap(const wxString &filename, wxBitmapType bitmapType=wxBITMAP_TYPE_PNG)
This function loads a bitmap from disk.
Definition: globals.cpp:1102
bool Reload(bool detectEncoding=true)
Reloads the file from disk.
Definition: cbeditor.cpp:1673
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
Definition: cbproject.h:685
void Enable(int id, bool enable)
bool wxFileExists(const wxString &filename)
wxFileName file
The full filename of this file.
Definition: projectfile.h:126
void RemoveFileFromProject(ProjectFile *pfile, cbProject *project)
Remove a file from a project.
virtual bool IsReadOnly() const
Is the editor read-only?
Definition: editorbase.h:217
void SetColourSet(EditorColourSet *theme)
Set the colour set to use.
Definition: cbeditor.cpp:1620
virtual void ShowFileInTree(ProjectFile &projectFile)=0
void OnAppStartShutdown(wxCommandEvent &event)
PrintColourMode
void RebuildNotebookStack()
EVTIMPORT const wxEventType cbEVT_BUILDTARGET_SELECTED
Definition: sdk_events.cpp:119
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
cbEditor * InternalGetBuiltinEditor(int page)
DLLIMPORT bool NormalizePath(wxFileName &f, const wxString &base)
Definition: globals.cpp:942
static const int idNBTabTop
void Print(bool selectionOnly, PrintColourMode pcm, bool line_numbers)
Print the file.
Definition: cbeditor.cpp:3010
static const int idNBTabSplitHorz
bool GetCheckForExternallyModifiedFiles() const
Get check for externally modified files.
Definition: cbproject.cpp:1628
#define wxCANCEL
bool CloseAllInTabCtrlToTheLeft(EditorBase *editor, bool dontsave=false)
Closes all editors in the same tab control which are on the left of the passed editor.
EVTIMPORT const wxEventType cbEVT_PROJECT_ACTIVATE
Definition: sdk_events.cpp:99
FileManager * GetFileManager() const
Definition: manager.cpp:479
void OnAppDoneStartup(wxCommandEvent &event)
void OnCloseAllOthers(wxCommandEvent &event)
~EditorManager() override
int GetZoom() const
bool CloseAllExcept(EditorBase *editor, bool dontsave=false)
Closes all opened editors, except the editor passed as parameter.
virtual const wxArrayString & GetCompilerOptions() const
wxCStrData c_str() const
bool wxDirExists(const wxString &dirname)
wxMenuItem * Append(int id, const wxString &item=wxEmptyString, const wxString &helpString=wxEmptyString, wxItemKind kind=wxITEM_NORMAL)
static Compiler * GetCompiler(size_t index)
void SetText(const wxString &text)
Replace the contents of the document with the argument text.
virtual void SwitchToProjectsPage()=0
Switches the management&#39;s notebook to the Projects tab.
void wxRegisterId(int id)
#define _T(string)
void SetActiveEditor(EditorBase *ed)
FileType
Known file types.
Definition: globals.h:49
void OnPageChanged(wxAuiNotebookEvent &event)
#define wxYES_NO
bool Close(const wxString &filename, bool dontsave=false)
void Unsplit()
Unsplit the editor window.
Definition: cbeditor.cpp:1185
void OnCheckForModifiedFiles(wxCommandEvent &event)
cbProjectManagerUI & GetUI()
DLLIMPORT wxString GetStringFromArray(const wxArrayString &array, const wxString &separator=DEFAULT_ARRAY_SEP, bool SeparatorAtEnd=true)
Definition: globals.cpp:122
bool IsLoading()
Check if the project manager is loading a project/workspace.
bool IsAbsolute(wxPathFormat format=wxPATH_NATIVE) const
DLLIMPORT FileType FileTypeOf(const wxString &filename)
Definition: globals.cpp:285
void OnAddFileToProject(wxCommandEvent &event)
void OnOpenContainingFolder(wxCommandEvent &event)
void SetModified(bool modified=true) override
Set the editor&#39;s modification state to modified.
Definition: cbeditor.cpp:861
void OnShowFileInTree(wxCommandEvent &event)
wxString GetName() const
static size_t GetAllFiles(const wxString &dirname, wxArrayString *files, const wxString &filespec=wxEmptyString, int flags=wxDIR_DEFAULT)
void OnPageChanging(wxAuiNotebookEvent &event)
bool OpenContainingFolder()
static const int idNBTabCloseAll
int idEditorManagerCheckFiles
#define wxT(string)
#define wxNOT_FOUND
bool CloseEditors(const std::vector< EditorBase *> &editors, bool dontsave=false)
Closes all editors passed to the function.
Represents a file in a Code::Blocks project.
Definition: projectfile.h:39
size_t GetMenuItemCount() const
size_t find(const wxString &str, size_t nStart=0) const
A generic Code::Blocks event.
Definition: sdk_events.h:20
void RecreateOpenEditorStyles()
void OnRemoveFileFromProject(wxCommandEvent &event)
int CmpNoCase(const wxString &s) const
void OnPageContextMenu(wxAuiNotebookEvent &event)
void OnSwapHeaderSource(wxCommandEvent &event)
wxWindow * GetAppWindow() const
Definition: manager.cpp:424
virtual void SetModified(bool=true)
Set the modification status.
Definition: editorbase.h:73
void OnUpdateUI(wxUpdateUIEvent &event)
static const int idNBSwapHeaderSource
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
void Write(const wxString &name, const wxString &value, bool ignoreEmpty=false)
virtual bool Close()
Close this editor.
Definition: editorbase.cpp:203
virtual const wxString & GetFilename() const
Get the editor&#39;s filename (if applicable).
Definition: editorbase.h:45
DLLIMPORT wxString UnixFilename(const wxString &filename, wxPathFormat format=wxPATH_NATIVE)
Definition: globals.cpp:228
wxString GetExt() const
Event functor class.
Definition: cbfunctor.h:37
Represents a Code::Blocks project.
Definition: cbproject.h:96
const wxString & GetActiveBuildTarget() const
Definition: cbproject.cpp:1373
void OnSave(wxCommandEvent &event)
EVTIMPORT const wxEventType cbEVT_WORKSPACE_LOADING_COMPLETE
Definition: sdk_events.cpp:112
bool wxSetWorkingDirectory(const wxString &dir)
EditorBase * GetActiveEditor()
static const int idNBShowFileInTree
void SetReadOnly(bool readonly=true) override
Set the editor read-only.
Definition: cbeditor.cpp:2574
wxColour * wxLIGHT_GREY
OpenContainingFolderData(const wxString &command, bool select)
cbStyledTextCtrl * GetControl() const
Returns a pointer to the underlying cbStyledTextCtrl object (which itself is the wxWindows implementa...
Definition: cbeditor.cpp:842
DLLIMPORT const wxString DEFAULT_CONSOLE_SHELL
Definition: globals.cpp:63
int FindPageFromEditor(EditorBase *eb)
bool CloseActive(bool dontsave=false)
EVTIMPORT const wxEventType cbEVT_EDITOR_SWITCHED
Definition: sdk_events.cpp:82
void AddCustomEditor(EditorBase *eb)
wxString wxPathOnly(const wxString &path)
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
virtual bool SaveAs()
Save editor contents under a different filename.
Definition: editorbase.h:120
const wxSize wxDefaultSize
const wxPoint wxDefaultPosition
void HideNotebook()
Hides the editor notebook for layout purposes.
bool IsSameAs(const wxString &s, bool caseSensitive=true) const
void Print(PrintScope ps, PrintColourMode pcm, bool line_numbers)
wxMenuItem * AppendSeparator()
int ID_EditorManager
Base class that all "editors" should inherit from.
Definition: editorbase.h:30
LogManager * GetLogManager() const
Definition: manager.cpp:439
static wxColour GetColour(wxSystemColour index)
cbProject * GetActiveProject()
Retrieve the active project.
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
virtual wxString GetBasePath() const
Read the target&#39;s base path, e.g. if GetFilename() returns "/usr/local/bin/xxx", base path will retur...
bool IsOpened() const
static const int idNBTabCloseToTheLeft
struct EditorManagerInternalData * This is the private data holder for the EditorManager * All data ...
void OnTabPosition(wxCommandEvent &event)
bool wxIsupper(const wxUniChar &c)
const wxString g_EditorModified
Definition: cbeditor.cpp:55
const wxStringCharType * wx_str() const
virtual int ShowModal()
bool Save(const wxString &filename)
PrintScope
virtual bool IsBuiltinEditor() const
Is this a built-in editor?
Definition: editorbase.cpp:209
int ID_NBEditorManager
cbNotebookStack * next
Definition: editormanager.h:53
wxString wxEmptyString
static const int idNBTabCloseToTheRight
static const int idNBAddFileToProject
EVTIMPORT const wxEventType cbEVT_EDITOR_DEACTIVATED
Definition: sdk_events.cpp:84
bool SaveAs(int index)
static const int idNBSwitchFile1
bool QueryClose(EditorBase *editor)
DLLIMPORT wxArrayString MakeUniqueArray(const wxArrayString &array, bool caseSens)
Definition: globals.cpp:198
void NotifyPlugins(CodeBlocksEvent &event)
Definition: manager.h:183
MacrosManager * GetMacrosManager() const
Definition: manager.cpp:454
void SetZoom(int zoom)
cbEditor * Open(const wxString &filename, int pos=0, ProjectFile *data=nullptr)
void RemoveCustomEditor(EditorBase *eb)
static bool Access(const wxString &name, wxFile::OpenMode mode)
const wxString & _(const wxString &string)
DLLIMPORT void QuoteStringIfNeeded(wxString &str)
Definition: globals.cpp:260
void ReplaceMacros(wxString &buffer, ProjectBuildTarget *target=nullptr, bool subrequest=false)
EditorBase * GetEditor(int index)
cbEditor * GetBuiltinEditor(EditorBase *eb)
int GetBuildTargetsCount()
Definition: cbproject.h:200
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
virtual const wxArrayString & GetIncludeDirs() const
cb_must_consume_result LoaderBase * Load(const wxString &file, bool reuseEditors=false)
Loads a file, once this function is called, the actually loading process is done in the worker thread...
ProjectFilesVector generatedFiles
Auto-generated files when compiling this file.
Definition: projectfile.h:207
virtual bool GetModified() const
Is it modified?
Definition: editorbase.h:67
wxArray< int > wxArrayInt
void OnGenericContextMenuHandler(wxCommandEvent &event)
static wxString GetDataFolder(bool global=true)
void CheckForExternallyModifiedFiles()
Check if one of the open files has been modified outside the IDE.
ProjectBuildTarget * GetBuildTarget(int index)
Access a build target.
Definition: cbproject.cpp:1392
Abstract base class for compilers.
Definition: compiler.h:274
ColourManager * GetColourManager() const
Definition: manager.cpp:489
void MarkReadOnly(int page, bool readOnly=true)
void SetKeyWords(int keyWordSet, const wxString &keyWords)
Set up the key words used by the lexer.
bool SaveFoldState()
Save fold states within a new cbStyledTextCtrl.
Definition: cbeditor.cpp:1920
SplitType GetSplitType() const
Returns the state of split-view for this editor.
Definition: cbeditor.h:95
void Touch()
Sets the last modification time for the file to &#39;now&#39;.
Definition: cbeditor.cpp:1699
void SetProjectFile(ProjectFile *project_file, bool preserve_modified=false)
Set the ProjectFile pointer associated with this editor.
Definition: cbeditor.cpp:885
bool CloseAllInTabCtrlToTheRight(EditorBase *editor, bool dontsave=false)
Closes all editors in the same tab control which are on the right of the passed editor.
bool GetReadOnly() const
In read-only mode?
A file editor.
Definition: cbeditor.h:43
EVTIMPORT const wxEventType cbEVT_EDITOR_ACTIVATED
Definition: sdk_events.cpp:83
static const int idNBTabSplitVert
FileVisualState GetFileState() const
bool IsEmpty() const
DLLIMPORT void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode=pdlBest, bool enforce=false)
Definition: globals.cpp:1177
wxString GetPath(int flags=wxPATH_GET_VOLUME, wxPathFormat format=wxPATH_NATIVE) const
The entry point singleton for working with projects.
void ShowNotebook()
Shows the previously hidden editor notebook.
virtual const wxString & GetCompilerID() const
Read the target&#39;s compiler.
wxFileName FindHeaderSource(const wxArrayString &candidateFilesArray, const wxFileName &activeFile, bool &isCandidate)
static const size_t npos
DLLIMPORT void AppendArray(const wxArrayString &from, wxArrayString &to)
Definition: globals.cpp:222
static const int idNBTabClose
wxString GetFullName() const
void AskPluginsForModuleMenu(const ModuleType type, wxMenu *menu, const FileTreeData *data=nullptr)
A notebook class This class is derived from wxAuiNotebook, to enhance its abilities.
Definition: cbauibook.h:30
void OnPageClose(wxAuiNotebookEvent &event)
void GetEditorsInTabCtrl(std::vector< EditorBase *> &editors, EditorBase *editor)
Returns a vector with pointers to the editors that are in the same tab control as the passed editor...
void DebugLog(const wxString &msg, Logger::level lv=Logger::info)
Definition: logmanager.h:146
bool EndsWith(const wxString &suffix, wxString *rest=NULL) const
static const int idNBTabSave
wxWindow * window
Definition: editormanager.h:52
void OnCloseAll(wxCommandEvent &event)
void RegisterEventSink(wxEventType eventType, IEventFunctorBase< CodeBlocksEvent > *functor)
Definition: manager.cpp:550
EditorManagerInternalData(EditorManager *owner)
size_t Add(const wxString &str, size_t copies=1)
wxBitmap wxNullBitmap
cbProject * FindProjectForFile(const wxString &file, ProjectFile **resultFile, bool isRelative, bool isUnixFilename)
Return the project which has the file in it, also return the pointer to the ProjectFile object...
cbProject * GetParentProject()
Definition: projectfile.h:93
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
#define wxCLIP_CHILDREN
Represents a Code::Blocks project build target.
static bool s_CanShutdown
Definition: editormanager.h:62
bool Normalize(int flags=wxPATH_NORM_ALL, const wxString &cwd=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
const DLLIMPORT wxString CPP_EXT
static const int idNBTabBottom
wxArrayString wxStringTokenize(const wxString &str, const wxString &delims=wxDEFAULT_DELIMITERS, wxStringTokenizerMode mode=wxTOKEN_DEFAULT)
size_t GetCount() const
ProjectFile * AutoGeneratedBy() const
If this is an auto-generated file, which file is generating it?
Definition: projectfile.h:201
ProjectFile * GetProjectFile() const
Read the ProjectFile pointer associated with this editor.
Definition: cbeditor.h:123
EVTIMPORT const wxEventType cbEVT_EDITOR_OPEN
Definition: sdk_events.cpp:81
void Split(SplitType split)
Split the editor window.
Definition: cbeditor.cpp:1084
#define EVT_APP_START_SHUTDOWN(fn)
Definition: sdk_events.h:254
DLLIMPORT wxString ExpandBackticks(wxString &str)
Definition: globals.cpp:861
static void SplitPath(const wxString &fullpath, wxString *volume, wxString *path, wxString *name, wxString *ext, bool *hasExt=NULL, wxPathFormat format=wxPATH_NATIVE)
bool MakeAbsolute(const wxString &cwd=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
bool FileExists() const
bool UpdateProjectFiles(cbProject *project)
static const int EditorMaxSwitchTo
HighlightLanguage GetLanguage() const
Definition: cbeditor.h:292
void SetFileState(FileVisualState state)
Set the visual state (modified, read-only, etc).
int Printf(const wxString &pszFormat,...)
EditorBase * IsOpen(const wxString &filename)
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
void DeleteNotebookStack()
int AddFileToProject(const wxString &filename, cbProject *project=nullptr, int target=-1)
Add a file to a project.
#define NULL
Definition: prefix.cpp:59
virtual bool Save()
Save contents.
Definition: editorbase.h:113
bool wxGetKeyState(wxKeyCode key)
int GetOldSelection() const
bool GetModified() const override
Returns true if editor is modified, false otherwise.
Definition: cbeditor.cpp:856
static const int idNBTabUnsplit
#define wxNO_FULL_REPAINT_ON_RESIZE
void AddEditorBase(EditorBase *eb)
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 OnClose(wxCommandEvent &event)
void OnSaveAll(wxCommandEvent &event)
static const int idNBTabSaveAll
void UpdateProjectFile()
Updates the associated ProjectFile object with the editor&#39;s caret position, top visible line and its ...
Definition: cbeditor.cpp:952
void SetEditorStyle()
Applies the styles that match the filename of the editor.
Definition: cbeditor.cpp:1230
long wxExecute(const wxString &command, int flags=wxEXEC_ASYNC, wxProcess *callback=NULL, const wxExecuteEnv *env=NULL)
DLLIMPORT wxString realpath(const wxString &path)
Definition: globals.cpp:1348
static const int idNBTabOpenContainingFolder
wxMenuItem * AppendCheckItem(int id, const wxString &item, const wxString &help=wxEmptyString)
bool SwapActiveHeaderSource()
static const int idNBTabCloseAllOthers