Code::Blocks  SVN r11506
classbrowser.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 10664 $
6  * $Id: classbrowser.cpp 10664 2016-01-17 13:58:33Z fuscated $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/classbrowser.cpp $
8  */
9 
10 #include <sdk.h>
11 
12 #ifndef CB_PRECOMP
13  #include <wx/button.h>
14  #include <wx/choice.h>
15  #include <wx/choicdlg.h>
16  #include <wx/intl.h>
17  #include <wx/listctrl.h>
18  #include <wx/menu.h>
19  #include <wx/sizer.h>
20  #include <wx/stattext.h>
21  #include <wx/treectrl.h>
22  #include <wx/settings.h>
23  #include <wx/splitter.h>
24  #include <wx/utils.h> // wxBusyCursor
25  #include <wx/tipwin.h>
26  #include <wx/xrc/xmlres.h>
27 
28  #include <cbeditor.h>
29  #include <cbproject.h>
30  #include <configmanager.h>
31  #include <editormanager.h>
32  #include <globals.h>
33  #include <logmanager.h>
34  #include <manager.h>
35  #include <pluginmanager.h>
36  #include <projectmanager.h>
37 #endif
38 
39 #include <wx/tokenzr.h>
40 
41 #include <cbstyledtextctrl.h>
42 
43 #include "classbrowser.h" // class's header file
44 #include "nativeparser.h"
45 
46 #include "parser/ccdebuginfo.h"
47 
48 #define CC_CLASS_BROWSER_DEBUG_OUTPUT 0
49 
50 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
51  #if CC_GLOBAL_DEBUG_OUTPUT == 1
52  #undef CC_CLASS_BROWSER_DEBUG_OUTPUT
53  #define CC_CLASS_BROWSER_DEBUG_OUTPUT 1
54  #elif CC_GLOBAL_DEBUG_OUTPUT == 2
55  #undef CC_CLASS_BROWSER_DEBUG_OUTPUT
56  #define CC_CLASS_BROWSER_DEBUG_OUTPUT 2
57  #endif
58 #endif
59 
60 #if CC_CLASS_BROWSER_DEBUG_OUTPUT == 1
61  #define TRACE(format, args...) \
62  CCLogger::Get()->DebugLog(F(format, ##args))
63  #define TRACE2(format, args...)
64 #elif CC_CLASS_BROWSER_DEBUG_OUTPUT == 2
65  #define TRACE(format, args...) \
66  do \
67  { \
68  if (g_EnableDebugTrace) \
69  CCLogger::Get()->DebugLog(F(format, ##args)); \
70  } \
71  while (false)
72  #define TRACE2(format, args...) \
73  CCLogger::Get()->DebugLog(F(format, ##args))
74 #else
75  #define TRACE(format, args...)
76  #define TRACE2(format, args...)
77 #endif
78 
92 
95 
96 BEGIN_EVENT_TABLE(ClassBrowser, wxPanel)
97  EVT_TREE_ITEM_ACTIVATED (XRCID("treeMembers"), ClassBrowser::OnTreeItemDoubleClick)
98  EVT_TREE_ITEM_RIGHT_CLICK(XRCID("treeMembers"), ClassBrowser::OnTreeItemRightClick)
99 
100  EVT_TREE_ITEM_ACTIVATED (XRCID("treeAll"), ClassBrowser::OnTreeItemDoubleClick)
101  EVT_TREE_ITEM_RIGHT_CLICK(XRCID("treeAll"), ClassBrowser::OnTreeItemRightClick)
102  EVT_TREE_ITEM_EXPANDING (XRCID("treeAll"), ClassBrowser::OnTreeItemExpanding)
103 #ifndef CC_NO_COLLAPSE_ITEM
104  EVT_TREE_ITEM_COLLAPSING (XRCID("treeAll"), ClassBrowser::OnTreeItemCollapsing)
105 #endif // CC_NO_COLLAPSE_ITEM
106  EVT_TREE_SEL_CHANGED (XRCID("treeAll"), ClassBrowser::OnTreeSelChanged)
107 
108  EVT_TEXT_ENTER(XRCID("cmbSearch"), ClassBrowser::OnSearch)
109  EVT_COMBOBOX (XRCID("cmbSearch"), ClassBrowser::OnSearch)
110  EVT_BUTTON(XRCID("btnSearch"), ClassBrowser::OnSearch)
111 
112  EVT_CHOICE(XRCID("cmbView"), ClassBrowser::OnViewScope)
113 
114  EVT_MENU(idMenuJumpToDeclaration, ClassBrowser::OnJumpTo)
115  EVT_MENU(idMenuJumpToImplementation, ClassBrowser::OnJumpTo)
116  EVT_MENU(idMenuRefreshTree, ClassBrowser::OnRefreshTree)
117  EVT_MENU(idMenuForceReparse, ClassBrowser::OnForceReparse)
118  EVT_MENU(idCBViewInheritance, ClassBrowser::OnCBViewMode)
119  EVT_MENU(idCBExpandNS, ClassBrowser::OnCBExpandNS)
120  EVT_MENU(idMenuDebugSmartSense, ClassBrowser::OnDebugSmartSense)
121  EVT_MENU(idCBNoSort, ClassBrowser::OnSetSortType)
122  EVT_MENU(idCBSortByAlpabet, ClassBrowser::OnSetSortType)
123  EVT_MENU(idCBSortByKind, ClassBrowser::OnSetSortType)
124  EVT_MENU(idCBSortByScope, ClassBrowser::OnSetSortType)
125  EVT_MENU(idCBSortByLine, ClassBrowser::OnSetSortType)
126  EVT_MENU(idCBBottomTree, ClassBrowser::OnCBViewMode)
127 
128  EVT_COMMAND(idThreadEvent, wxEVT_COMMAND_ENTER, ClassBrowser::OnThreadEvent)
129 END_EVENT_TABLE()
130 
131 // class constructor
133  m_NativeParser(np),
134  m_TreeForPopupMenu(0),
135  m_Parser(0L),
136  m_ClassBrowserSemaphore(/*initialcount*/ 0, /*maxcount*/ 1),
137  m_ClassBrowserBuilderThread(0)
138 {
139  wxXmlResource::Get()->LoadPanel(this, parent, _T("pnlCB")); // panel class browser -> pnlCB
140  m_Search = XRCCTRL(*this, "cmbSearch", wxComboBox);
141 
142  if (platform::windows)
143  m_Search->SetWindowStyle(wxTE_PROCESS_ENTER); // it's a must on windows to catch EVT_TEXT_ENTER
144 
145  // Subclassed in XRC file, for reference see here: http://wiki.wxwidgets.org/Resource_Files
146  m_CCTreeCtrl = XRCCTRL(*this, "treeAll", CCTreeCtrl);
147  m_CCTreeCtrlBottom = XRCCTRL(*this, "treeMembers", CCTreeCtrl);
148 
149  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
150  int filter = cfg->ReadInt(_T("/browser_display_filter"), bdfFile);
151  XRCCTRL(*this, "cmbView", wxChoice)->SetSelection(filter);
152 
153  XRCCTRL(*this, "splitterWin", wxSplitterWindow)->SetMinSize(wxSize(-1, 200));
154  // if the classbrowser is put under the control of a wxFlatNotebook,
155  // somehow the main panel is like "invisible" :/
156  // so we force the correct colour for the panel here...
157  XRCCTRL(*this, "MainPanel", wxPanel)->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
158 }
159 
160 // class destructor
162 {
163  int pos = XRCCTRL(*this, "splitterWin", wxSplitterWindow)->GetSashPosition();
164  Manager::Get()->GetConfigManager(_T("code_completion"))->Write(_T("/splitter_pos"), pos);
165 
166  SetParser(NULL);
167 
169  {
170  // tell the thread, that we want to terminate it, TestDestroy only works after Delete(), which should not
171  // be used on joinable threads
172  // if we disable the cc-plugin, we otherwise come to an infinite wait in the threads Entry()-function
174  // awake the thread
176  // free the system-resources
178  // according to the wxWidgets-documentation the wxThread object itself has to be deleted explicitly,
179  // to free the memory, if it is created on the heap, this is not done by Wait()
181  }
182 }
183 
185 {
186  if (m_Parser == parser)
187  return;
188 
189  m_Parser = parser;
190  if (m_Parser)
191  {
192  int sel = XRCCTRL(*this, "cmbView", wxChoice)->GetSelection();
193  BrowserDisplayFilter filter = static_cast<BrowserDisplayFilter>(sel);
194  if (!m_NativeParser->IsParserPerWorkspace() && filter == bdfWorkspace)
195  filter = bdfProject;
196 
200  }
201  else
202  CCLogger::Get()->DebugLog(wxT("SetParser: No parser available."));
203 }
204 
206 {
207  int pos = Manager::Get()->GetConfigManager(_T("code_completion"))->ReadInt(_T("/splitter_pos"), 250);
208  XRCCTRL(*this, "splitterWin", wxSplitterWindow)->SetSashPosition(pos, false);
209  XRCCTRL(*this, "splitterWin", wxSplitterWindow)->Refresh();
210 }
211 
212 void ClassBrowser::UpdateClassBrowserView(bool checkHeaderSwap)
213 {
214  TRACE(_T("ClassBrowser::UpdateClassBrowserView(), m_ActiveFilename = %s"), m_ActiveFilename.wx_str());
215 
216  wxString oldActiveFilename(m_ActiveFilename);
218 
220  return;
221 
223  if (editor)
224  m_ActiveFilename = editor->GetFilename();
225  TRACE(_T("ClassBrowser::UpdateClassBrowserView(), new m_ActiveFilename = %s"), m_ActiveFilename.wx_str());
226 
227  if (checkHeaderSwap)
228  {
229  wxString oldShortName = oldActiveFilename.AfterLast(wxFILE_SEP_PATH);
230  if (oldShortName.Find(_T('.')) != wxNOT_FOUND)
231  oldShortName = oldShortName.BeforeLast(_T('.'));
232 
233  wxString newShortName = m_ActiveFilename.AfterLast(wxFILE_SEP_PATH);
234  if (newShortName.Find(_T('.')) != wxNOT_FOUND)
235  newShortName = newShortName.BeforeLast(_T('.'));
236 
237  if ( oldShortName.IsSameAs(newShortName) )
238  {
239  TRACE(_T("ClassBrowser::UpdateClassBrowserView() match the old filename, return!"));
240  return;
241  }
242  }
243 
244  cbProject* activeProject = 0;
246  activeProject = m_NativeParser->GetProjectByParser(m_Parser);
247  else
248  activeProject = m_NativeParser->GetCurrentProject();
249 
250  if (!activeProject)
251  CCLogger::Get()->DebugLog(wxT("ClassBrowser::UpdateClassBrowserView(): No active project available."));
252 
253  ThreadedBuildTree(activeProject); // (Re-) create tree UI
254 
255  wxSplitterWindow* splitter = XRCCTRL(*this, "splitterWin", wxSplitterWindow);
257  {
259  m_CCTreeCtrlBottom->Show(true);
260  }
261  else
262  {
263  splitter->Unsplit();
264  m_CCTreeCtrlBottom->Show(false);
265  }
266 }
267 
268 void ClassBrowser::ShowMenu(wxTreeCtrl* tree, wxTreeItemId id, cb_unused const wxPoint& pt)
269 {
270 // NOTE: local variables are tricky! If you build two local menus
271 // and attach menu B to menu A, on function exit both menu A and menu B
272 // will be destroyed. But when destroying menu A, menu B will be destroyed
273 // again. Its already-freed memory will be accessed, generating a segfault.
274 
275 // A safer approach is to make all menus heap-based, and delete the topmost
276 // on exit.
277 
278  m_TreeForPopupMenu = tree;
279  if (!id.IsOk() || !m_Parser)
280  return;
281 
282  wxString caption;
283  wxMenu* menu = new wxMenu(wxEmptyString);
284 
285  CCTreeCtrlData* ctd = (CCTreeCtrlData*)tree->GetItemData(id);
286  if (ctd && ctd->m_Token)
287  {
288  switch (ctd->m_Token->m_TokenKind)
289  {
290  case tkConstructor:
291  case tkDestructor:
292  case tkFunction:
293  if (ctd->m_Token->m_ImplLine != 0 && !ctd->m_Token->GetImplFilename().IsEmpty())
294  menu->Append(idMenuJumpToImplementation, _("Jump to &implementation"));
295  // intentionally fall through
296  case tkNamespace:
297  case tkClass:
298  case tkEnum:
299  case tkTypedef:
300  case tkVariable:
301  case tkEnumerator:
302  case tkMacroDef:
303  case tkMacroUse:
304  case tkAnyContainer:
305  case tkAnyFunction:
306  case tkUndefined:
307  default:
308  menu->Append(idMenuJumpToDeclaration, _("Jump to &declaration"));
309  }
310  }
311 
312  const BrowserOptions& options = m_Parser->ClassBrowserOptions();
313  if (tree == m_CCTreeCtrl)
314  {
315  // only in top tree
316  if (menu->GetMenuItemCount() != 0)
317  menu->AppendSeparator();
318 
319  menu->AppendCheckItem(idCBViewInheritance, _("Show inherited members"));
320  menu->AppendCheckItem(idCBExpandNS, _("Auto-expand namespaces"));
321  menu->Append (idMenuRefreshTree, _("&Refresh tree"));
322 
323  if (id == m_CCTreeCtrl->GetRootItem())
324  {
325  menu->AppendSeparator();
326  menu->Append(idMenuForceReparse, _("Re-parse now"));
327  }
328 
330  {
331  menu->AppendSeparator();
332  menu->AppendCheckItem(idMenuDebugSmartSense, _("Debug SmartSense"));
333  menu->Check(idMenuDebugSmartSense, s_DebugSmartSense);
334  }
335 
336  menu->Check(idCBViewInheritance, m_Parser ? options.showInheritance : false);
337  menu->Check(idCBExpandNS, m_Parser ? options.expandNS : false);
338  }
339 
340  menu->AppendSeparator();
341  menu->AppendCheckItem(idCBNoSort, _("Do not sort"));
342  menu->AppendCheckItem(idCBSortByAlpabet, _("Sort alphabetically"));
343  menu->AppendCheckItem(idCBSortByKind, _("Sort by kind"));
344  menu->AppendCheckItem(idCBSortByScope, _("Sort by access"));
345  menu->AppendCheckItem(idCBSortByLine, _("Sort by line"));
346 
347  const BrowserSortType& bst = options.sortType;
348  switch (bst)
349  {
350  case bstAlphabet:
351  menu->Check(idCBSortByAlpabet, true);
352  break;
353  case bstKind:
354  menu->Check(idCBSortByKind, true);
355  break;
356  case bstScope:
357  menu->Check(idCBSortByScope, true);
358  break;
359  case bstLine:
360  menu->Check(idCBSortByLine, true);
361  break;
362  case bstNone:
363  default:
364  menu->Check(idCBNoSort, true);
365  break;
366  }
367 
368  menu->AppendSeparator();
369  menu->AppendCheckItem(idCBBottomTree, _("Display bottom tree"));
370  menu->Check(idCBBottomTree, options.treeMembers);
371 
372  if (menu->GetMenuItemCount() != 0)
373  PopupMenu(menu);
374 
375  delete menu; // Prevents memory leak
376 }
377 
378 bool ClassBrowser::FoundMatch(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& item)
379 {
380  ClassTreeData* ctd = static_cast<ClassTreeData*>(tree->GetItemData(item));
381  if (ctd && ctd->GetToken())
382  {
383  const Token* token = ctd->GetToken();
384  if ( token->m_Name.Lower().StartsWith(search)
385  || token->m_Name.Lower().StartsWith(_T('~') + search) ) // C++ destructor
386  {
387  return true;
388  }
389  }
390  return false;
391 }
392 
394 {
395  wxTreeItemId ret;
396  if (!start.IsOk())
397  return ret;
398 
399  // look at siblings
400  ret = tree->GetNextSibling(start);
401  if (ret.IsOk())
402  return ret;
403 
404  // ascend one level now and recurse
405  return FindNext(search, tree, tree->GetItemParent(start));
406 }
407 
408 wxTreeItemId ClassBrowser::FindChild(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& start, bool recurse, bool partialMatch)
409 {
410  if (!tree)
411  return wxTreeItemId();
412 
413  wxTreeItemIdValue cookie;
414  wxTreeItemId res = tree->GetFirstChild(start, cookie);
415  while (res.IsOk())
416  {
417  wxString text = tree->GetItemText(res);
418  if ( (!partialMatch && text == search)
419  || ( partialMatch && text.StartsWith(search)) )
420  {
421  return res;
422  }
423 
424  if (recurse && tree->ItemHasChildren(res))
425  {
426  res = FindChild(search, tree, res, true, partialMatch);
427  if (res.IsOk())
428  return res;
429  }
430  res = m_CCTreeCtrl->GetNextChild(start, cookie);
431  }
432  res.Unset();
433  return res;
434 }
435 
436 bool ClassBrowser::RecursiveSearch(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& parent, wxTreeItemId& result)
437 {
438  if (!parent.IsOk() || !tree)
439  return false;
440 
441  // first check the parent item
442  if (FoundMatch(search, tree, parent))
443  {
444  result = parent;
445  return true;
446  }
447 
448  wxTreeItemIdValue cookie;
449  wxTreeItemId child = tree->GetFirstChild(parent, cookie);
450 
451  if (!child.IsOk())
452  return RecursiveSearch(search, tree, FindNext(search, tree, parent), result);
453 
454  while (child.IsOk())
455  {
456  if (FoundMatch(search, tree, child))
457  {
458  result = child;
459  return true;
460  }
461  if (tree->ItemHasChildren(child))
462  {
463  if (RecursiveSearch(search, tree, child, result))
464  return true;
465  }
466  child = tree->GetNextChild(parent, cookie);
467  }
468 
469  return RecursiveSearch(search, tree, FindNext(search, tree, parent), result);
470 }
471 
472 // events
473 
475 {
476  wxTreeCtrl* tree = (wxTreeCtrl*)event.GetEventObject();
477  if (!tree)
478  return;
479 
480  tree->SelectItem(event.GetItem());
481  ShowMenu(tree, event.GetItem(), event.GetPoint());
482 }
483 
485 {
487  if (!tree || !m_Parser)
488  return;
489 
490  wxTreeItemId id = tree->GetSelection();
491  CCTreeCtrlData* ctd = (CCTreeCtrlData*)tree->GetItemData(id);
492  if (ctd)
493  {
494  wxFileName fname;
495  if (event.GetId() == idMenuJumpToImplementation)
496  fname.Assign(ctd->m_Token->GetImplFilename());
497  else
498  fname.Assign(ctd->m_Token->GetFilename());
499 
500  cbProject* project = nullptr;
503  else
504  project = m_NativeParser->GetCurrentProject();
505 
506  wxString base;
507  if (project)
508  {
509  base = project->GetBasePath();
510  NormalizePath(fname, base);
511  }
512  else
513  {
514  const wxArrayString& incDirs = m_Parser->GetIncludeDirs();
515  for (size_t i = 0; i < incDirs.GetCount(); ++i)
516  {
517  if (NormalizePath(fname, incDirs.Item(i)))
518  break;
519  }
520  }
521 
523  if (ed)
524  {
525  int line;
526  if (event.GetId() == idMenuJumpToImplementation)
527  line = ctd->m_Token->m_ImplLine - 1;
528  else
529  line = ctd->m_Token->m_Line - 1;
530 
531  ed->GotoTokenPosition(line, ctd->m_Token->m_Name);
532  }
533  }
534 }
535 /* NOTE (ollydbg#1#05/17/15): This function can directly access to the TokenTree, but I don't see
536  any protector here, do we need one? In the meanwhile, the parserthread may be running, and the
537  TokenTree could be updated. */
539 {
540  wxTreeCtrl* wx_tree = (wxTreeCtrl*)event.GetEventObject();
541  if (!wx_tree || !m_Parser)
542  return;
543 
544  wxTreeItemId id = event.GetItem();
545  CCTreeCtrlData* ctd = (CCTreeCtrlData*)wx_tree->GetItemData(id);
546  if (ctd && ctd->m_Token)
547  {
548  // when user double click on an item, also with CONTROL and SHIFT key pressed, then we
549  // pop up a cc debugging dialog.
551  {
552 // TokenTree* tree = m_Parser->GetTokenTree(); // the one used inside CCDebugInfo
553 
555 
556  CCDebugInfo info(wx_tree, m_Parser, ctd->m_Token);
557  info.ShowModal();
558 
560 
561  return;
562  }
563 
564  // jump to the implementation line only if the token is a function, and has a valid
565  // implementation field
566  bool toImp = false;
567  switch (ctd->m_Token->m_TokenKind)
568  {
569  case tkConstructor:
570  case tkDestructor:
571  case tkFunction:
572  if (ctd->m_Token->m_ImplLine != 0 && !ctd->m_Token->GetImplFilename().IsEmpty())
573  toImp = true;
574  break;
575  case tkNamespace:
576  case tkClass:
577  case tkEnum:
578  case tkTypedef:
579  case tkVariable:
580  case tkEnumerator:
581  case tkMacroDef:
582  case tkMacroUse:
583  case tkAnyContainer:
584  case tkAnyFunction:
585  case tkUndefined:
586  default:
587  break;
588  }
589 
590  wxFileName fname;
591  if (toImp)
592  fname.Assign(ctd->m_Token->GetImplFilename());
593  else
594  fname.Assign(ctd->m_Token->GetFilename());
595 
596  cbProject* project = nullptr;
599  else
600  project = m_NativeParser->GetCurrentProject();
601 
602  wxString base;
603  if (project)
604  {
605  base = project->GetBasePath();
606  NormalizePath(fname, base);
607  }
608  else
609  {
610  const wxArrayString& incDirs = m_Parser->GetIncludeDirs();
611  for (size_t i = 0; i < incDirs.GetCount(); ++i)
612  {
613  if (NormalizePath(fname, incDirs.Item(i)))
614  break;
615  }
616  }
617 
619  if (ed)
620  {
621  // our Token's line is zero based, but Scintilla's one based, so we need to adjust the
622  // line number
623  int line;
624  if (toImp)
625  line = ctd->m_Token->m_ImplLine - 1;
626  else
627  line = ctd->m_Token->m_Line - 1;
628 
629  ed->GotoTokenPosition(line, ctd->m_Token->m_Name);
630  }
631  }
632 }
633 
635 {
637 }
638 
640 {
641  if (m_NativeParser)
643 }
644 
646 {
647  if (!m_Parser)
648  return;
649 
651 
652  if (event.GetId() == idCBViewInheritance)
653  options.showInheritance = event.IsChecked();
654  if (event.GetId() == idCBExpandNS)
655  options.expandNS = event.IsChecked();
656  if (event.GetId() == idCBBottomTree)
657  options.treeMembers = event.IsChecked();
658 
661 }
662 
664 {
665  if (!m_Parser)
666  return;
667 
668  if (event.GetId() == idCBExpandNS)
669  m_Parser->ClassBrowserOptions().expandNS = event.IsChecked();
670 
673 }
674 
676 {
677  int sel = event.GetSelection();
678  if (m_Parser)
679  {
680  BrowserDisplayFilter filter = static_cast<BrowserDisplayFilter>(sel);
681  if (!m_NativeParser->IsParserPerWorkspace() && filter == bdfWorkspace)
682  {
683  cbMessageBox(_("This feature is not supported in combination with\n"
684  "the option \"one parser per whole workspace\"."),
685  _("Information"), wxICON_INFORMATION);
686  filter = bdfProject;
687  XRCCTRL(*this, "cmbView", wxChoice)->SetSelection(filter);
688  }
689 
693  }
694  else
695  {
696  // we have no parser; just write the setting in the configuration
697  Manager::Get()->GetConfigManager(_T("code_completion"))->Write(_T("/browser_display_filter"), sel);
698  CCLogger::Get()->DebugLog(wxT("OnViewScope: No parser available."));
699  }
700 }
701 
703 {
705 }
706 
708 {
709  BrowserSortType bst;
710  if (event.GetId() == idCBSortByAlpabet) bst = bstAlphabet;
711  else if (event.GetId() == idCBSortByKind) bst = bstKind;
712  else if (event.GetId() == idCBSortByScope) bst = bstScope;
713  else if (event.GetId() == idCBSortByLine) bst = bstLine;
714  else bst = bstNone;
715 
716  if (m_Parser)
717  {
721  }
722  else
723  Manager::Get()->GetConfigManager(_T("code_completion"))->Write(_T("/browser_sort_type"), (int)bst);
724 }
725 
727 {
728  wxString search = m_Search->GetValue();
729  if (search.IsEmpty() || !m_Parser)
730  return;
731 
732  TokenTree* tree = m_Parser->GetTokenTree();
733 
734  TokenIdxSet result;
735  size_t count = 0;
736  {
738 
739  count = tree->FindMatches(search, result, false, true);
740 
742  }
743 
744  const Token* token = 0;
745  if (count == 0)
746  {
747  cbMessageBox(_("No matches were found: ") + search,
748  _("Search failed"), wxICON_INFORMATION);
749  return;
750  }
751  else if (count == 1)
752  {
754 
755  token = tree->at(*result.begin());
756 
758  }
759  else if (count > 1)
760  {
761  wxArrayString selections;
762  wxArrayInt int_selections;
763  for (TokenIdxSet::iterator it = result.begin(); it != result.end(); ++it)
764  {
766 
767  const Token* sel = tree->at(*it);
768  if (sel)
769  {
770  selections.Add(sel->DisplayName());
771  int_selections.Add(*it);
772  }
773 
775  }
776  if (selections.GetCount() > 1)
777  {
778  int sel = cbGetSingleChoiceIndex(_("Please make a selection:"), _("Multiple matches"), selections,
779  Manager::Get()->GetAppWindow(), wxSize(400, 400));
780  if (sel == -1)
781  return;
782 
784 
785  token = tree->at(int_selections[sel]);
786 
788  }
789  else if (selections.GetCount() == 1)
790  {
792 
793  // number of selections can be < result.size() due to the if tests, so in case we fall
794  // back on 1 entry no need to show a selection
795  token = tree->at(int_selections[0]);
796 
798  }
799  }
800 
801  // time to "walk" the tree
802  if (token)
803  {
804  // store the search in the combobox
805  if (m_Search->FindString(token->m_Name) == wxNOT_FOUND)
806  m_Search->Append(token->m_Name);
807 
808  if (token->m_ParentIndex == -1 && !(token->m_TokenKind & tkAnyContainer))
809  {
810  // a global non-container: search in special folders only
811  wxTreeItemIdValue cookie;
813  while (res.IsOk())
814  {
816  if (data && (data->m_SpecialFolder & (sfGFuncs | sfGVars | sfPreproc | sfTypedef)))
817  {
818  m_CCTreeCtrl->SelectItem(res);
820  if (srch.IsOk())
821  {
823  return;
824  }
825  }
827  }
828  return;
829  }
830 
831  // example:
832  // search="cou"
833  // token->GetNamespace()="std::"
834  // token->m_Name="cout"
836  wxStringTokenizer tkz(token->GetNamespace(), _T(":"));
837  while (tkz.HasMoreTokens())
838  {
839  wxString part = tkz.GetNextToken();
840  if (!part.IsEmpty())
841  {
842  m_CCTreeCtrl->Expand(start);
843  wxTreeItemId res = FindChild(part, m_CCTreeCtrl, start);
844  if (!res.IsOk())
845  break;
846  start = res;
847  }
848  }
849  // now the actual token
850  m_CCTreeCtrl->Expand(start);
851  m_CCTreeCtrl->SelectItem(start);
852  wxTreeItemId res = FindChild(token->m_Name, m_CCTreeCtrl, start);
853  if (res.IsOk())
854  m_CCTreeCtrl->SelectItem(res);
855  else
856  {
857  // search in bottom tree too
858  res = FindChild(token->m_Name, m_CCTreeCtrlBottom, m_CCTreeCtrlBottom->GetRootItem(), true, true);
859  if (res.IsOk())
861  }
862  }
863 }
864 
865 /* There are several cases:
866  A: If the worker thread is not created yet, just create one, and build the tree.
867  B: If the worker thread is already created
868  B1: the thread is running, then we need to pause it, and re-initialize it and rebuild the tree.
869  B2: if the thread is already paused, then we only need to resume it again.
870 */
872 {
874  return;
875 
876  TRACE(wxT("ClassBrowser: ThreadedBuildTree started."));
877 
878  // create the thread if needed
879  bool thread_needs_run = false;
881  {
884  thread_needs_run = true; // just created, so surely need to run it
885  }
886 
887  if (!thread_needs_run) // this means a worker thread is already created
888  {
889  TRACE(wxT("ClassBrowser: Pausing ClassBrowserBuilderThread..."));
890  }
891 
892  // whether the thread is running or paused, we try to pause the tree
893  // this is an infinite loop, the loop only exists when the thread is actually paused
894  bool thread_needs_resume = false;
895  while ( !thread_needs_run // the thread already created
896  && m_ClassBrowserBuilderThread->IsAlive() // thread is alive: i.e. running or suspended
897  && m_ClassBrowserBuilderThread->IsRunning() // running
898  && !m_ClassBrowserBuilderThread->IsPaused() ) // not paused
899  {
900  thread_needs_resume = true;
902  wxMilliSleep(20); // allow processing
903  }
904 
905  // there are two conditions here:
906  // 1, the thread is newly created, but hasn't run yet
907  // 2, the thread is already created, and we have paused it
908  if (thread_needs_resume) // satisfy the above condition 2
909  {
910  TRACE(wxT("ClassBrowser: ClassBrowserBuilderThread: Paused."));
911  }
912 
913  // initialise it, this function is called from the GUI main thread.
915  m_CCTreeCtrl,
918  activeProject,
921  idThreadEvent);
922 
923  // when m_ClassBrowserSemaphore.Post(), the worker thread has chance to build the tree
924  if (thread_needs_run)
925  {
926  TRACE(wxT("ClassBrowser: Run ClassBrowserBuilderThread."));
927  m_ClassBrowserBuilderThread->Run(); // run newly created thread
928  m_ClassBrowserSemaphore.Post(); // ...and allow BuildTree
929  }
930  else if (thread_needs_resume) // no resume without run ;-)
931  {
934  {
935  TRACE(wxT("ClassBrowser: Resume ClassBrowserBuilderThread."));
936  m_ClassBrowserBuilderThread->Resume(); // resume existing thread
937  m_ClassBrowserSemaphore.Post(); // ...and allow BuildTree
938  }
939  }
940 }
941 
943 {
946 #ifndef CC_NO_COLLAPSE_ITEM
947  event.Allow();
948 #endif // CC_NO_COLLAPSE_ITEM
949 }
950 
951 #ifndef CC_NO_COLLAPSE_ITEM
953 {
956  event.Allow();
957 }
958 #endif // CC_NO_COLLAPSE_ITEM
959 
961 {
962  if (!::wxIsMainThread())
963  return; // just to be sure it called from main thread
964 
967 #ifndef CC_NO_COLLAPSE_ITEM
968  event.Allow();
969 #endif // CC_NO_COLLAPSE_ITEM
970 }
971 
973 {
975  static_cast<ClassBrowserBuilderThread::EThreadEvent>(event.GetInt());
976 
977  switch (query)
978  {
980  {
983  break;
984  }
986  {
987  CCLogger::Get()->DebugLog(wxT("ClassBrowser::OnThreadEvent(): Updating class browser..."));
988  break;
989  }
991  {
992  CCLogger::Get()->DebugLog(wxT("ClassBrowser::OnThreadEvent(): Class browser updated."));
993  break;
994  }
995  default:
996  break;
997  }
998 }
wxTreeCtrl * m_TreeForPopupMenu
remember the context menu is created from which tree control, the upper or the bottom ...
Definition: classbrowser.h:201
int idCBSortByAlpabet
virtual wxTreeItemId GetNextChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
wxString AfterLast(wxUniChar ch) const
virtual BrowserOptions & ClassBrowserOptions()
Definition: parser_base.h:175
destructor class member function
Definition: token.h:51
EThreadEvent
the builder threads&#39; event sent to the GUI(class browser window)
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
BrowserSortType
specify the sort order of the symbol tree nodes
Definition: parser_base.h:49
variable
Definition: token.h:57
namespace
Definition: token.h:34
void OnViewScope(wxCommandEvent &event)
the view scope choice has changed, user can switch between view everything, view a single file...
int m_ParentIndex
Parent Token index.
Definition: token.h:265
int wxNewId()
int idCBBottomTree
constructor class member function
Definition: token.h:48
wxSemaphore m_ClassBrowserSemaphore
semaphore to synchronize the GUI(class browser) and the tree builder thread, when the GUI post the se...
Definition: classbrowser.h:215
class or struct
Definition: token.h:37
void UpdateSash()
update the position sash bar between top tree and the bottom tree, the position (percentage) of the t...
int idCBNoSort
virtual void WriteOptions()
write Parse options to configure file
Definition: parser_base.h:171
virtual wxTreeItemId GetItemParent(const wxTreeItemId &item) const
ClassBrowserBuilderThread * m_ClassBrowserBuilderThread
a wxThread used to build the wxTreeCtrl for the top and bottom in the class(symbol) browser because i...
Definition: classbrowser.h:221
Token * at(int idx)
Definition: tokentree.h:51
void Init(NativeParser *np, CCTreeCtrl *treeTop, CCTreeCtrl *treeBottom, const wxString &active_filename, void *user_data, const BrowserOptions &bo, TokenTree *tt, int idThreadEvent)
void Assign(const wxFileName &filepath)
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
int ReadInt(const wxString &name, int defaultVal=0)
static CCLogger * Get()
Definition: cclogger.cpp:60
bool IsOk() const
virtual bool SplitHorizontally(wxWindow *window1, wxWindow *window2, int sashPosition=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
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
bool IsRunning() const
int idCBExpandNS
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
wxString Lower() const
typedef, note typedefs are stored as classes inheriting from the typedef&#39;d type, this takes advantage...
Definition: token.h:45
static bool IsAppShuttingDown()
Definition: manager.cpp:333
int idMenuDebugSmartSense
CCTreeCtrl * m_CCTreeCtrl
the top(main) level tree control, see above diagram for details
Definition: classbrowser.h:195
void OnThreadEvent(wxCommandEvent &event)
class browser builder thread will send notification event to the parent, this is the event handler fu...
container like tokens, those tokens can have children tokens
Definition: token.h:70
void OnDebugSmartSense(wxCommandEvent &event)
whether print the debug log message
wxTreeItemId FindNext(const wxString &search, wxTreeCtrl *tree, const wxTreeItemId &start)
get the next item of the "start" item, if no next item in the current level, go up one level ...
wxString GetFilename() const
get a full path of the file which contains the current Token
Definition: token.cpp:185
bool GotoTokenPosition(int line, const wxString &tokenName)
Move the caret at the specified line.
Definition: cbeditor.cpp:2240
int idMenuForceReparse
#define wxTE_PROCESS_ENTER
DLLIMPORT bool NormalizePath(wxFileName &f, const wxString &base)
Definition: globals.cpp:942
virtual wxTreeItemId GetSelection() const
bool wxIsMainThread()
SpecialFolder m_SpecialFolder
the node&#39;s kind, it could be "root", "normal token",
Definition: cctreectrl.h:52
a container class to hold all the Tokens getting from parsing stage
Definition: tokentree.h:37
bool showInheritance
whether the base class or derive class information is shown as a child node default: false ...
Definition: parser_base.h:72
worker thread to build the symbol browser tree controls(both the top tree and the bottom tree) When t...
alphabetical
Definition: parser_base.h:52
wxMenuItem * Append(int id, const wxString &item=wxEmptyString, const wxString &helpString=wxEmptyString, wxItemKind kind=wxITEM_NORMAL)
DLLIMPORT int cbGetSingleChoiceIndex(const wxString &message, const wxString &caption, const wxArrayString &choices, wxWindow *parent=NULL, const wxSize &size=wxSize(300, 300), int initialSelection=0)
Definition: globals.cpp:1427
void UpdateClassBrowserView(bool checkHeaderSwap=false)
update or refresh the symbol browser trees
#define _T(string)
unsigned int m_Line
Line index where the token was met, which is 1 based.
Definition: token.h:210
the thread is starting to (re)build the tree
wxString BeforeLast(wxUniChar ch, wxString *rest=NULL) const
wxThreadError Create(unsigned int stackSize=0)
ParserBase * m_Parser
a pointer to the associated parser object
Definition: classbrowser.h:207
bool RecursiveSearch(const wxString &search, wxTreeCtrl *tree, const wxTreeItemId &parent, wxTreeItemId &result)
find an item whose item name matches the "search" key string in the sub-tree
void ThreadedBuildTree(cbProject *activeProject)
create a thread to update the symbol tree, if the thread is already created, just pause and resume th...
#define wxICON_INFORMATION
virtual wxTreeItemData * GetItemData(const wxTreeItemId &item) const
wxString GetNamespace() const
get a literal string presentation of the namespace.
Definition: token.cpp:253
virtual wxString GetItemText(const wxTreeItemId &item) const
cbProject * GetCurrentProject()
Get current project by active editor or just return active project.
#define wxT(string)
int idMenuJumpToDeclaration
#define wxNOT_FOUND
wxString DisplayName() const
a short simple string to show the token information, this usually generate for show the tip message w...
Definition: token.cpp:80
size_t GetMenuItemCount() const
void OnTreeItemDoubleClick(wxTreeEvent &event)
handler for the mouse double click on a tree item, we usually make a jump to the associated token&#39;s p...
void DebugLog(const wxString &msg)
Definition: cclogger.cpp:107
void RequestTermination(bool terminate=true)
ask the worker thread to die Called from external: when the class browser window get destroyed ...
wxThreadError Pause()
wxSemaError Post()
wxPanel * LoadPanel(wxWindow *parent, const wxString &name)
wxTreeItemId GetItem() const
int idCBSortByLine
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
NativeParser * m_NativeParser
the pointer to parser manager object
Definition: classbrowser.h:192
void OnForceReparse(wxCommandEvent &event)
reparse the current project
cbProject * GetProjectByParser(ParserBase *parser)
return the C::B project associated with Parser pointer
bool expandNS
whether a namespaces node is auto-expand auto-expand means the child of the namespace is automaticall...
Definition: parser_base.h:79
const wxArrayString & GetIncludeDirs() const
Definition: parser_base.h:160
Tree data associate with the symbol tree item.
Definition: parser.h:71
virtual wxTreeItemId GetFirstChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
void Write(const wxString &name, const wxString &value, bool ignoreEmpty=false)
virtual const wxString & GetFilename() const
Get the editor&#39;s filename (if applicable).
Definition: editorbase.h:45
wxString m_ActiveFilename
source file name of active editor, used for filtering(if view option is Current file&#39;s symbols) ...
Definition: classbrowser.h:210
void OnCBViewMode(wxCommandEvent &event)
user change the view mode (View Inheritance or View the bottom tree)
CCTreeCtrl * m_CCTreeCtrlBottom
the bottom tree control, mainly used to show the member variable and member functions ...
Definition: classbrowser.h:198
Represents a Code::Blocks project.
Definition: cbproject.h:96
display symbols of current project
Definition: parser_base.h:44
int idCBSortByScope
void OnTreeItemRightClick(wxTreeEvent &event)
show a context menu
void Check(int id, bool check)
a symbol found in the parsed files, it can be many kinds, such as a variable, a class and so on...
Definition: token.h:82
void OnRefreshTree(wxCommandEvent &event)
force rebuilding the tree
void OnJumpTo(wxCommandEvent &event)
the handler for jump to declaration or jump to definition menu item
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
display symbols of current file
Definition: parser_base.h:43
Token * m_Token
a pointer to the associated Token instance in the TokenTree
Definition: cctreectrl.h:44
wxThreadError Resume()
virtual void SelectItem(const wxTreeItemId &item, bool select=true)
ExitCode Wait(wxThreadWait flags=wxTHREAD_WAIT_BLOCK)
void OnSetSortType(wxCommandEvent &event)
sort type changed
Options for the symbol browser, this specify how the symbol browser will shown.
Definition: parser_base.h:59
cbEditor * GetBuiltinActiveEditor()
Definition: editormanager.h:95
void OnCBExpandNS(wxCommandEvent &event)
whether automatically expand the namespace option switch
bool IsSameAs(const wxString &s, bool caseSensitive=true) const
wxMenuItem * AppendSeparator()
static wxColour GetColour(wxSystemColour index)
wxString & Item(size_t nIndex)
bool Unsplit(wxWindow *toRemove=NULL)
virtual wxString GetBasePath() const
Read the target&#39;s base path, e.g. if GetFilename() returns "/usr/local/bin/xxx", base path will retur...
wxEventType wxEVT_COMMAND_ENTER
#define CC_LOCKER_TRACK_TT_MTX_UNLOCK(M)
Definition: cclogger.h:165
const wxStringCharType * wx_str() const
virtual int ShowModal()
void ReparseCurrentProject()
re-parse the active Parser (the project associated with m_Parser member variable
wxString wxEmptyString
bool IsAlive() const
int idCBSortByKind
bool s_DebugSmartSense
if this option is enabled, there will be many log messages when doing semantic match ...
symbol browser panel is shown in the Management panel besides projects browser panel.
Definition: classbrowser.h:53
void CollapseItem(wxTreeItemId item)
remove the children of the tree item Called from external, BuildTree(), RemoveInvalidNodes(): ...
cbEditor * Open(const wxString &filename, int pos=0, ProjectFile *data=nullptr)
const wxString & _(const wxString &string)
void ShowMenu(wxTreeCtrl *tree, wxTreeItemId id, const wxPoint &pt)
build and show a context menu when user right click on the tree item "id"
#define CC_LOCKER_TRACK_TT_MTX_LOCK(M)
Definition: cclogger.h:159
wxTreeItemId FindChild(const wxString &search, wxTreeCtrl *tree, const wxTreeItemId &start, bool recurse=false, bool partialMatch=false)
get a child of the parent item, which matches the "search" key
wxArray< int > wxArrayInt
Token * GetToken()
Definition: parser.h:75
NativeParser class is just like a manager class to control Parser objects.
Definition: nativeparser.h:55
virtual void Expand(const wxTreeItemId &item)
code like order
Definition: parser_base.h:55
Actual data stored with each node in the symbol tree.
Definition: cctreectrl.h:37
undefined or just "all"
Definition: token.h:76
BrowserDisplayFilter displayFilter
token filter option
Definition: parser_base.h:88
enum
Definition: token.h:40
A file editor.
Definition: cbeditor.h:43
bool IsEmpty() const
BrowserDisplayFilter
specify the scope of the shown symbols
Definition: parser_base.h:40
void Clear()
bool treeMembers
show members in the bottom tree.
Definition: parser_base.h:82
virtual wxTreeItemId GetNextSibling(const wxTreeItemId &item) const
enumerator
Definition: token.h:60
any kind of functions
Definition: token.h:73
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
void wxMilliSleep(unsigned long milliseconds)
void OnTreeItemExpanding(wxTreeEvent &event)
expanding one node of top tree
general function, not constructor nor destructor
Definition: token.h:54
size_t Add(const wxString &str, size_t copies=1)
void OnTreeItemCollapsing(wxTreeEvent &event)
collapse one node of the top tree
BrowserSortType sortType
token sort option in the tree default: bstKind
Definition: parser_base.h:93
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
virtual ~ClassBrowser()
class destructor
wxThreadError Run()
virtual wxTreeItemId GetRootItem() const
public, protected, private
Definition: parser_base.h:54
bool FoundMatch(const wxString &search, wxTreeCtrl *tree, const wxTreeItemId &item)
string compare between the search and the token&#39;s name associated with item
size_t FindMatches(const wxString &query, TokenIdxSet &result, bool caseSensitive, bool is_prefix, TokenKind kindMask=tkUndefined)
find a collection of matched tokens
Definition: tokentree.cpp:266
size_t GetCount() const
int Find(wxUniChar ch, bool fromEnd=false) const
virtual TokenTree * GetTokenTree() const
static wxXmlResource * Get()
int idThreadEvent
the event ID which will be sent from worker thread to ClassBrowser
int idCBViewInheritance
macro definition, such as: #define AAA(x,y) f(x,y), where AAA is a token of tkMacroDef ...
Definition: token.h:63
wxString GetImplFilename() const
get a full path of the file which contains the function implementation.
Definition: token.cpp:192
bool IsPaused() const
void ExpandItem(wxTreeItemId item)
construct the children of the tree item Called from external, BuildTree():
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
bool IsParserPerWorkspace() const
Return true if use one Parser per whole workspace.
Definition: nativeparser.h:105
class, function, macros
Definition: parser_base.h:53
#define NULL
Definition: prefix.cpp:59
bool wxGetKeyState(wxKeyCode key)
#define TRACE(format, args...)
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
virtual bool ItemHasChildren(const wxTreeItemId &item) const
int idMenuJumpToImplementation
void OnSearch(wxCommandEvent &event)
when user try to search a word in the symbols tree
int idMenuRefreshTree
void SetParser(ParserBase *parser)
Set the Parser object associated with the class browser.
the usage of the macro, for example: AAA(1,2)
Definition: token.h:66
wxMenuItem * AppendCheckItem(int id, const wxString &item, const wxString &help=wxEmptyString)
void OnTreeSelChanged(wxTreeEvent &event)
item selection changed in the top tree