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
11
#include "classbrowserbuilderthread.h"
14
#include <projectmanager.h>
15
#include <cbproject.h>
17
#include <wx/settings.h>
22
namespace compatibility { typedef TernaryCondTypedef<wxMinimumVersion<2,5>::eval, wxTreeItemIdValue, long int>::eval tree_cookie_t; };
24
ClassBrowserBuilderThread::ClassBrowserBuilderThread(wxSemaphore& sem, ClassBrowserBuilderThread** threadVar)
25
: wxThread(wxTHREAD_JOINABLE),
33
m_ppThreadVar(threadVar)
38
ClassBrowserBuilderThread::~ClassBrowserBuilderThread()
43
void ClassBrowserBuilderThread::Init(Parser* parser,
45
wxTreeCtrl* treeBottom,
46
const wxString& active_filename,
47
void* user_data, // active project
48
const BrowserOptions& options,
52
wxMutexLocker lock(m_BuildMutex);
55
m_pTreeBottom = treeBottom;
56
m_ActiveFilename = active_filename;
57
m_pUserData = user_data;
61
m_CurrentFileSet.clear();
62
m_CurrentTokenSet.clear();
64
TokensTree* tree = m_pParser->GetTokens();
65
// fill filter set for current-file-filter
66
if (m_Options.displayFilter == bdfFile && !m_ActiveFilename.IsEmpty())
68
// m_ActiveFilename is the full filename up to the extension dot. No extension though.
69
// get all filenames' indices matching our mask
70
tree->m_FilenamesMap.FindMatches(m_ActiveFilename, m_CurrentFileSet, true, true);
73
if(m_Options.displayFilter == bdfProject && (user_data != 0))
75
cbProject* prj = (cbProject*)user_data;
76
for(int i = 0; i < prj->GetFilesCount(); i++)
78
ProjectFile* curfile = prj->GetFile(i);
81
wxString filename = curfile->file.GetFullPath();
82
size_t fileIdx = tree->m_FilenamesMap.GetItemNo(filename);
85
m_CurrentFileSet.insert(fileIdx);
90
if (!m_CurrentFileSet.empty())
92
m_CurrentTokenSet.clear();
93
m_CurrentGlobalTokensSet.clear();
94
for(TokenFilesSet::iterator it = m_CurrentFileSet.begin();it != m_CurrentFileSet.end(); it++)
96
TokenIdxSet* curset = &(tree->m_FilesMap[*it]);
97
for(TokenIdxSet::iterator it2 = curset->begin(); it2 != curset->end(); it2++)
99
Token* curtoken = tree->at(*it2);
102
m_CurrentTokenSet.insert(*it2);
103
if(curtoken->m_ParentIndex == -1)
104
m_CurrentGlobalTokensSet.insert(*it2);
116
void* ClassBrowserBuilderThread::Entry()
118
while (!TestDestroy() && !Manager::IsAppShuttingDown())
120
// wait until the classbrowser signals
122
// Manager::Get()->GetLogManager()->DebugLog(F(_T(" - - - - - -")));
124
if (TestDestroy() || Manager::IsAppShuttingDown())
129
// this code (PART 1/2) seems to be good on linux
130
// because of it the libcairo crash on dualcore processors
131
// is gone, but on windows it has very bad influence,
132
// henceforth the ifdef guard
133
// the questions remains if it is the correct solution
134
if(!::wxIsMainThread())
142
if (TestDestroy() || Manager::IsAppShuttingDown())
146
if(!::wxIsMainThread())
154
m_pTreeTop->Freeze();
155
ExpandNamespaces(m_pTreeTop->GetRootItem());
160
// this code (PART 2/2) seems to be good on linux
161
// because of it the libcairo crash on dualcore processors
162
// is gone, but on windows it has very bad influence,
163
// henceforth the ifdef guard
164
// the questions remains if it is the correct solution
165
if(!::wxIsMainThread())
177
*m_ppThreadVar = 0;*/
181
void ClassBrowserBuilderThread::ExpandNamespaces(wxTreeItemId node)
183
if (!m_Options.expandNS || !node.IsOk())
186
wxTreeItemIdValue enumerationCookie;
187
wxTreeItemId existing = m_pTreeTop->GetFirstChild(node, enumerationCookie);
188
while (existing.IsOk())
190
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(existing);
191
if (data && data->m_pToken && data->m_pToken->m_TokenKind == tkNamespace)
193
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Auto-expanding: ") + data->m_pToken->m_Name));
194
m_pTreeTop->Expand(existing);
195
ExpandNamespaces(existing); // recurse
198
existing = m_pTreeTop->GetNextSibling(existing);
202
void ClassBrowserBuilderThread::BuildTree()
204
if (Manager::IsAppShuttingDown())
206
// wxMutexLocker lock(m_BuildMutex);
208
m_pTreeTop->SetImageList(m_pParser->GetImageList());
209
m_pTreeBottom->SetImageList(m_pParser->GetImageList());
211
wxTreeItemId root = m_pTreeTop->GetRootItem();
214
root = m_pTreeTop->AddRoot(_("Symbols"), PARSER_IMG_SYMBOLS_FOLDER, PARSER_IMG_SYMBOLS_FOLDER, new CBTreeData(sfRoot));
215
m_pTreeTop->SetItemHasChildren(root);
219
m_pTreeBottom->Hide();
220
m_pTreeTop->Freeze();
221
m_pTreeBottom->Freeze();
223
RemoveInvalidNodes(m_pTreeTop, root);
224
RemoveInvalidNodes(m_pTreeBottom, m_pTreeBottom->GetRootItem());
226
if (!TestDestroy() && !Manager::IsAppShuttingDown())
228
// the tree is completely dynamic: it is populated when a node expands/collapses.
229
// so, by expanding the root node, we already instruct it to fill the top level :)
231
// this technique makes it really fast to draw (we only draw what's expanded) and
232
// has very minimum memory overhead since it contains as few items as possible.
233
// plus, it doesn't flicker because we 're not emptying it and re-creating it each time ;)
234
m_pTreeTop->Expand(root);
238
// seems like the "expand" event comes too late in wxGTK,
239
// so make it happen now
244
m_pTreeBottom->Thaw();
246
m_pTreeBottom->Show();
249
SelectNode(m_pTreeTop->GetSelection()); // refresh selection
253
void ClassBrowserBuilderThread::RemoveInvalidNodes(wxTreeCtrl* tree, wxTreeItemId parent)
255
if (TestDestroy() || Manager::IsAppShuttingDown() || (!(parent.IsOk())))
258
// recursively enters all existing nodes and deletes the node if the token it references
259
// is invalid (i.e. m_pTokens->at() != token_in_data)
261
// we 'll loop backwards so we can delete nodes without problems
262
wxTreeItemId existing = tree->GetLastChild(parent);
263
wxTreeItemId root = tree->GetRootItem();
264
while (parent.IsOk() && existing.IsOk())
266
bool removeCurrent = false;
267
bool hasChildren = tree->ItemHasChildren(existing);
268
CBTreeData* data = (CBTreeData*)(tree->GetItemData(existing));
270
if (tree == m_pTreeBottom)
271
removeCurrent = true;
272
else if (data && data->m_pToken)
274
if (m_pTokens->at(data->m_TokenIndex) != data->m_pToken ||
275
(data->m_Ticket && data->m_Ticket != data->m_pToken->GetTicket()) ||
276
!TokenMatchesFilter(data->m_pToken))
278
removeCurrent = true;
284
tree->DeleteChildren(existing);
285
wxTreeItemId next = tree->GetPrevSibling(existing);
286
if(!next.IsOk() && parent.IsOk() && tree == m_pTreeTop && tree->GetChildrenCount(parent, false) == 1 )
288
CollapseItem(parent);
289
// tree->SetItemHasChildren(parent, false);
293
tree->Delete(existing);
300
RemoveInvalidNodes(tree, existing); // recurse
303
existing = tree->GetPrevSibling(existing);
307
void ClassBrowserBuilderThread::RemoveInvalidNodes(wxTreeCtrl* tree, wxTreeItemId parent)
309
if (TestDestroy() || Manager::IsAppShuttingDown() || (!(parent.IsOk())))
312
// recursively enters all existing nodes and deletes the node if the token it references
313
// is invalid (i.e. m_pTokens->at() != token_in_data)
315
// we 'll loop backwards so we can delete nodes without problems
316
wxTreeItemId existing = tree->GetLastChild(parent);
317
while (existing.IsOk())
320
if (tree->ItemHasChildren(existing))
321
RemoveInvalidNodes(tree, existing);
323
CBTreeData* data = (CBTreeData*)tree->GetItemData(existing);
324
if (data && data->m_pToken)
326
if (m_pTokens->at(data->m_TokenIndex) != data->m_pToken ||
327
data->m_TokenKind != data->m_pToken->m_TokenKind || // need to compare kinds: the token index might have been reused...
328
data->m_TokenName != data->m_pToken->m_Name || // same for the token name
329
!TokenMatchesFilter(data->m_pToken))
331
// keep parent and set flag if this is the last child of parent
332
wxTreeItemId parent = tree->GetItemParent(existing);
333
bool isLastChild = tree->GetChildrenCount(parent) == 1;
334
// we have to do this in two steps: first collapse and then set haschildren to false
335
if (isLastChild && parent.IsOk() && tree == m_pTreeTop)
337
CollapseItem(parent);
342
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Item %s is invalid"), tree->GetItemText(existing).c_str()));
343
wxTreeItemId next = tree->GetPrevSibling(existing);
344
tree->Delete(existing);
348
// if this was the last child of its parent, collapse the parent
350
// tree->SetItemHasChildren(parent, false);
356
existing = tree->GetPrevSibling(existing);
359
// if (parent != tree->GetRootItem() && tree->GetChildrenCount(parent) == 0)
360
// tree->Delete(parent);
363
wxTreeItemId ClassBrowserBuilderThread::AddNodeIfNotThere(wxTreeCtrl* tree, wxTreeItemId parent, const wxString& name, int imgIndex, CBTreeData* data, bool sorted)
365
sorted = sorted & tree == m_pTreeTop && data; // sorting only for the top tree
366
SpecialFolder new_type = data->m_SpecialFolder;
367
bool newIsNamespace = data->m_TokenKind == tkNamespace;
369
compatibility::tree_cookie_t cookie = 0;
371
wxTreeItemId insert_after; // node to insert after; we 'll be looping all children so we might as well sort at the same time
372
wxTreeItemId existing = tree->GetFirstChild(parent, cookie);
375
wxString itemText = tree->GetItemText(existing);
376
if (itemText == name)
378
// update the existing node's image indices and user-data.
379
// it's not possible to have the same token name more than once
380
// under the same namespace anyway. if we do, there's a bug in the parser :(
381
tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Normal);
382
tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Selected);
383
delete tree->GetItemData(existing); // make Valgrind happy
384
tree->SetItemData(existing, data);
391
CBTreeData* existing_data = (CBTreeData*)tree->GetItemData(existing);
394
SpecialFolder existing_type = existing_data->m_SpecialFolder;
396
// first go special folders
397
if ((existing_type & (sfGFuncs | sfGVars | sfPreproc | sfTypedef)) &&
398
!(new_type & (sfGFuncs | sfGVars | sfPreproc | sfTypedef)))
400
insert_after = existing;
402
// then go namespaces, alphabetically
403
else if (newIsNamespace &&
404
existing_data->m_TokenKind == tkNamespace &&
405
name.CompareTo(itemText, wxString::ignoreCase) >= 0)
407
insert_after = existing;
409
// then everything else, alphabetically
410
else if (!newIsNamespace &&
411
(existing_data->m_TokenKind == tkNamespace ||
412
name.CompareTo(itemText, wxString::ignoreCase) >= 0))
414
insert_after = existing;
418
existing = tree->GetNextChild(parent, cookie);
422
existing = tree->InsertItem(parent, insert_after, name, imgIndex, imgIndex, data);
424
existing = tree->AppendItem(parent, name, imgIndex, imgIndex, data);
428
bool ClassBrowserBuilderThread::AddChildrenOf(wxTreeCtrl* tree, wxTreeItemId parent, int parentTokenIdx, int tokenKindMask)
430
if (TestDestroy() || Manager::IsAppShuttingDown())
433
Token* parentToken = 0;
434
TokenIdxSet::iterator it;
435
TokenIdxSet::iterator it_end;
437
if (parentTokenIdx == -1)
439
if(m_Options.displayFilter == bdfWorkspace)
441
it = m_pTokens->m_GlobalNameSpace.begin();
442
it_end = m_pTokens->m_GlobalNameSpace.end();
446
it = m_CurrentGlobalTokensSet.begin();
447
it_end = m_CurrentGlobalTokensSet.end();
452
parentToken = m_pTokens->at(parentTokenIdx);
455
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Token not found?!?")));
458
it = parentToken->m_Children.begin();
459
it_end = parentToken->m_Children.end();
462
return AddNodes(tree, parent, it, it_end, tokenKindMask);
465
bool ClassBrowserBuilderThread::AddAncestorsOf(wxTreeCtrl* tree, wxTreeItemId parent, int tokenIdx)
467
if (TestDestroy() || Manager::IsAppShuttingDown())
470
Token* token = m_pTokens->at(tokenIdx);
474
return AddNodes(tree, parent, token->m_DirectAncestors.begin(), token->m_DirectAncestors.end(), tkClass | tkTypedef, true);
477
bool ClassBrowserBuilderThread::AddDescendantsOf(wxTreeCtrl* tree, wxTreeItemId parent, int tokenIdx, bool allowInheritance)
479
if (TestDestroy() || Manager::IsAppShuttingDown())
482
Token* token = m_pTokens->at(tokenIdx);
486
bool inh = m_Options.showInheritance;
487
m_Options.showInheritance = allowInheritance;
489
bool ret = AddNodes(tree, parent, token->m_Descendants.begin(), token->m_Descendants.end(), tkClass | tkTypedef, true);
491
m_Options.showInheritance = inh;
495
bool ClassBrowserBuilderThread::AddNodes(wxTreeCtrl* tree, wxTreeItemId parent, TokenIdxSet::iterator start, TokenIdxSet::iterator end, int tokenKindMask, bool allowGlobals)
498
set<unsigned long, less<unsigned long> > tickets;
500
// Build temporary list of Token tickets - if the token's ticket is present
501
// among the parent node's children, it's a dupe, and we'll skip it.
502
if(parent.IsOk() && tree == m_pTreeTop)
504
wxTreeItemIdValue cookie;
505
wxTreeItemId curchild = tree->GetFirstChild(parent,cookie);
506
while(curchild.IsOk())
508
CBTreeData* data = (CBTreeData*)(tree->GetItemData(curchild));
509
curchild = tree->GetNextSibling(curchild);
510
if(data && data->m_Ticket)
511
tickets.insert(data->m_Ticket);
515
for ( ; start != end; ++start)
517
Token* token = m_pTokens->at(*start);
519
(token->m_TokenKind & tokenKindMask) &&
520
(allowGlobals || token->m_IsLocal) &&
521
TokenMatchesFilter(token))
523
if(tree == m_pTreeTop && tickets.find(token->GetTicket()) != tickets.end())
526
int img = m_pParser->GetTokenKindImage(token);
528
wxString str = token->m_Name;
529
if (token->m_TokenKind == tkFunction || token->m_TokenKind == tkConstructor || token->m_TokenKind == tkDestructor)
530
str << token->m_Args;
531
if (!token->m_ActualType.IsEmpty())
532
str = str + _T(" : ") + token->m_ActualType;
534
if (tree == m_pTreeTop)
536
wxTreeItemId child = AddNodeIfNotThere(tree, parent, str, img, new CBTreeData(sfToken, token, tokenKindMask));
537
// mark as expanding if it is a container
538
if (token->m_TokenKind == tkClass)
539
tree->SetItemHasChildren(child, m_Options.showInheritance || TokenContainsChildrenOfKind(token, tkClass | tkNamespace | tkEnum));
540
else if (token->m_TokenKind & (tkNamespace | tkEnum))
541
tree->SetItemHasChildren(child, TokenContainsChildrenOfKind(token, tkClass | tkNamespace | tkEnum));
543
else // the bottom tree needs no checks
544
tree->AppendItem(parent, str, img, img, new CBTreeData(sfToken, token));
547
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Sorting...")));
548
if (tree == m_pTreeBottom) // only sort alphabetically the bottom tree
549
tree->SortChildren(parent);
550
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Added %d nodes"), count));
554
bool ClassBrowserBuilderThread::TokenMatchesFilter(Token* token)
559
if (m_Options.displayFilter == bdfWorkspace)
562
if (m_Options.displayFilter == bdfFile && !m_CurrentTokenSet.empty())
564
if (m_CurrentTokenSet.find(token->GetSelf()) != m_CurrentTokenSet.end())
567
// we got to check all children of this token (recursively)
568
// to see if any of them matches the filter...
569
for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
571
if (TokenMatchesFilter(m_pTokens->at(*it)))
575
else if (m_Options.displayFilter == bdfProject && m_pUserData)
577
return token->m_pUserData == m_pUserData;
583
bool ClassBrowserBuilderThread::TokenContainsChildrenOfKind(Token* token, int kind)
587
TokensTree* tt = token->GetTree();
588
for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
590
Token* child = tt->at(*it);
591
if (child->m_TokenKind & kind)
597
void ClassBrowserBuilderThread::SelectNode(wxTreeItemId node)
599
if (TestDestroy() || Manager::IsAppShuttingDown() || (!(node.IsOk())))
602
m_pTreeBottom->Freeze();
603
wxTreeItemId root = m_pTreeBottom->GetRootItem();
605
root = m_pTreeBottom->AddRoot(_T("Members")); // not visible, so don't translate
607
m_pTreeBottom->DeleteChildren(root);
608
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(node);
611
switch (data->m_SpecialFolder)
613
case sfGFuncs: AddChildrenOf(m_pTreeBottom, root, -1, tkFunction); break;
614
case sfGVars: AddChildrenOf(m_pTreeBottom, root, -1, tkVariable); break;
615
case sfPreproc: AddChildrenOf(m_pTreeBottom, root, -1, tkPreprocessor); break;
616
case sfTypedef: AddChildrenOf(m_pTreeBottom, root, -1, tkTypedef); break;
619
// add all children, except containers
620
AddChildrenOf(m_pTreeBottom, root, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum));
626
m_pTreeBottom->Thaw();
629
// checks if there are respective children and colors the nodes
630
bool ClassBrowserBuilderThread::CreateSpecialFolders(wxTreeCtrl* tree, wxTreeItemId parent)
637
// loop all tokens in global namespace and see if we have matches
638
TokensTree* tt = m_pParser->GetTokens();
639
for (TokenIdxSet::iterator it = tt->m_GlobalNameSpace.begin(); it != tt->m_GlobalNameSpace.end(); ++it)
641
Token* token = tt->at(*it);
642
if (token && token->m_IsLocal && TokenMatchesFilter(token))
644
if (!hasGF && token->m_TokenKind == tkFunction)
646
else if (!hasGV && token->m_TokenKind == tkVariable)
648
else if (!hasGP && token->m_TokenKind == tkPreprocessor)
650
else if (!hasTD && token->m_TokenKind == tkTypedef)
654
if (hasGF && hasGV && hasGP && hasTD)
655
break; // we have everything, stop iterating...
658
wxTreeItemId gfuncs = AddNodeIfNotThere(m_pTreeTop, parent, _("Global functions"), PARSER_IMG_OTHERS_FOLDER, new CBTreeData(sfGFuncs, 0, tkFunction, -1));
659
wxTreeItemId tdef = AddNodeIfNotThere(m_pTreeTop, parent, _("Global typedefs"), PARSER_IMG_TYPEDEF_FOLDER, new CBTreeData(sfTypedef, 0, tkTypedef, -1));
660
wxTreeItemId gvars = AddNodeIfNotThere(m_pTreeTop, parent, _("Global variables"), PARSER_IMG_OTHERS_FOLDER, new CBTreeData(sfGVars, 0, tkVariable, -1));
661
wxTreeItemId preproc = AddNodeIfNotThere(m_pTreeTop, parent, _("Preprocessor symbols"), PARSER_IMG_PREPROC_FOLDER, new CBTreeData(sfPreproc, 0, tkPreprocessor, -1));
663
wxColour black = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
664
wxColour grey = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
666
tree->SetItemTextColour(gfuncs, hasGF ? black : grey);
667
tree->SetItemTextColour(gvars, hasGV ? black : grey);
668
tree->SetItemTextColour(preproc, hasGP ? black : grey);
669
tree->SetItemTextColour(tdef, hasTD ? black : grey);
671
return hasGF || hasGV || hasGP || hasTD;
674
void ClassBrowserBuilderThread::ExpandItem(wxTreeItemId item)
676
if (TestDestroy() || Manager::IsAppShuttingDown())
679
wxMutexLocker lock(m_BuildMutex);
680
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(item);
683
switch (data->m_SpecialFolder)
687
CreateSpecialFolders(m_pTreeTop, item);
688
AddChildrenOf(m_pTreeTop, item, -1, ~(tkFunction | tkVariable | tkPreprocessor | tkTypedef));
691
case sfBase: AddAncestorsOf(m_pTreeTop, item, data->m_pToken->GetSelf()); break;
692
case sfDerived: AddDescendantsOf(m_pTreeTop, item, data->m_pToken->GetSelf(), false); break;
696
switch (data->m_pToken->m_TokenKind)
700
// add base and derived classes folders
701
if (m_Options.showInheritance)
703
wxTreeItemId base = AddNodeIfNotThere(m_pTreeTop, item, _("Base classes"), PARSER_IMG_CLASS_FOLDER, new CBTreeData(sfBase, data->m_pToken, tkClass, data->m_pToken->GetSelf()));
704
if (!data->m_pToken->m_DirectAncestors.empty())
705
m_pTreeTop->SetItemHasChildren(base);
706
wxTreeItemId derived = AddNodeIfNotThere(m_pTreeTop, item, _("Derived classes"), PARSER_IMG_CLASS_FOLDER, new CBTreeData(sfDerived, data->m_pToken, tkClass, data->m_pToken->GetSelf()));
707
if (!data->m_pToken->m_Descendants.empty())
708
m_pTreeTop->SetItemHasChildren(derived);
710
kind = tkClass | tkEnum;
714
kind = tkNamespace | tkClass | tkEnum;
720
AddChildrenOf(m_pTreeTop, item, data->m_pToken->GetSelf(), kind);
726
// Manager::Get()->GetLogManager()->DebugLog(F(_("E: %d items"), m_pTreeTop->GetCount()));
729
void ClassBrowserBuilderThread::CollapseItem(wxTreeItemId item)
731
if (TestDestroy() || Manager::IsAppShuttingDown())
734
wxMutexLocker lock(m_BuildMutex);
736
m_pTreeTop->CollapseAndReset(item); // this freezes gtk
738
m_pTreeTop->DeleteChildren(item);
740
m_pTreeTop->SetItemHasChildren(item);
741
// Manager::Get()->GetLogManager()->DebugLog(F(_("C: %d items"), m_pTreeTop->GetCount()));
744
void ClassBrowserBuilderThread::SelectItem(wxTreeItemId item)
746
if (TestDestroy() || Manager::IsAppShuttingDown())
749
wxMutexLocker lock(m_BuildMutex);
751
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Select ") + m_pTreeTop->GetItemText(item)));
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
11
#include "classbrowserbuilderthread.h"
14
#include <projectmanager.h>
15
#include <cbproject.h>
17
#include <wx/settings.h>
19
#ifdef buildtree_measuring
20
#include <wx/stopwatch.h>
26
namespace compatibility { typedef TernaryCondTypedef<wxMinimumVersion<2,5>::eval, wxTreeItemIdValue, long int>::eval tree_cookie_t; };
28
IMPLEMENT_DYNAMIC_CLASS(CBTreeCtrl, wxTreeCtrl)
30
CBTreeCtrl::CBTreeCtrl()
32
Compare = &CBNoCompare;
35
CBTreeCtrl::CBTreeCtrl(wxWindow *parent, const wxWindowID id,const wxPoint& pos, const wxSize& size,long style)
36
:wxTreeCtrl(parent, id, pos, size, style)
38
Compare = &CBNoCompare;
41
void CBTreeCtrl::SetCompareFunction(const BrowserSortType type)
46
Compare = &CBAlphabetCompare;
49
Compare = &CBKindCompare;
52
Compare = &CBScopeCompare;
56
Compare = &CBNoCompare;
62
int CBTreeCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
64
return Compare((CBTreeData*)GetItemData(item1), (CBTreeData*)GetItemData(item2));
68
int CBTreeCtrl::CBAlphabetCompare (CBTreeData* lhs, CBTreeData* rhs)
72
if (lhs->m_SpecialFolder != sfToken || rhs->m_SpecialFolder != sfToken)
74
if (!lhs->m_pToken || !rhs->m_pToken)
76
return wxStricmp(lhs->m_pToken->m_Name, rhs->m_pToken->m_Name);
79
int CBTreeCtrl::CBKindCompare(CBTreeData* lhs, CBTreeData* rhs)
83
if (lhs->m_SpecialFolder != sfToken || rhs->m_SpecialFolder != sfToken)
85
if (lhs->m_TokenKind == rhs->m_TokenKind)
86
return CBAlphabetCompare(lhs, rhs);
88
return lhs->m_TokenKind - rhs->m_TokenKind;
91
int CBTreeCtrl::CBScopeCompare(CBTreeData* lhs, CBTreeData* rhs)
95
if (lhs->m_SpecialFolder != sfToken || rhs->m_SpecialFolder != sfToken)
98
if (lhs->m_pToken->m_Scope == rhs->m_pToken->m_Scope)
99
return CBKindCompare(lhs, rhs);
101
return rhs->m_pToken->m_Scope - lhs->m_pToken->m_Scope;
104
int CBTreeCtrl::CBNoCompare(CBTreeData* lhs, CBTreeData* rhs)
109
// This does not really do what it says !
110
// It only removes doubles, if they are neighbours, so the tree should be sorted !!
111
// The last one (after sorting) remains.
112
void CBTreeCtrl::RemoveDoubles(const wxTreeItemId& parent)
114
if (Manager::IsAppShuttingDown() || (!(parent.IsOk())))
117
#ifdef buildtree_measuring
120
// we 'll loop backwards so we can delete nodes without problems
121
wxTreeItemId existing = GetLastChild(parent);
122
while (parent.IsOk() && existing.IsOk())
124
wxTreeItemId prevItem = GetPrevSibling(existing);
125
if (!prevItem.IsOk())
127
CBTreeData* dataExisting = (CBTreeData*)(GetItemData(existing));
128
CBTreeData* dataPrev = (CBTreeData*)(GetItemData(prevItem));
131
dataExisting->m_SpecialFolder == sfToken &&
132
dataPrev->m_SpecialFolder == sfToken &&
133
dataExisting->m_pToken &&
134
dataPrev->m_pToken &&
135
(dataExisting->m_pToken->DisplayName() == dataPrev->m_pToken->DisplayName()))
139
else if (existing.IsOk())
140
existing = GetPrevSibling(existing);
142
#ifdef buildtree_measuring
143
Manager::Get()->GetLogManager()->DebugLog(F(_T("RemoveDoubles took : %ld"), sw.Time()));
147
// ClassBrowserBuilderThread
148
ClassBrowserBuilderThread::ClassBrowserBuilderThread(wxSemaphore& sem, ClassBrowserBuilderThread** threadVar)
149
: wxThread(wxTHREAD_JOINABLE),
157
m_ppThreadVar(threadVar)
162
ClassBrowserBuilderThread::~ClassBrowserBuilderThread()
167
void ClassBrowserBuilderThread::Init(Parser* parser,
169
CBTreeCtrl* treeBottom,
170
const wxString& active_filename,
171
void* user_data, // active project
172
const BrowserOptions& options,
173
TokensTree* pTokensTree,
176
wxMutexLocker lock(m_BuildMutex);
178
m_pTreeTop = treeTop;
179
m_pTreeBottom = treeBottom;
180
m_ActiveFilename = active_filename;
181
m_pUserData = user_data;
183
m_pTokensTree = pTokensTree;
185
m_CurrentFileSet.clear();
186
m_CurrentTokenSet.clear();
188
TokensTree* tree = m_pParser->GetTokens();
189
// fill filter set for current-file-filter
190
if (m_Options.displayFilter == bdfFile && !m_ActiveFilename.IsEmpty())
192
// m_ActiveFilename is the full filename up to the extension dot. No extension though.
193
// get all filenames' indices matching our mask
194
tree->m_FilenamesMap.FindMatches(m_ActiveFilename, m_CurrentFileSet, true, true);
197
if (m_Options.displayFilter == bdfProject && (user_data != 0))
199
cbProject* prj = (cbProject*)user_data;
200
for (int i = 0; i < prj->GetFilesCount(); i++)
202
ProjectFile* curfile = prj->GetFile(i);
206
wxString filename = curfile->file.GetFullPath();
207
size_t fileIdx = tree->m_FilenamesMap.GetItemNo(filename);
210
m_CurrentFileSet.insert(fileIdx);
215
if (!m_CurrentFileSet.empty())
217
m_CurrentTokenSet.clear();
218
m_CurrentGlobalTokensSet.clear();
219
for (TokenFilesSet::iterator it = m_CurrentFileSet.begin();it != m_CurrentFileSet.end(); it++)
221
TokenIdxSet* curset = &(tree->m_FilesMap[*it]);
222
for (TokenIdxSet::iterator it2 = curset->begin(); it2 != curset->end(); it2++)
224
Token* curtoken = tree->at(*it2);
227
m_CurrentTokenSet.insert(*it2);
228
if (curtoken->m_ParentIndex == -1)
229
m_CurrentGlobalTokensSet.insert(*it2);
241
void* ClassBrowserBuilderThread::Entry()
243
while (!TestDestroy() && !Manager::IsAppShuttingDown())
245
// wait until the classbrowser signals
247
// Manager::Get()->GetLogManager()->DebugLog(F(_T(" - - - - - -")));
249
if (TestDestroy() || Manager::IsAppShuttingDown())
254
// this code (PART 1/2) seems to be good on linux
255
// because of it the libcairo crash on dualcore processors
256
// is gone, but on windows it has very bad influence,
257
// henceforth the ifdef guard
258
// the questions remains if it is the correct solution
259
if (!::wxIsMainThread())
267
// this code (PART 2/2) seems to be good on linux
268
// because of it the libcairo crash on dualcore processors
269
// is gone, but on windows it has very bad influence,
270
// henceforth the ifdef guard
271
// the questions remains if it is the correct solution
272
if (!::wxIsMainThread())
284
void ClassBrowserBuilderThread::ExpandNamespaces(wxTreeItemId node)
286
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
289
if (!m_Options.expandNS || !node.IsOk())
292
wxTreeItemIdValue enumerationCookie;
293
wxTreeItemId existing = m_pTreeTop->GetFirstChild(node, enumerationCookie);
294
while (existing.IsOk())
296
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(existing);
297
if (data && data->m_pToken && data->m_pToken->m_TokenKind == tkNamespace)
299
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Auto-expanding: ") + data->m_pToken->m_Name));
300
m_pTreeTop->Expand(existing);
301
ExpandNamespaces(existing); // recurse
304
existing = m_pTreeTop->GetNextSibling(existing);
308
void ClassBrowserBuilderThread::BuildTree(bool useLock)
310
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
313
#ifdef buildtree_measuring
315
wxStopWatch sw_total;
317
m_pTreeTop->SetImageList(m_pParser->GetImageList());
318
m_pTreeBottom->SetImageList(m_pParser->GetImageList());
320
wxTreeItemId root = m_pTreeTop->GetRootItem();
323
root = m_pTreeTop->AddRoot(_("Symbols"), PARSER_IMG_SYMBOLS_FOLDER, PARSER_IMG_SYMBOLS_FOLDER, new CBTreeData(sfRoot));
324
m_pTreeTop->SetItemHasChildren(root);
328
m_pTreeTop->SetCompareFunction(m_Options.sortType);
329
m_pTreeBottom->SetCompareFunction(m_Options.sortType);
331
m_ExpandedVect.clear();
332
SaveExpandedItems(m_pTreeTop, root, 0);
333
#ifdef buildtree_measuring
334
Manager::Get()->GetLogManager()->DebugLog(F(_T("Saving expanded items took : %ld ms"),sw.Time()));
339
#ifdef buildtree_measuring
340
Manager::Get()->GetLogManager()->DebugLog(F(_T("Saving selected items took : %ld ms"),sw.Time()));
344
if (m_Options.treeMembers)
346
m_pTreeBottom->Hide();
347
m_pTreeBottom->Freeze();
350
m_pTreeTop->Freeze();
352
#ifdef buildtree_measuring
353
Manager::Get()->GetLogManager()->DebugLog(F(_T("Hiding and freezing trees took : %ld ms"),sw.Time()));
356
RemoveInvalidNodes(m_pTreeTop, root);
357
#ifdef buildtree_measuring
358
Manager::Get()->GetLogManager()->DebugLog(F(_T("Removing invalid nodes (top tree) took : %ld ms"),sw.Time()));
361
if (m_Options.treeMembers)
363
RemoveInvalidNodes(m_pTreeBottom, m_pTreeBottom->GetRootItem());
364
#ifdef buildtree_measuring
365
Manager::Get()->GetLogManager()->DebugLog(F(_T("Removing invalid nodes (bottom tree) took : %ld ms"),sw.Time()));
370
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
372
#ifdef buildtree_measuring
373
Manager::Get()->GetLogManager()->DebugLog(F(_T("TestDestroy() took : %ld ms"),sw.Time()));
377
// the tree is completely dynamic: it is populated when a node expands/collapses.
378
// so, by expanding the root node, we already instruct it to fill the top level :)
380
// this technique makes it really fast to draw (we only draw what's expanded) and
381
// has very minimum memory overhead since it contains as few items as possible.
382
// plus, it doesn't flicker because we 're not emptying it and re-creating it each time ;)
384
CollapseItem(root, useLock);
385
#ifdef buildtree_measuring
386
Manager::Get()->GetLogManager()->DebugLog(F(_T("Collapsing root item took : %ld ms"),sw.Time()));
389
// Bottleneck: Takes ~4 secs on C::B workspace:
390
m_pTreeTop->Expand(root);
391
#ifdef buildtree_measuring
392
Manager::Get()->GetLogManager()->DebugLog(F(_T("Expanding root item took : %ld ms"),sw.Time()));
396
// seems like the "expand" event comes too late in wxGTK, so make it happen now
399
#ifdef buildtree_measuring
400
Manager::Get()->GetLogManager()->DebugLog(F(_T("Expanding root item (gtk only) took : %ld ms"),sw.Time()));
403
ExpandSavedItems(m_pTreeTop, root, 0);
404
#ifdef buildtree_measuring
405
Manager::Get()->GetLogManager()->DebugLog(F(_T("Expanding saved items took : %ld ms"),sw.Time()));
408
// Bottleneck: Takes ~4 secs on C::B workspace:
410
#ifdef buildtree_measuring
411
Manager::Get()->GetLogManager()->DebugLog(F(_T("Selecting saved item took : %ld ms"),sw.Time()));
415
if (m_Options.treeMembers)
417
m_pTreeBottom->Thaw();
418
#ifdef buildtree_measuring
419
Manager::Get()->GetLogManager()->DebugLog(F(_T("Thaw bottom tree took : %ld ms"),sw.Time()));
422
m_pTreeBottom->Show();
423
#ifdef buildtree_measuring
424
Manager::Get()->GetLogManager()->DebugLog(F(_T("Showing bottom tree took : %ld ms"),sw.Time()));
429
ExpandNamespaces(m_pTreeTop->GetRootItem());
430
#ifdef buildtree_measuring
431
Manager::Get()->GetLogManager()->DebugLog(F(_T("Expanding namespaces took : %ld ms"),sw.Time()));
436
#ifdef buildtree_measuring
437
Manager::Get()->GetLogManager()->DebugLog(F(_T("Thaw top tree took : %ld ms"),sw.Time()));
440
// Bottleneck: Takes ~4 secs on C::B workspace:
442
#ifdef buildtree_measuring
443
Manager::Get()->GetLogManager()->DebugLog(F(_T("Show top tree took : %ld ms"),sw.Time()));
444
Manager::Get()->GetLogManager()->DebugLog(F(_T("BuildTree took : %ld ms in total"),sw_total.Time()));
449
void ClassBrowserBuilderThread::RemoveInvalidNodes(CBTreeCtrl* tree, wxTreeItemId parent)
451
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown() || (!(parent.IsOk())))
454
// recursively enters all existing nodes and deletes the node if the token it references
455
// is invalid (i.e. m_pTokensTree->at() != token_in_data)
457
// we 'll loop backwards so we can delete nodes without problems
458
wxTreeItemId existing = tree->GetLastChild(parent);
459
while (parent.IsOk() && existing.IsOk())
461
bool removeCurrent = false;
462
bool hasChildren = tree->ItemHasChildren(existing);
463
CBTreeData* data = (CBTreeData*)(tree->GetItemData(existing));
465
if (tree == m_pTreeBottom)
467
removeCurrent = true;
469
else if (data && data->m_pToken)
472
if (m_pTokensTree->at(data->m_TokenIndex) != data->m_pToken ||
473
(data->m_Ticket && data->m_Ticket != data->m_pToken->GetTicket()) ||
474
!TokenMatchesFilter(data->m_pToken))
476
removeCurrent = true;
483
tree->DeleteChildren(existing);
485
wxTreeItemId next = tree->GetPrevSibling(existing);
486
if (!next.IsOk() && parent.IsOk() && tree == m_pTreeTop && tree->GetChildrenCount(parent, false) == 1 )
488
CollapseItem(parent);
489
// tree->SetItemHasChildren(parent, false);
490
// existing is the last item an gets deleted in CollapseItem and at least on 64-bit linux it can
491
// lead to a crash, because we use it again some lines later, but m_pItem is not 0 in some rare cases,
492
// and therefore IsOk returns true !!
493
// so we leave the function here
498
tree->Delete(existing);
505
RemoveInvalidNodes(tree, existing); // recurse
508
existing = tree->GetPrevSibling(existing);
512
void ClassBrowserBuilderThread::RemoveInvalidNodes(CBTreeCtrl* tree, wxTreeItemId parent)
514
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown() || (!(parent.IsOk())))
517
// recursively enters all existing nodes and deletes the node if the token it references
518
// is invalid (i.e. m_pTokensTree->at() != token_in_data)
520
// we 'll loop backwards so we can delete nodes without problems
521
wxTreeItemId existing = tree->GetLastChild(parent);
522
while (existing.IsOk())
525
if (tree->ItemHasChildren(existing))
526
RemoveInvalidNodes(tree, existing);
528
CBTreeData* data = (CBTreeData*)tree->GetItemData(existing);
529
if (data && data->m_pToken)
531
if (m_pTokensTree->at(data->m_TokenIndex) != data->m_pToken ||
532
data->m_TokenKind != data->m_pToken->m_TokenKind || // need to compare kinds: the token index might have been reused...
533
data->m_TokenName != data->m_pToken->m_Name || // same for the token name
534
!TokenMatchesFilter(data->m_pToken))
536
// keep parent and set flag if this is the last child of parent
537
wxTreeItemId parent = tree->GetItemParent(existing);
538
bool isLastChild = tree->GetChildrenCount(parent) == 1;
539
// we have to do this in two steps: first collapse and then set haschildren to false
540
if (isLastChild && parent.IsOk() && tree == m_pTreeTop)
542
CollapseItem(parent);
547
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Item %s is invalid"), tree->GetItemText(existing).c_str()));
548
wxTreeItemId next = tree->GetPrevSibling(existing);
549
tree->Delete(existing);
553
// if this was the last child of its parent, collapse the parent
555
// tree->SetItemHasChildren(parent, false);
561
existing = tree->GetPrevSibling(existing);
566
wxTreeItemId ClassBrowserBuilderThread::AddNodeIfNotThere(CBTreeCtrl* tree, wxTreeItemId parent, const wxString& name, int imgIndex, CBTreeData* data)
568
compatibility::tree_cookie_t cookie = 0;
570
wxTreeItemId existing = tree->GetFirstChild(parent, cookie);
573
wxString itemText = tree->GetItemText(existing);
574
if (itemText == name)
576
// update the existing node's image indices and user-data.
577
// it's not possible to have the same token name more than once
578
// under the same namespace anyway. if we do, there's a bug in the parser :(
579
tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Normal);
580
tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Selected);
581
delete tree->GetItemData(existing); // make Valgrind happy
582
tree->SetItemData(existing, data);
586
existing = tree->GetNextChild(parent, cookie);
588
return tree->AppendItem(parent, name, imgIndex, imgIndex, data);
591
bool ClassBrowserBuilderThread::AddChildrenOf(CBTreeCtrl* tree, wxTreeItemId parent, int parentTokenIdx, short int tokenKindMask, int tokenScopeMask)
593
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
596
Token* parentToken = 0;
597
TokenIdxSet* tokens = 0;
599
if (parentTokenIdx == -1)
601
if (m_Options.displayFilter >= bdfWorkspace)
602
tokens = &m_pTokensTree->m_GlobalNameSpace;
604
tokens = &m_CurrentGlobalTokensSet;
608
parentToken = m_pTokensTree->at(parentTokenIdx);
611
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Token not found?!?")));
614
tokens = &parentToken->m_Children;
617
return AddNodes(tree, parent, *tokens, tokenKindMask, tokenScopeMask, m_Options.displayFilter == bdfEverything);
620
bool ClassBrowserBuilderThread::AddAncestorsOf(CBTreeCtrl* tree, wxTreeItemId parent, int tokenIdx)
622
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
625
Token* token = m_pTokensTree->at(tokenIdx);
629
return AddNodes(tree, parent, token->m_DirectAncestors, tkClass | tkTypedef, 0, true);
632
bool ClassBrowserBuilderThread::AddDescendantsOf(CBTreeCtrl* tree, wxTreeItemId parent, int tokenIdx, bool allowInheritance)
634
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
637
Token* token = m_pTokensTree->at(tokenIdx);
641
bool inh = m_Options.showInheritance;
642
m_Options.showInheritance = allowInheritance;
644
bool ret = AddNodes(tree, parent, token->m_Descendants, tkClass | tkTypedef, 0, true);
646
m_Options.showInheritance = inh;
650
bool ClassBrowserBuilderThread::AddNodes(CBTreeCtrl* tree, wxTreeItemId parent, const TokenIdxSet& tokens, short int tokenKindMask, int tokenScopeMask, bool allowGlobals)
653
set<unsigned long, less<unsigned long> > tickets;
655
// Build temporary list of Token tickets - if the token's ticket is present
656
// among the parent node's children, it's a dupe, and we'll skip it.
657
if (parent.IsOk() && tree == m_pTreeTop)
659
wxTreeItemIdValue cookie;
660
wxTreeItemId curchild = tree->GetFirstChild(parent,cookie);
661
while (curchild.IsOk())
663
CBTreeData* data = (CBTreeData*)(tree->GetItemData(curchild));
664
curchild = tree->GetNextSibling(curchild);
665
if (data && data->m_Ticket)
666
tickets.insert(data->m_Ticket);
670
TokenIdxSet::iterator start = tokens.begin();
671
TokenIdxSet::iterator end = tokens.end();
673
for ( ; start != end; ++start)
675
Token* token = m_pTokensTree->at(*start);
677
(token->m_TokenKind & tokenKindMask) &&
678
(tokenScopeMask == 0 || token->m_Scope == tokenScopeMask) &&
679
(allowGlobals || token->m_IsLocal ||
680
TokenMatchesFilter(token)))
682
if (tree == m_pTreeTop && tickets.find(token->GetTicket()) != tickets.end())
685
int img = m_pParser->GetTokenKindImage(token);
687
wxString str = token->m_Name;
688
if ( (token->m_TokenKind == tkFunction)
689
|| (token->m_TokenKind == tkConstructor)
690
|| (token->m_TokenKind == tkDestructor)
691
|| (token->m_TokenKind == tkMacro)
692
|| (token->m_TokenKind == tkClass) )
693
str << token->m_Args;
694
// modification suggested by ollydbg in http://forums.codeblocks.org/index.php/topic,10242.msg70865.html#msg70865:
695
// if (!token->m_ActualType.IsEmpty())
696
// str = str + _T(" : ") + token->m_ActualType;
697
if (!token->m_Type.IsEmpty())
698
str = str + _T(" : ") + token->m_Type;
700
wxTreeItemId child = tree->AppendItem(parent, str, img, img, new CBTreeData(sfToken, token, tokenKindMask));
702
// mark as expanding if it is a container
703
int kind = tkClass | tkNamespace | tkEnum;
704
if (token->m_TokenKind == tkClass)
706
if (!m_Options.treeMembers)
707
kind |= tkTypedef | tkFunction | tkVariable | tkEnum | tkMacro;
708
tree->SetItemHasChildren(child, m_Options.showInheritance || TokenContainsChildrenOfKind(token, kind));
710
else if (token->m_TokenKind & (tkNamespace | tkEnum))
712
if (!m_Options.treeMembers)
713
kind |= tkTypedef | tkFunction | tkVariable | tkEnumerator | tkMacro;
714
tree->SetItemHasChildren(child, TokenContainsChildrenOfKind(token, kind));
719
tree->SortChildren(parent);
720
// tree->RemoveDoubles(parent);
721
#ifdef buildtree_measuring
722
Manager::Get()->GetLogManager()->DebugLog(F(_T("Added %d nodes"), count));
727
bool ClassBrowserBuilderThread::TokenMatchesFilter(Token* token)
732
if ( m_Options.displayFilter == bdfEverything
733
|| (m_Options.displayFilter == bdfWorkspace && token->m_IsLocal) )
736
if (m_Options.displayFilter == bdfFile && !m_CurrentTokenSet.empty())
738
if (m_CurrentTokenSet.find(token->GetSelf()) != m_CurrentTokenSet.end())
741
// we got to check all children of this token (recursively)
742
// to see if any of them matches the filter...
743
for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
745
if (TokenMatchesFilter(m_pTokensTree->at(*it)))
749
else if (m_Options.displayFilter == bdfProject && m_pUserData)
751
return token->m_pUserData == m_pUserData;
757
bool ClassBrowserBuilderThread::TokenContainsChildrenOfKind(Token* token, int kind)
761
TokensTree* tt = token->GetTree();
762
for (TokenIdxSet::iterator it = token->m_Children.begin(); it != token->m_Children.end(); ++it)
764
Token* child = tt->at(*it);
765
if (child->m_TokenKind & kind)
771
void ClassBrowserBuilderThread::AddMembersOf(CBTreeCtrl* tree, wxTreeItemId node)
773
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown() || !node.IsOk())
776
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(node);
778
bool bottom = (tree == m_pTreeBottom);
781
#ifdef buildtree_measuring
785
#ifdef buildtree_measuring
786
Manager::Get()->GetLogManager()->DebugLog(F(_T("tree->Freeze() took : %ld ms"),sw.Time()));
789
tree->DeleteAllItems();
790
#ifdef buildtree_measuring
791
Manager::Get()->GetLogManager()->DebugLog(F(_T("tree->DeleteAllItems() took : %ld ms"),sw.Time()));
794
node = tree->AddRoot(_T("Members")); // not visible, so don't translate
795
#ifdef buildtree_measuring
796
Manager::Get()->GetLogManager()->DebugLog(F(_T("tree->AddRoot() took : %ld ms"),sw.Time()));
800
wxTreeItemId firstItem;
801
bool haveFirstItem = false;
804
switch (data->m_SpecialFolder)
806
case sfGFuncs : AddChildrenOf(tree, node, -1, tkFunction, false); break;
807
case sfGVars : AddChildrenOf(tree, node, -1, tkVariable, false); break;
808
case sfPreproc : AddChildrenOf(tree, node, -1, tkPreprocessor, false); break;
809
case sfTypedef : AddChildrenOf(tree, node, -1, tkTypedef, false); break;
810
case sfMacro : AddChildrenOf(tree, node, -1, tkMacro, false); break;
815
if (m_Options.sortType == bstKind && !(data->m_pToken->m_TokenKind & tkEnum))
817
wxTreeItemId rootCtorDtor = tree->AppendItem(node, _("Ctors & Dtors"), PARSER_IMG_CLASS_FOLDER);
818
wxTreeItemId rootFuncs = tree->AppendItem(node, _("Functions"), PARSER_IMG_FUNCS_FOLDER);
819
wxTreeItemId rootVars = tree->AppendItem(node, _("Variables"), PARSER_IMG_VARS_FOLDER);
820
wxTreeItemId rootMacro = tree->AppendItem(node, _("Macros"), PARSER_IMG_MACRO_FOLDER);
821
wxTreeItemId rootOthers = tree->AppendItem(node, _("Others"), PARSER_IMG_OTHERS_FOLDER);
823
AddChildrenOf(tree, rootCtorDtor, data->m_pToken->GetSelf(), tkConstructor | tkDestructor);
824
AddChildrenOf(tree, rootFuncs, data->m_pToken->GetSelf(), tkFunction);
825
AddChildrenOf(tree, rootVars, data->m_pToken->GetSelf(), tkVariable);
826
AddChildrenOf(tree, rootMacro, data->m_pToken->GetSelf(), tkMacro);
827
AddChildrenOf(tree, rootOthers, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum | tkAnyFunction | tkVariable | tkMacro));
829
firstItem = rootCtorDtor;
831
else if (m_Options.sortType == bstScope && data->m_pToken->m_TokenKind & tkClass)
833
wxTreeItemId rootPublic = tree->AppendItem(node, _("Public"), PARSER_IMG_CLASS_FOLDER);
834
wxTreeItemId rootProtected = tree->AppendItem(node, _("Protected"), PARSER_IMG_FUNCS_FOLDER);
835
wxTreeItemId rootPrivate = tree->AppendItem(node, _("Private"), PARSER_IMG_VARS_FOLDER);
837
AddChildrenOf(tree, rootPublic, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum), tsPublic);
838
AddChildrenOf(tree, rootProtected, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum), tsProtected);
839
AddChildrenOf(tree, rootPrivate, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum), tsPrivate);
841
firstItem = rootPublic;
845
AddChildrenOf(tree, node, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum));
849
wxTreeItemId existing = tree->GetLastChild(tree->GetRootItem());
850
while (existing.IsOk())
852
wxTreeItemId next = tree->GetPrevSibling(existing);
854
if (tree->GetChildrenCount(existing) > 0)
856
tree->SetItemBold(existing, true);
857
// make existing the firstItem, because the former firstItem might get deleted
858
// in the else-clause, if it has no children, what can lead to a crash
859
firstItem = existing;
860
// needed, if no child remains, because firstItem IsOk() returns true anyway
862
haveFirstItem = true;
866
tree->Delete(existing);
870
existing = tree->GetPrevSibling(existing);
874
AddChildrenOf(tree, node, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum));
876
// add all children, except containers
877
// AddChildrenOf(tree, node, data->m_pToken->GetSelf(), ~(tkNamespace | tkClass | tkEnum));
887
if (haveFirstItem && firstItem.IsOk())
889
tree->ScrollTo(firstItem);
890
tree->EnsureVisible(firstItem);
896
// checks if there are respective children and colors the nodes
897
bool ClassBrowserBuilderThread::CreateSpecialFolders(CBTreeCtrl* tree, wxTreeItemId parent)
905
// loop all tokens in global namespace and see if we have matches
906
TokensTree* tt = m_pParser->GetTokens();
907
for (TokenIdxSet::iterator it = tt->m_GlobalNameSpace.begin(); it != tt->m_GlobalNameSpace.end(); ++it)
909
Token* token = tt->at(*it);
910
if (token && token->m_IsLocal && TokenMatchesFilter(token))
912
if (!hasGF && token->m_TokenKind == tkFunction)
914
else if (!hasGM && token->m_TokenKind == tkMacro)
916
else if (!hasGV && token->m_TokenKind == tkVariable)
918
else if (!hasGP && token->m_TokenKind == tkPreprocessor)
920
else if (!hasTD && token->m_TokenKind == tkTypedef)
924
if (hasGF && hasGV && hasGP && hasTD && hasGM)
925
break; // we have everything, stop iterating...
928
wxTreeItemId gfuncs = AddNodeIfNotThere(m_pTreeTop, parent, _("Global functions"), PARSER_IMG_FUNCS_FOLDER, new CBTreeData(sfGFuncs, 0, tkFunction, -1));
929
wxTreeItemId tdef = AddNodeIfNotThere(m_pTreeTop, parent, _("Global typedefs"), PARSER_IMG_TYPEDEF_FOLDER, new CBTreeData(sfTypedef, 0, tkTypedef, -1));
930
wxTreeItemId gvars = AddNodeIfNotThere(m_pTreeTop, parent, _("Global variables"), PARSER_IMG_VARS_FOLDER, new CBTreeData(sfGVars, 0, tkVariable, -1));
931
wxTreeItemId preproc = AddNodeIfNotThere(m_pTreeTop, parent, _("Preprocessor symbols"), PARSER_IMG_PREPROC_FOLDER, new CBTreeData(sfPreproc, 0, tkPreprocessor, -1));
932
wxTreeItemId gmacro = AddNodeIfNotThere(m_pTreeTop, parent, _("Global macros"), PARSER_IMG_MACRO_FOLDER, new CBTreeData(sfMacro, 0, tkMacro, -1));
934
bool bottom = m_Options.treeMembers;
935
m_pTreeTop->SetItemHasChildren(gfuncs, !bottom && hasGF);
936
m_pTreeTop->SetItemHasChildren(tdef, !bottom && hasTD);
937
m_pTreeTop->SetItemHasChildren(gvars, !bottom && hasGV);
938
m_pTreeTop->SetItemHasChildren(preproc, !bottom && hasGP);
939
m_pTreeTop->SetItemHasChildren(gmacro, !bottom && hasGM);
941
wxColour black = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
942
wxColour grey = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
944
tree->SetItemTextColour(gfuncs, hasGF ? black : grey);
945
tree->SetItemTextColour(gvars, hasGV ? black : grey);
946
tree->SetItemTextColour(preproc, hasGP ? black : grey);
947
tree->SetItemTextColour(tdef, hasTD ? black : grey);
948
tree->SetItemTextColour(gmacro, hasGM ? black : grey);
950
return hasGF || hasGV || hasGP || hasTD || hasGM;
953
void ClassBrowserBuilderThread::ExpandItem(wxTreeItemId item)
955
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
958
#ifdef buildtree_measuring
961
// wxMutexLocker lock(m_BuildMutex);
962
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(item);
965
switch (data->m_SpecialFolder)
969
CreateSpecialFolders(m_pTreeTop, item);
970
if( ! (m_Options.displayFilter == bdfFile && m_ActiveFilename.IsEmpty()))
971
AddChildrenOf(m_pTreeTop, item, -1, ~(tkFunction | tkVariable | tkPreprocessor | tkTypedef | tkMacro));
974
case sfBase: AddAncestorsOf(m_pTreeTop, item, data->m_pToken->GetSelf()); break;
975
case sfDerived: AddDescendantsOf(m_pTreeTop, item, data->m_pToken->GetSelf(), false); break;
979
switch (data->m_pToken->m_TokenKind)
983
// add base and derived classes folders
984
if (m_Options.showInheritance)
986
wxTreeItemId base = m_pTreeTop->AppendItem(item, _("Base classes"), PARSER_IMG_CLASS_FOLDER, PARSER_IMG_CLASS_FOLDER, new CBTreeData(sfBase, data->m_pToken, tkClass, data->m_pToken->GetSelf()));
987
if (!data->m_pToken->m_DirectAncestors.empty())
988
m_pTreeTop->SetItemHasChildren(base);
989
wxTreeItemId derived = m_pTreeTop->AppendItem(item, _("Derived classes"), PARSER_IMG_CLASS_FOLDER, PARSER_IMG_CLASS_FOLDER, new CBTreeData(sfDerived, data->m_pToken, tkClass, data->m_pToken->GetSelf()));
990
if (!data->m_pToken->m_Descendants.empty())
991
m_pTreeTop->SetItemHasChildren(derived);
993
kind = tkClass | tkEnum;
997
kind = tkNamespace | tkClass | tkEnum;
1003
AddChildrenOf(m_pTreeTop, item, data->m_pToken->GetSelf(), kind);
1009
if (m_pParser && !m_Options.treeMembers)
1011
AddMembersOf(m_pTreeTop, item);
1013
#ifdef buildtree_measuring
1014
Manager::Get()->GetLogManager()->DebugLog(F(_T("ExpandItems (internally) took : %ld ms"),sw.Time()));
1016
// Manager::Get()->GetLogManager()->DebugLog(F(_("E: %d items"), m_pTreeTop->GetCount()));
1019
void ClassBrowserBuilderThread::CollapseItem(wxTreeItemId item, bool useLock)
1021
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1025
wxMutexLocker lock(m_BuildMutex);
1027
m_pTreeTop->CollapseAndReset(item); // this freezes gtk
1029
m_pTreeTop->DeleteChildren(item);
1031
m_pTreeTop->SetItemHasChildren(item);
1032
// Manager::Get()->GetLogManager()->DebugLog(F(_("C: %d items"), m_pTreeTop->GetCount()));
1035
void ClassBrowserBuilderThread::SelectItem(wxTreeItemId item)
1037
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1039
#ifdef buildtree_measuring
1042
wxMutexLocker lock(m_BuildMutex);
1044
CBTreeCtrl* tree = (m_Options.treeMembers) ? m_pTreeBottom : m_pTreeTop;
1045
if ( !(m_Options.displayFilter == bdfFile && m_ActiveFilename.IsEmpty()))
1046
AddMembersOf(tree, item);
1047
// Manager::Get()->GetLogManager()->DebugLog(F(_T("Select ") + m_pTreeTop->GetItemText(item)));
1048
#ifdef buildtree_measuring
1049
Manager::Get()->GetLogManager()->DebugLog(F(_T("SelectItem (internally) took : %ld ms"),sw.Time()));
1053
void ClassBrowserBuilderThread::SaveExpandedItems(CBTreeCtrl* tree, wxTreeItemId parent, int level)
1055
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1058
wxTreeItemIdValue cookie;
1059
wxTreeItemId existing = tree->GetFirstChild(parent, cookie);
1060
while (existing.IsOk())
1062
CBTreeData* data = (CBTreeData*)(tree->GetItemData(existing));
1063
if (tree->GetChildrenCount(existing,false) > 0)
1065
m_ExpandedVect.push_back(CBExpandedItemData(data, level));
1067
SaveExpandedItems(tree, existing, level + 1);
1070
existing = tree->GetNextSibling(existing);
1074
void ClassBrowserBuilderThread::ExpandSavedItems(CBTreeCtrl* tree, wxTreeItemId parent, int level)
1076
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1079
wxTreeItemIdValue cookie;
1080
wxTreeItemId existing = tree->GetFirstChild(parent, cookie);
1081
while (existing.IsOk() && !m_ExpandedVect.empty())
1083
CBTreeData* data = (CBTreeData*)(tree->GetItemData(existing));
1084
CBExpandedItemData saved = m_ExpandedVect.front();
1086
if (level == saved.GetLevel() &&
1087
wxStrcmp(data->m_TokenName, saved.GetData().m_TokenName) == 0 &&
1088
data->m_TokenKind == saved.GetData().m_TokenKind &&
1089
data->m_SpecialFolder == saved.GetData().m_SpecialFolder)
1091
tree->Expand(existing);
1092
//ExpandItem(existing);
1094
m_ExpandedVect.pop_front();
1096
if (m_ExpandedVect.empty())
1099
saved = m_ExpandedVect.front(); //next saved
1100
if (saved.GetLevel() < level)
1103
if (saved.GetLevel() > level)
1104
ExpandSavedItems(tree, existing, saved.GetLevel());
1107
existing = tree->GetNextSibling(existing);
1110
// remove non-existing by now saved items
1111
while (!m_ExpandedVect.empty() && m_ExpandedVect.front().GetLevel() > level)
1112
m_ExpandedVect.pop_front();
1115
void ClassBrowserBuilderThread::SaveSelectedItem()
1117
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1120
m_SelectedPath.clear();
1122
wxTreeItemId item = m_pTreeTop->GetSelection();
1123
while (item.IsOk() && item != m_pTreeTop->GetRootItem())
1125
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(item);
1126
m_SelectedPath.push_front(*data);
1128
item = m_pTreeTop->GetItemParent(item);
1132
void ClassBrowserBuilderThread::SelectSavedItem()
1134
if ((!::wxIsMainThread() && TestDestroy()) || Manager::IsAppShuttingDown())
1137
wxTreeItemId parent = m_pTreeTop->GetRootItem();
1139
wxTreeItemIdValue cookie;
1140
wxTreeItemId item = m_pTreeTop->GetFirstChild(parent, cookie);
1142
while (!m_SelectedPath.empty() && item.IsOk())
1144
CBTreeData* data = (CBTreeData*)m_pTreeTop->GetItemData(item);
1145
CBTreeData* saved = &m_SelectedPath.front();
1147
if (data->m_SpecialFolder == saved->m_SpecialFolder &&
1148
wxStrcmp(data->m_TokenName, saved->m_TokenName) == 0 &&
1149
data->m_TokenKind == saved->m_TokenKind)
1151
wxTreeItemIdValue cookie;
1153
item = m_pTreeTop->GetFirstChild(item, cookie);
1154
m_SelectedPath.pop_front();
1157
item = m_pTreeTop->GetNextSibling(item);
1160
m_pTreeTop->SelectItem(parent, true);
1161
m_pTreeTop->EnsureVisible(parent);
1162
m_SelectedPath.clear();