1 /*
2  * This file is licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  */
6 
7 #include <sdk.h>
8 #ifndef CB_PRECOMP
9     #include <wx/settings.h>
10     #include <wx/utils.h>
11     #include <wx/string.h>
12 
13     #include <globals.h>
14     #include <manager.h>
15     #include <projectmanager.h>
16     #include <cbproject.h>
17 #endif
18 
19 #include "workspacebrowserbuilder.h"
20 
WorkspaceBrowserBuilder(ParserF * parser,wxTreeCtrl * treeTop,wxTreeCtrl * treeBottom)21 WorkspaceBrowserBuilder::WorkspaceBrowserBuilder(ParserF* parser, wxTreeCtrl* treeTop, wxTreeCtrl* treeBottom)
22     : m_pActiveProject(0),
23     m_Options()
24 {
25     m_AtWork = false;
26 
27     m_pParser = parser;
28     m_pTreeTop = treeTop;
29     m_pTreeBottom = treeBottom;
30     int targetHeight = floor(16 * cbGetActualContentScaleFactor(*m_pTreeTop));
31     m_pImlist = new FPImageList(targetHeight);
32     m_pTreeTop->SetImageList(m_pImlist->GetImageList());
33     m_pTreeBottom->SetImageList(m_pImlist->GetImageList());
34 }
35 
~WorkspaceBrowserBuilder()36 WorkspaceBrowserBuilder::~WorkspaceBrowserBuilder()
37 {
38     //dtor
39     delete m_pImlist;
40 }
41 
Init(const wxString & active_filename,cbProject * active_project,const BrowserOptions & options)42 void WorkspaceBrowserBuilder::Init(const wxString& active_filename,
43                                     cbProject* active_project,
44                                     const BrowserOptions& options)
45 {
46     m_ActiveFilename = active_filename;
47     m_pActiveProject = active_project;
48     m_Options = options;
49 
50     BuildTree();
51 }
52 
BuildTree()53 void WorkspaceBrowserBuilder::BuildTree()
54 {
55     if (Manager::IsAppShuttingDown())
56         return;
57 
58     if (!m_pParser)
59         return;
60 
61     m_AtWork = true;
62 
63     wxTreeItemId root = m_pTreeTop->GetRootItem();
64     if (!root.IsOk())
65     {
66         root = m_pTreeTop->AddRoot(_("Symbols"), m_pImlist->GetImageIdx("symbols_folder"), m_pImlist->GetImageIdx("symbols_folder"), new TreeDataF(sfRoot));
67         m_pTreeTop->SetItemHasChildren(root);
68     }
69 
70     wxString oldSelText;
71     wxString oldParentText;
72     bool oldParent_isRoot = false;
73     wxTreeItemId oldSel = m_pTreeTop->GetSelection();
74     if (oldSel.IsOk())
75     {
76         oldSelText = m_pTreeTop->GetItemText(oldSel);
77         wxTreeItemId oldParent = m_pTreeTop->GetItemParent(oldSel);
78         oldParent_isRoot = (root == oldParent);
79         if (oldParent.IsOk())
80         {
81             oldParentText = m_pTreeTop->GetItemText(oldParent);
82         }
83     }
84 
85     m_pTreeTop->Hide();
86     m_pTreeTop->Freeze();
87     wxArrayString expandedBottomNodes;
88     if (m_Options.visibleBottomTree)
89     {
90         MakeExpandedNodesArray(expandedBottomNodes);
91         m_pTreeBottom->Hide();
92         m_pTreeBottom->Freeze();
93     }
94 
95     m_pTreeTop->DeleteChildren(root);
96 
97     wxTreeItemId root_bot = m_pTreeBottom->GetRootItem();
98     if (root_bot.IsOk())
99         m_pTreeBottom->DeleteChildren(root_bot);
100 
101     if (!Manager::IsAppShuttingDown())
102     {
103         ExpandTop();
104         m_pTreeTop->Expand(root);
105         if (!m_Options.visibleBottomTree)
106         {
107             size_t i=0;
108             while ( i < m_ExpandedNodes.GetCount() )
109             {
110                 wxTreeItemId item = FindItemByName(m_pTreeTop, m_ExpandedNodes[i]);
111                 if (item.IsOk())
112                 {
113                     m_pTreeTop->Expand(item);
114                     i++;
115                 }
116                 else
117                 {
118                     m_ExpandedNodes.RemoveAt(i);
119                 }
120             }
121         }
122         else
123             m_ExpandedNodes.Clear();
124     }
125 
126     if (m_Options.visibleBottomTree)
127     {
128         m_pTreeBottom->Thaw();
129         m_pTreeBottom->Show();
130     }
131 
132     m_pTreeTop->Thaw();
133     m_pTreeTop->Show();
134 
135     m_AtWork = false;
136 
137     if (!oldSelText.IsEmpty())
138     {
139         if ( !oldParent_isRoot )
140         {
141             wxTreeItemId item = FindItemByName(m_pTreeTop, oldParentText, oldSelText); // refresh selection
142             if (item.IsOk())
143                 m_pTreeTop->SelectItem(item);
144         }
145         else
146         {
147             wxTreeItemId item = FindItemByName(m_pTreeTop, oldSelText); // refresh selection
148             if (item.IsOk())
149             {
150                 m_pTreeTop->SelectItem(item);
151                 ExpandBottomNodes(expandedBottomNodes);
152             }
153         }
154     }
155 }
156 
DeleteTopRootChildren()157 void WorkspaceBrowserBuilder::DeleteTopRootChildren()
158 {
159     if (Manager::IsAppShuttingDown())
160         return;
161 
162     wxTreeItemId root = m_pTreeTop->GetRootItem();
163     if (root.IsOk())
164     {
165         m_pTreeTop->DeleteChildren(root);
166     }
167 }
168 
MakeExpandedNodesArray(wxArrayString & expandedBottomNodes)169 void WorkspaceBrowserBuilder::MakeExpandedNodesArray(wxArrayString &expandedBottomNodes)
170 {
171     if (!m_Options.visibleBottomTree)
172         return;
173 
174     wxTreeItemIdValue cookie;
175     wxTreeItemId root = m_pTreeBottom->GetRootItem();
176     if (!root.IsOk())
177         return;
178     wxTreeItemId item = m_pTreeBottom->GetFirstChild(root, cookie);
179     while (item.IsOk())
180     {
181         if (m_pTreeBottom->IsExpanded(item))
182         {
183             wxTreeItemIdValue cookie2;
184             wxTreeItemId item2 = m_pTreeBottom->GetFirstChild(item, cookie2);
185             while (item2.IsOk())
186             {
187                 if (m_pTreeBottom->IsExpanded(item2))
188                 {
189                     expandedBottomNodes.Add(m_pTreeBottom->GetItemText(item));
190                     expandedBottomNodes.Add(m_pTreeBottom->GetItemText(item2));
191                 }
192                 item2 = m_pTreeBottom->GetNextChild(item, cookie2);
193             }
194         }
195         item = m_pTreeBottom->GetNextChild(root, cookie);
196     }
197 }
198 
ExpandBottomNodes(wxArrayString & expandedBottomNodes)199 void WorkspaceBrowserBuilder::ExpandBottomNodes(wxArrayString &expandedBottomNodes)
200 {
201     if (!m_Options.visibleBottomTree)
202         return;
203 
204     for (size_t i=1; i<expandedBottomNodes.Count(); i+=2)
205     {
206         wxTreeItemId item = FindItemByName(m_pTreeBottom, expandedBottomNodes.Item(i-1), expandedBottomNodes.Item(i));
207         if (item.IsOk())
208             m_pTreeBottom->Expand(item);
209     }
210 }
211 
HasChildren(TokenF * tokenParent,int tokenKindMask)212 bool WorkspaceBrowserBuilder::HasChildren(TokenF* tokenParent, int tokenKindMask)
213 {
214     bool has = false;
215     size_t chilCount = tokenParent->m_Children.GetCount();
216     for (size_t j=0; j<chilCount; ++j)
217     {
218         TokenF* tok1 = tokenParent->m_Children.Item(j);
219         if (tok1->m_TokenKind & tokenKindMask)
220         {
221             has = true;
222             break;
223         }
224     }
225     return has;
226 }
227 
HasGlobalFunctionsOthers(int tokenKindMask)228 bool WorkspaceBrowserBuilder::HasGlobalFunctionsOthers(int tokenKindMask)
229 {
230     bool has = false;
231     if (Manager::IsAppShuttingDown())
232         return has;
233 
234     switch (m_Options.displayFilter)
235     {
236         case bdfFile:
237         {
238             if (!m_ActiveFilename.IsEmpty())
239                 has = FileHasTokens(UnixFilename(m_ActiveFilename), tokenKindMask);
240             break;
241         }
242         case bdfProject:
243         {
244             for (FilesList::iterator it = m_pActiveProject->GetFilesList().begin(); it != m_pActiveProject->GetFilesList().end(); ++it)
245             {
246                 ProjectFile* pf = *it;
247                 if (FileHasTokens(UnixFilename(pf->file.GetFullPath()), tokenKindMask))
248                 {
249                     has = true;
250                     break;
251                 }
252             }
253             break;
254         }
255         case bdfWorkspace:
256         {
257 
258             TokensArrayF* pTokens = m_pParser->GetTokens();
259             for (size_t i=0; i< pTokens->GetCount(); ++i)
260             {
261                 TokenF* token = pTokens->Item(i);
262                 if (token->m_TokenKind == tkFile)
263                 {
264                     for (size_t j=0; j < token->m_Children.GetCount(); ++j)
265                     {
266                         TokenF* tok1 = token->m_Children.Item(j);
267                         if (tok1->m_TokenKind & tokenKindMask)
268                         {
269                             has = true;
270                             break;
271                         }
272                     }
273                     if (has)
274                         break;
275                 }
276             }
277             break;
278         }
279     }
280     return has;
281 }
282 
FileHasTokens(const wxString & fileName,int tokenKindMask)283 bool WorkspaceBrowserBuilder::FileHasTokens(const wxString& fileName, int tokenKindMask)
284 {
285     TokensArrayF* pTokens = m_pParser->GetTokens();
286     bool has = false;
287 
288     for (size_t i=0; i< pTokens->GetCount(); ++i)
289     {
290         TokenF* token = pTokens->Item(i);
291 
292         if (token->m_TokenKind == tkFile && token->m_Filename.IsSameAs(fileName))
293         {
294             for (size_t j=0; j < token->m_Children.GetCount(); ++j)
295             {
296                 TokenF* tok1 = token->m_Children.Item(j);
297                 if (tok1->m_TokenKind & tokenKindMask)
298                 {
299                     has = true;
300                     break;
301                 }
302             }
303             break;
304         }
305     }
306     return has;
307 }
308 
AddTreeChildren(wxTreeCtrl * tree,wxTreeItemId parent,int tokenKindMask)309 void WorkspaceBrowserBuilder::AddTreeChildren(wxTreeCtrl* tree, wxTreeItemId parent, int tokenKindMask)
310 {
311     if (Manager::IsAppShuttingDown())
312         return;
313 
314     switch (m_Options.displayFilter)
315     {
316         case bdfFile:
317         {
318             if (!m_ActiveFilename.IsEmpty() &&
319                 (!m_Options.showIncludeSeparately ||
320                  (m_Options.showIncludeSeparately && !m_pParser->IsIncludeFile(m_ActiveFilename))))
321             {
322                 AddFileNodes(tree, parent, UnixFilename(m_ActiveFilename), tokenKindMask);
323             }
324             break;
325         }
326         case bdfProject:
327         {
328             for (FilesList::iterator it = m_pActiveProject->GetFilesList().begin(); it != m_pActiveProject->GetFilesList().end(); ++it)
329             {
330                 ProjectFile* pf = *it;
331                 if (!m_Options.showIncludeSeparately ||
332                     (m_Options.showIncludeSeparately && !m_pParser->IsIncludeFile(pf->file.GetFullPath())))
333                     AddFileNodes(tree, parent, UnixFilename(pf->file.GetFullPath()), tokenKindMask);
334             }
335             break;
336         }
337         case bdfWorkspace:
338         {
339             TokensArrayF* pTokens = m_pParser->GetTokens();
340             if (!pTokens)
341                 break;
342             for (size_t i=0; i< pTokens->GetCount(); ++i)
343             {
344                 TokenF* token = pTokens->Item(i);
345                 if (token->m_TokenKind == tkFile &&
346                     (!m_Options.showIncludeSeparately ||
347                      (m_Options.showIncludeSeparately && !m_pParser->IsIncludeFile(token->m_Filename))))
348                 {
349                     AddChildrenNodes(tree, parent, token, tokenKindMask);
350                 }
351             }
352             break;
353         }
354     }
355 }
356 
AddFileNodes(wxTreeCtrl * tree,wxTreeItemId parent,wxString file,int tokenKindMask)357 bool WorkspaceBrowserBuilder::AddFileNodes(wxTreeCtrl* tree, wxTreeItemId parent, wxString file, int tokenKindMask)
358 {
359     TokensArrayF* pTokens = m_pParser->GetTokens();
360 
361     size_t tokCount = pTokens->GetCount();
362     for (size_t i=0; i<tokCount; ++i)
363     {
364         TokenF* token = pTokens->Item(i);
365 
366         if (token->m_TokenKind == tkFile && token->m_Filename.IsSameAs(file))
367         {
368             return AddChildrenNodes(tree, parent, token, tokenKindMask);
369         }
370     }
371     return false;
372 }
373 
AddChildrenNodes(wxTreeCtrl * tree,wxTreeItemId parent,TokenF * parToken,int tokenKindMask)374 bool WorkspaceBrowserBuilder::AddChildrenNodes(wxTreeCtrl* tree, wxTreeItemId parent, TokenF* parToken, int tokenKindMask)
375 {
376     int count = 0;
377     bool sorted = m_Options.sortAlphabetically || (tree == m_pTreeTop && parToken->m_TokenKind == tkFile);
378     TokensArrayF* pTokens = &parToken->m_Children;
379 
380     if (parToken->m_TokenKind == tkType)
381     {
382         count += AddTypeChildren(tree, parent, pTokens);
383         return count != 0;
384     }
385 
386     int childKM = tkFunction | tkProgram | tkSubroutine | tkPreprocessor | tkInterface | tkInterfaceExplicit | tkBlockData |
387                     tkType | tkVariable | tkProcedure | tkAccessList;
388     int interfaceMask = tkInterface | tkInterfaceExplicit;
389     int funChildKM = childKM ^ tkVariable;
390 
391     if (!m_Options.showLocalVariables && (parToken->m_TokenKind == tkSubroutine || parToken->m_TokenKind == tkFunction || parToken->m_TokenKind == tkProgram))
392     {
393         childKM = childKM ^ tkVariable;
394         if (tokenKindMask & tkVariable)
395             tokenKindMask = tokenKindMask ^ tkVariable;
396     }
397 
398     size_t tokCount = pTokens->GetCount();
399     for (size_t i=0; i<tokCount; ++i)
400     {
401         TokenF* token = pTokens->Item(i);
402         if (token->m_TokenKind & tokenKindMask)
403         {
404             if (token->m_TokenKind & interfaceMask)
405             {
406                 count += AddInterfaceNode(tree, parent, token);
407             }
408             else
409             {
410                 wxString nameDisp = token->m_DisplayName;
411                 if (token->m_TokenKind == tkVariable)
412                     nameDisp << _T(" : ") << token->m_PartFirst;
413                 wxTreeItemId idni = AddNodeIfNotThere(tree, parent, nameDisp, GetTokenKindImageIdx(token), new TreeDataF(sfToken, token), sorted);
414                 count++;
415                 if (tree == m_pTreeTop && !m_Options.visibleBottomTree)
416                 {
417                     if (!m_Options.showLocalVariables && (token->m_TokenKind == tkSubroutine || token->m_TokenKind == tkFunction))
418                     {
419                         if (HasChildren(token, funChildKM))
420                             tree->SetItemHasChildren(idni);
421                     }
422                     else
423                     {
424                         if (HasChildren(token, childKM))
425                             tree->SetItemHasChildren(idni);
426                     }
427                 }
428                 else if(tree == m_pTreeBottom && HasChildren(token, childKM))
429                 {
430                     AddChildrenNodes(tree, idni, token, childKM);
431                 }
432             }
433         }
434     }
435     return count != 0;
436 }
437 
AddInterfaceNode(wxTreeCtrl * tree,wxTreeItemId parent,TokenF * parToken)438 int WorkspaceBrowserBuilder::AddInterfaceNode(wxTreeCtrl* tree, wxTreeItemId parent, TokenF* parToken)
439 {
440     int count = 0;
441     bool sorted = m_Options.sortAlphabetically;
442 
443     if (!parToken->m_Name.IsEmpty())
444     {
445         wxString name;
446         if (parToken->m_DisplayName.StartsWith(_T("%%")))
447         {
448             name = parToken->m_DisplayName.Mid(2);
449         }
450         else
451         {
452             name = parToken->m_DisplayName;
453         }
454         AddNodeIfNotThere(tree, parent, name, GetTokenKindImageIdx(parToken), new TreeDataF(sfToken, parToken), sorted);
455         count++;
456     }
457     else
458     {
459         TokensArrayF* pTokens = &parToken->m_Children;
460         if (pTokens)
461         {
462             int childKM = tkFunction | tkSubroutine;
463             int imageIdx;
464             for (size_t i=0; i< pTokens->GetCount(); ++i)
465             {
466                 TokenF* token = pTokens->Item(i);
467                 if (token->m_TokenKind & childKM)
468                 {
469                     if (token->m_TokenKind == tkFunction)
470                     {
471                         if (token->m_TokenAccess == taPublic)
472                             imageIdx = m_pImlist->GetImageIdx("interface_function");
473                         else
474                             imageIdx = m_pImlist->GetImageIdx("interface_function_private");
475                     }
476                     else
477                     {
478                         if (token->m_TokenAccess == taPublic)
479                             imageIdx = m_pImlist->GetImageIdx("interface_subroutine");
480                         else
481                             imageIdx = m_pImlist->GetImageIdx("interface_subroutine_private");
482                     }
483                     AddNodeIfNotThere(tree, parent, token->m_DisplayName, imageIdx, new TreeDataF(sfToken, token), sorted);
484                     count++;
485                 }
486             }
487         }
488     }
489     return count;
490 }
491 
AddTypeChildren(wxTreeCtrl * tree,wxTreeItemId parent,TokensArrayF * pTokens)492 int WorkspaceBrowserBuilder::AddTypeChildren(wxTreeCtrl* tree, wxTreeItemId parent, TokensArrayF* pTokens)
493 {
494     int count = 0;
495     bool sorted = m_Options.sortAlphabetically;
496     TokensArrayF varTokens;
497     TokensArrayF otherTokens;
498 
499     size_t tokCount = pTokens->GetCount();
500     for (size_t i=0; i<tokCount; ++i)
501     {
502         TokenF* token = pTokens->Item(i);
503         if (token->m_TokenKind == tkVariable)
504         {
505             if (sorted)
506             {
507                 size_t j;
508                 for (j=0; j<varTokens.GetCount(); j++)
509                 {
510                     if (token->m_DisplayName.CmpNoCase(varTokens.Item(j)->m_DisplayName) < 0)
511                         break;
512                 }
513                 varTokens.Insert(token, j);
514             }
515             else
516             {
517                 varTokens.Add(token);
518             }
519         }
520         else
521         {
522             if (sorted)
523             {
524                 wxString name;
525                 if (token->m_DisplayName.StartsWith(_T("%%")))
526                     name = token->m_DisplayName.Mid(2);
527                 else
528                     name = token->m_DisplayName;
529                 size_t j;
530                 for (j=0; j<otherTokens.GetCount(); j++)
531                 {
532                     if (name.CmpNoCase(otherTokens.Item(j)->m_DisplayName) < 0)
533                         break;
534                 }
535                 otherTokens.Insert(token, j);
536             }
537             else
538             {
539                 otherTokens.Add(token);
540             }
541         }
542     }
543 
544     tokCount = varTokens.GetCount();
545     for (size_t i=0; i<tokCount; ++i)
546     {
547         wxString nameDisp;
548         nameDisp << varTokens.Item(i)->m_DisplayName << _T(" : ") << varTokens.Item(i)->m_PartFirst;
549         AddNodeIfNotThere(tree, parent, nameDisp,
550                           GetTokenKindImageIdx(varTokens.Item(i)), new TreeDataF(sfToken, varTokens.Item(i)), false);
551         count++;
552     }
553 
554     tokCount = otherTokens.GetCount();
555     for (size_t i=0; i<tokCount; ++i)
556     {
557         wxString name;
558         if (otherTokens.Item(i)->m_DisplayName.StartsWith(_T("%%")))
559             name = otherTokens.Item(i)->m_DisplayName.Mid(2);
560         else
561             name = otherTokens.Item(i)->m_DisplayName;
562         AddNodeIfNotThere(tree, parent, name,
563                           GetTokenKindImageIdx(otherTokens.Item(i)), new TreeDataF(sfToken, otherTokens.Item(i)), false);
564         count++;
565     }
566 
567     return count;
568 }
569 
SelectNode(wxTreeItemId node)570 bool WorkspaceBrowserBuilder::SelectNode(wxTreeItemId node)
571 {
572     // m_pTreeTop node was selected
573     if (Manager::IsAppShuttingDown() || (!(node.IsOk())) || m_AtWork)
574         return false;
575 
576     m_pTreeBottom->Freeze();
577     wxTreeItemId root = m_pTreeBottom->GetRootItem();
578     if (!root)
579         root = m_pTreeBottom->AddRoot(_T("Members"));
580     else
581         m_pTreeBottom->DeleteChildren(root);
582     TreeDataF* data = (TreeDataF*)m_pTreeTop->GetItemData(node);
583     if (data)
584     {
585         switch (data->m_SpecialFolder)
586         {
587             case sfGFuncs:
588             {
589                 AddTreeChildren(m_pTreeBottom, root, tkFunction | tkProgram | tkSubroutine);
590                 break;
591             }
592             case sfOthers:
593             {
594                 AddTreeChildren(m_pTreeBottom, root, tkPreprocessor | tkInterface | tkBlockData);
595                 if (m_Options.showIncludeSeparately)
596                     AddIncludeFiles(m_pTreeBottom, root);
597                 break;
598             }
599             case sfToken:
600             {
601 				wxTreeItemId rootTypes = m_pTreeBottom->AppendItem(root, _("Types"), m_pImlist->GetImageIdx("typedefs_folder"));
602 				wxTreeItemId rootOthers = m_pTreeBottom->AppendItem(root, _("Others"), m_pImlist->GetImageIdx("others_folder"));
603 				wxTreeItemId rootFuncs = m_pTreeBottom->AppendItem(root, _("Procedures"), m_pImlist->GetImageIdx("function_folder"));
604 
605                 TokenF* pToken = data->m_pToken;
606                 AddChildrenNodes(m_pTreeBottom, rootTypes, pToken, tkType);
607                 AddChildrenNodes(m_pTreeBottom, rootOthers, pToken, tkInterface | tkInterfaceExplicit | tkAccessList | tkVariable);
608                 AddChildrenNodes(m_pTreeBottom, rootFuncs, pToken, tkFunction | tkSubroutine | tkProcedure);
609 
610                 m_pTreeBottom->Expand(rootTypes);
611                 m_pTreeBottom->Expand(rootOthers);
612                 m_pTreeBottom->Expand(rootFuncs);
613                 //ExpandAll();
614 
615                 break;
616             }
617             default: break;
618         }
619     }
620     m_pTreeBottom->Thaw();
621     return true;
622 }
623 
AddNodeIfNotThere(wxTreeCtrl * tree,wxTreeItemId parent,const wxString & name,int imgIndex,TreeDataF * data,bool sorted)624 wxTreeItemId WorkspaceBrowserBuilder::AddNodeIfNotThere(wxTreeCtrl* tree, wxTreeItemId parent, const wxString& name, int imgIndex, TreeDataF* data, bool sorted)
625 {
626     SpecialFolder new_type = data->m_SpecialFolder;
627 
628     wxTreeItemIdValue cookie = 0;
629 
630     wxTreeItemId insert_after; // node to insert after; we 'll be looping all children so we might as well sort at the same time
631     wxTreeItemId existing = tree->GetFirstChild(parent, cookie);
632     while (existing.IsOk())
633     {
634         wxString itemText = tree->GetItemText(existing);
635         if (itemText.IsSameAs(name))
636         {
637             if (tree->GetItemImage(existing) == imgIndex)
638             {
639                 tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Normal);
640                 tree->SetItemImage(existing, imgIndex, wxTreeItemIcon_Selected);
641                 delete tree->GetItemData(existing); // make Valgrind happy
642                 tree->SetItemData(existing, data);
643 
644                 return existing;
645             }
646         }
647 
648         if (sorted)
649         {
650             TreeDataF* existing_data = (TreeDataF*)tree->GetItemData(existing);
651             if (existing_data)
652             {
653                 SpecialFolder existing_type = existing_data->m_SpecialFolder;
654 
655                 // first go special folders
656                 if ((existing_type & (sfGFuncs | sfOthers)) &&
657                     !(new_type & (sfGFuncs | sfOthers)))
658                 {
659                     insert_after = existing;
660                 }
661                 // then everything else, alphabetically
662                 else if (name.CmpNoCase(itemText) >= 0)
663                 {
664                     insert_after = existing;
665                 }
666                 else // name.CmpNoCase(itemText) < 0
667                 {
668                     break;
669                 }
670             }
671         }
672         existing = tree->GetNextChild(parent, cookie);
673     }
674 
675     if (sorted)
676         existing = tree->InsertItem(parent, insert_after, name, imgIndex, imgIndex, data);
677     else
678         existing = tree->AppendItem(parent, name, imgIndex, imgIndex, data);
679     return existing;
680 }
681 
CreateSpecialFolders()682 void WorkspaceBrowserBuilder::CreateSpecialFolders()
683 {
684     wxTreeItemId parent = m_pTreeTop->GetRootItem();
685     wxTreeItemId gfuncs = AddNodeIfNotThere(m_pTreeTop, parent, _("Global procedures"), m_pImlist->GetImageIdx("function_folder"), new TreeDataF(sfGFuncs, 0));
686     wxTreeItemId others = AddNodeIfNotThere(m_pTreeTop, parent, _("Others"), m_pImlist->GetImageIdx("others_folder"), new TreeDataF(sfOthers, 0));
687 
688     if (!m_Options.visibleBottomTree)
689     {
690         if (HasGlobalFunctionsOthers(tkFunction | tkProgram | tkSubroutine))
691             m_pTreeTop->SetItemHasChildren(gfuncs);
692         if (HasGlobalFunctionsOthers(tkPreprocessor | tkInterface | tkBlockData) ||
693             (m_Options.showIncludeSeparately && m_pParser->HasIncludeFiles()))
694             m_pTreeTop->SetItemHasChildren(others);
695     }
696 }
697 
ExpandTop()698 void WorkspaceBrowserBuilder::ExpandTop()
699 {
700     if (Manager::IsAppShuttingDown())
701         return;
702 
703     CreateSpecialFolders();
704     wxTreeItemId root = m_pTreeTop->GetRootItem();
705     AddTreeChildren(m_pTreeTop, root, tkModule | tkSubmodule);
706 }
707 
ExpandTopNode(wxTreeItemId node)708 void WorkspaceBrowserBuilder::ExpandTopNode(wxTreeItemId node)
709 {
710     if (Manager::IsAppShuttingDown() || (!(node.IsOk())) || (node == m_pTreeTop->GetRootItem()))
711         return;
712 
713     m_pTreeTop->Freeze();
714     TreeDataF* data = (TreeDataF*)m_pTreeTop->GetItemData(node);
715     if (data)
716     {
717         wxString disName;
718         switch (data->m_SpecialFolder)
719         {
720             case sfGFuncs:
721             {
722                 AddTreeChildren(m_pTreeTop, node, tkFunction | tkProgram | tkSubroutine);
723                 break;
724             }
725             case sfOthers:
726             {
727                 AddTreeChildren(m_pTreeTop, node, tkPreprocessor | tkInterface | tkBlockData);
728                 if (m_Options.showIncludeSeparately)
729                     AddIncludeFiles(m_pTreeTop, node);
730                 break;
731             }
732             case sfToken:
733             {
734                 TokenF* pToken = data->m_pToken;
735                 AddChildrenNodes(m_pTreeTop, node, pToken, tkFunction | tkSubroutine | tkInterface | tkType | tkVariable |
736                                  tkProcedure | tkAccessList | tkInterfaceExplicit);
737                 break;
738             }
739             default: break;
740         }
741         disName = m_pTreeTop->GetItemText(node);
742         if (m_ExpandedNodes.Index(disName) == wxNOT_FOUND)
743             m_ExpandedNodes.Add(disName);
744     }
745     m_pTreeTop->Thaw();
746 }
747 
CollapsTopNode(wxTreeItemId node)748 void WorkspaceBrowserBuilder::CollapsTopNode(wxTreeItemId node)
749 {
750     if (Manager::IsAppShuttingDown() || (!(node.IsOk())) || (node == m_pTreeTop->GetRootItem()))
751         return;
752 
753     int indx = m_ExpandedNodes.Index(m_pTreeTop->GetItemText(node));
754     if (indx != wxNOT_FOUND)
755     {
756         m_ExpandedNodes.RemoveAt(indx);
757     }
758 }
759 
SelectItem(TokenF * token)760 void WorkspaceBrowserBuilder::SelectItem(TokenF* token)
761 {
762     if (Manager::IsAppShuttingDown())
763         return;
764 
765     wxTreeItemId item;
766     if (token && token->m_pParent)
767     {
768         if (token->m_pParent->m_TokenKind == tkFile)
769         {
770             if (token->m_TokenKind == tkFunction)
771             {
772                 item = FindItemByName(m_pTreeTop, _("Global procedures"));
773                 if (item.IsOk())
774                 {
775                     m_pTreeTop->SelectItem(item);
776                     item = FindItemByName(m_pTreeBottom, token->m_DisplayName);
777                     if (item.IsOk())
778                         m_pTreeBottom->SelectItem(item);
779                 }
780             }
781             else if (token->m_TokenKind == tkPreprocessor)
782             {
783                 item = FindItemByName(m_pTreeTop, _("Preprocessor symbols"));
784                 if (item.IsOk())
785                 {
786                     m_pTreeTop->SelectItem(item);
787                     item = FindItemByName(m_pTreeBottom, token->m_DisplayName);
788                     if (item.IsOk())
789                         m_pTreeBottom->SelectItem(item);
790                 }
791             }
792             else if (token->m_TokenKind == tkModule || token->m_TokenKind == tkSubmodule)
793             {
794                 item = FindItemByName(m_pTreeTop, token->m_DisplayName);
795                 if (item.IsOk())
796                     m_pTreeTop->SelectItem(item);
797             }
798         }
799         else if (token->m_pParent->m_TokenKind == tkModule || token->m_pParent->m_TokenKind == tkSubmodule)
800         {
801             item = FindItemByName(m_pTreeTop, token->m_pParent->m_DisplayName);
802             if (item.IsOk())
803             {
804                 m_pTreeTop->SelectItem(item);
805                 item = FindItemByName(m_pTreeBottom, token->m_DisplayName);
806                 if (item.IsOk())
807                     m_pTreeBottom->SelectItem(item);
808             }
809         }
810     }
811 }
812 
FindItemByName(wxTreeCtrl * tree,wxString name,wxString name2)813 wxTreeItemId WorkspaceBrowserBuilder::FindItemByName(wxTreeCtrl* tree, wxString name, wxString name2)
814 {
815     bool foundFirst = false;
816     wxTreeItemId firstItem;
817 
818     wxTreeItemIdValue cookie;
819     wxTreeItemId root = tree->GetRootItem();
820     if (!root.IsOk())
821         return root;
822     wxTreeItemId item = tree->GetFirstChild(root, cookie);
823     while (item.IsOk())
824     {
825         if (tree->GetItemText(item).IsSameAs(name))
826         {
827             if (name2.IsEmpty())
828                 return item;
829             else
830             {
831                 firstItem = item;
832                 foundFirst = true;
833                 break;
834             }
835         }
836         else if(name2.IsEmpty())
837         {
838             wxTreeItemIdValue cookie2;
839             wxTreeItemId item2 = tree->GetFirstChild(item, cookie2);
840             while (item2.IsOk())
841             {
842                 if (tree->GetItemText(item2).IsSameAs(name))
843                 {
844                     return item2;
845                 }
846                 item2 = tree->GetNextChild(item, cookie2);
847             }
848         }
849         item = tree->GetNextChild(root, cookie);
850     }
851     if (!name2.IsEmpty() && foundFirst)
852     {
853         wxTreeItemIdValue cookie3;
854         wxTreeItemId item2 = tree->GetFirstChild(firstItem, cookie3);
855         while (item2.IsOk())
856         {
857             if (tree->GetItemText(item2).IsSameAs(name2))
858             {
859                 return item2;
860             }
861             item2 = tree->GetNextChild(item, cookie3);
862         }
863         return firstItem;
864     }
865     item.Unset();
866 	return item;
867 }
868 
GetTokenKindImageIdx(TokenF * token)869 int WorkspaceBrowserBuilder::GetTokenKindImageIdx(TokenF* token)
870 {
871     return m_pImlist->GetTokenKindImageIdx(token);
872 }
873 
SelectSymbol(const wxString & filename,int line)874 void WorkspaceBrowserBuilder::SelectSymbol(const wxString& filename, int line)
875 {
876     if (Manager::IsAppShuttingDown() || m_AtWork)
877         return;
878 
879     bool found = false;
880     wxTreeItemIdValue cookie;
881     wxTreeItemId root = m_pTreeTop->GetRootItem();
882     if(!root.IsOk())
883         return;
884     wxTreeItemId item = m_pTreeTop->GetFirstChild(root, cookie);
885     wxTreeItemId itemGlob;
886     bool haveGlob = false;
887     wxTreeItemId itemOthers;
888     while (item.IsOk())
889     {
890         TreeDataF* data = (TreeDataF*)m_pTreeTop->GetItemData(item);
891         if (data)
892         {
893             switch (data->m_SpecialFolder)
894             {
895                 case sfGFuncs:
896                 {
897                     itemGlob = item;
898                     haveGlob = true;
899                     break;
900                 }
901                 case sfToken:
902                 {
903                     if (data->m_pToken->m_Filename.IsSameAs(filename))
904                     {
905                         if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
906                         {
907                             m_pTreeTop->SelectItem(item);
908                             if (m_Options.visibleBottomTree)
909                             {
910                                 SelectBottomSymbol(filename, line);
911                             }
912                             found = true;
913                         }
914                     }
915                     break;
916                 }
917                 default:
918                 {
919                     break;
920                 }
921             }
922             if (found)
923                 break;
924         }
925         item = m_pTreeTop->GetNextChild(root, cookie);
926     }
927 
928     if (!found && haveGlob)
929     {
930         if (m_Options.visibleBottomTree)
931         {
932             m_pTreeTop->SelectItem(itemGlob);
933             SelectBottomSymbol(filename, line);
934         }
935     }
936 }
937 
SelectBottomSymbol(const wxString & filename,int line)938 bool WorkspaceBrowserBuilder::SelectBottomSymbol(const wxString& filename, int line)
939 {
940     wxTreeItemIdValue cookie;
941     wxTreeItemId root = m_pTreeBottom->GetRootItem();
942     if (!root.IsOk())
943         return false;
944     wxTreeItemId item = m_pTreeBottom->GetFirstChild(root, cookie);
945     while (item.IsOk())
946     {
947         TreeDataF* data = (TreeDataF*)m_pTreeBottom->GetItemData(item);
948         if (data)
949         {
950             if (data->m_SpecialFolder == sfToken)
951             {
952                 if (data->m_pToken->m_Filename.IsSameAs(filename))
953                 {
954                     if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
955                     {
956                         m_pTreeBottom->SelectItem(item);
957                         return true;
958                     }
959                 }
960             }
961             else if(data->m_SpecialFolder == sfFile)
962             {
963                 if (data->m_pToken->m_Filename.IsSameAs(filename))
964                 {
965                     m_pTreeBottom->SelectItem(item);
966                     return true;
967                 }
968             }
969         }
970         else
971         {
972             wxTreeItemIdValue cookie2;
973             wxTreeItemId item2 = m_pTreeBottom->GetFirstChild(item, cookie2);
974             while (item2.IsOk())
975             {
976                 TreeDataF* data2 = (TreeDataF*)m_pTreeBottom->GetItemData(item2);
977                 if (data2)
978                 {
979                     if (data2->m_SpecialFolder == sfToken)
980                     {
981                         if (data2->m_pToken->m_Filename.IsSameAs(filename)
982                             && (int)data2->m_pToken->m_LineStart <= line
983                             && (int)data2->m_pToken->m_LineEnd >= line)
984                         {
985                             m_pTreeBottom->SelectItem(item2);
986                             return true;
987                         }
988                     }
989                 }
990                 item2 = m_pTreeBottom->GetNextChild(item, cookie2);
991             }
992         }
993         item = m_pTreeBottom->GetNextChild(root, cookie);
994     }
995     return false;
996 }
997 
MarkSymbol(const wxString & filename,int line)998 void WorkspaceBrowserBuilder::MarkSymbol(const wxString& filename, int line)
999 {
1000     if (Manager::IsAppShuttingDown() || m_AtWork)
1001         return;
1002 
1003     bool found = false;
1004     bool unmarked = true;
1005     wxTreeItemIdValue cookie;
1006     wxTreeItemId root = m_pTreeTop->GetRootItem();
1007     if(!root.IsOk())
1008         return;
1009     wxTreeItemId item = m_pTreeTop->GetFirstChild(root, cookie);
1010     wxTreeItemId itemGlob;
1011     bool haveGlob = false;
1012     wxTreeItemId itemOthers;
1013     bool haveOthers = false;
1014     while (item.IsOk())
1015     {
1016         TreeDataF* data = (TreeDataF*)m_pTreeTop->GetItemData(item);
1017         if (data)
1018         {
1019             switch (data->m_SpecialFolder)
1020             {
1021                 case sfGFuncs:
1022                 {
1023                     itemGlob = item;
1024                     haveGlob = true;
1025                     break;
1026                 }
1027                 case sfOthers:
1028                 {
1029                     itemOthers = item;
1030                     haveOthers = true;
1031                     break;
1032                 }
1033                 case sfToken:
1034                 {
1035                     if (m_pTreeTop->IsBold(item))
1036                     {
1037                         if (!data->m_pToken->m_Filename.IsSameAs(filename)
1038                             || ((int)data->m_pToken->m_LineStart > line)
1039                             || ((int)data->m_pToken->m_LineEnd < line))
1040                         {
1041                             MarkItem(m_pTreeTop, item, false);
1042                             if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(item))
1043                             {
1044                                 MarkChildSymbol(m_pTreeTop, item, line, false);
1045                             }
1046                             unmarked = true;
1047                         }
1048                         else
1049                             unmarked = false;
1050                     }
1051                     if (!found)
1052                     {
1053                         if (data->m_pToken->m_Filename.IsSameAs(filename))
1054                         {
1055                             if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
1056                             {
1057                                 if (unmarked)
1058                                     MarkItem(m_pTreeTop, item);
1059                                 if ((m_pTreeTop->GetSelection() == item) && m_Options.visibleBottomTree)
1060                                 {
1061                                     MarkBottomSymbol(filename, line);
1062                                 }
1063                                 else if (m_Options.visibleBottomTree)
1064                                 {
1065                                     UnmarkBottomSymbol();
1066                                 }
1067                                 else if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(item))
1068                                 {
1069                                     MarkChildSymbol(m_pTreeTop, item, line);
1070                                 }
1071                                 found = true;
1072                             }
1073                         }
1074                     }
1075                     break;
1076                 }
1077                 default:
1078                 {
1079                     break;
1080                 }
1081             }
1082         }
1083         item = m_pTreeTop->GetNextChild(root, cookie);
1084     }
1085 
1086     if (haveGlob && found)
1087     {
1088         if (m_Options.visibleBottomTree && (m_pTreeTop->GetSelection() == itemGlob))
1089         {
1090             UnmarkBottomSymbol();
1091         }
1092         else if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(itemGlob) &&  m_pTreeTop->GetLastChild(itemGlob).IsOk())
1093         {
1094             MarkChildSymbol(m_pTreeTop, itemGlob, line, false);
1095         }
1096         if (m_pTreeTop->IsBold(itemGlob))
1097             MarkItem(m_pTreeTop, itemGlob, false);
1098     }
1099     else if (haveGlob)
1100     {
1101         bool foundGlob = false;
1102         if (m_Options.visibleBottomTree && (m_pTreeTop->GetSelection() == itemGlob))
1103         {
1104             foundGlob = MarkBottomSymbol(filename, line);
1105         }
1106         else if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(itemGlob) &&  m_pTreeTop->GetLastChild(itemGlob).IsOk())
1107         {
1108             foundGlob = MarkGlobalSymbol(m_pTreeTop, itemGlob, filename, line);
1109         }
1110         else
1111         {
1112             foundGlob = IsLineInGlobals(filename, line);
1113             if (m_Options.visibleBottomTree && foundGlob && (m_pTreeTop->GetSelection() != itemGlob))
1114             {
1115                 UnmarkBottomSymbol();
1116             }
1117         }
1118         if (foundGlob)
1119         {
1120             MarkItem(m_pTreeTop, itemGlob);
1121             found = true;
1122         }
1123         else if (m_pTreeTop->IsBold(itemGlob))
1124         {
1125             MarkItem(m_pTreeTop, itemGlob, false);
1126         }
1127     }
1128 
1129     if (haveOthers && found)
1130     {
1131         if (m_Options.visibleBottomTree && (m_pTreeTop->GetSelection() == itemOthers))
1132         {
1133             UnmarkBottomSymbol();
1134         }
1135         else if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(itemOthers) &&  m_pTreeTop->GetLastChild(itemOthers).IsOk())
1136         {
1137             MarkChildSymbol(m_pTreeTop, itemOthers, line, false);
1138             MarkGlobalSymbol(m_pTreeTop, itemOthers, filename, line);
1139         }
1140         if (m_pTreeTop->IsBold(itemOthers))
1141             MarkItem(m_pTreeTop, itemOthers, false);
1142     }
1143     else if (haveOthers)
1144     {
1145         bool foundOthers = false;
1146         if (m_Options.visibleBottomTree && (m_pTreeTop->GetSelection() == itemOthers))
1147         {
1148             foundOthers = MarkBottomSymbol(filename, line);
1149         }
1150         else if (!m_Options.visibleBottomTree && m_pTreeTop->HasChildren(itemOthers) &&  m_pTreeTop->GetLastChild(itemOthers).IsOk())
1151         {
1152             foundOthers = MarkGlobalSymbol(m_pTreeTop, itemOthers, filename, line);
1153         }
1154         else
1155         {
1156             foundOthers = (m_Options.showIncludeSeparately && m_pParser->IsIncludeFile(filename));
1157             if (m_Options.visibleBottomTree && foundOthers && (m_pTreeTop->GetSelection() != itemOthers))
1158             {
1159                 UnmarkBottomSymbol();
1160             }
1161         }
1162         if (foundOthers)
1163         {
1164             MarkItem(m_pTreeTop, itemOthers);
1165             found = true;
1166         }
1167         else if (m_pTreeTop->IsBold(itemOthers))
1168         {
1169             MarkItem(m_pTreeTop, itemOthers, false);
1170         }
1171     }
1172 
1173     if (!found && m_Options.visibleBottomTree)
1174     {
1175         UnmarkBottomSymbol();
1176     }
1177 }
1178 
MarkItem(wxTreeCtrl * tree,wxTreeItemId & item,bool mark)1179 void WorkspaceBrowserBuilder::MarkItem(wxTreeCtrl* tree, wxTreeItemId& item, bool mark)
1180 {
1181     if (item.IsOk())
1182     {
1183         tree->SetItemBold(item, mark);
1184 #ifdef __WXGTK__
1185         tree->Refresh();
1186 #endif
1187     }
1188 }
1189 
MarkBottomSymbol(const wxString & filename,int line)1190 bool WorkspaceBrowserBuilder::MarkBottomSymbol(const wxString& filename, int line)
1191 {
1192     bool found = false;
1193     bool foundFile = false;
1194     bool unmarked = true;
1195     wxTreeItemIdValue cookie;
1196     wxTreeItemId root = m_pTreeBottom->GetRootItem();
1197     if (!root.IsOk())
1198         return false;
1199     wxTreeItemId item = m_pTreeBottom->GetFirstChild(root, cookie);
1200     while (item.IsOk())
1201     {
1202         bool goInside = false;
1203         TreeDataF* data = (TreeDataF*)m_pTreeBottom->GetItemData(item);
1204         if (data)
1205         {
1206             if (data->m_SpecialFolder == sfToken)
1207             {
1208                 if (m_pTreeBottom->IsBold(item))
1209                 {
1210                     if (!data->m_pToken->m_Filename.IsSameAs(filename)
1211                         || (int)data->m_pToken->m_LineStart > line
1212                         || (int)data->m_pToken->m_LineEnd < line)
1213                     {
1214                         MarkItem(m_pTreeBottom, item, false);
1215                         unmarked = true;
1216                     }
1217                     else
1218                         unmarked = false;
1219                 }
1220                 if (!found)
1221                 {
1222                     if (data->m_pToken->m_Filename.IsSameAs(filename))
1223                     {
1224                         if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
1225                         {
1226                             if (unmarked)
1227                                 MarkItem(m_pTreeBottom, item);
1228                             found = true;
1229                         }
1230                     }
1231                 }
1232             }
1233             else if(data->m_SpecialFolder == sfFile)
1234             {
1235                 if (data->m_pToken->m_Filename.IsSameAs(filename))
1236                 {
1237                     MarkItem(m_pTreeBottom, item);
1238                     goInside = true;
1239                     foundFile = true;
1240                 }
1241                 else
1242                     MarkItem(m_pTreeBottom, item, false);
1243             }
1244         }
1245         else
1246             goInside = true;
1247 
1248         if (goInside)
1249         {
1250             bool unmarked2 = true;
1251             wxTreeItemIdValue cookie2;
1252             wxTreeItemId item2 = m_pTreeBottom->GetFirstChild(item, cookie2);
1253             while (item2.IsOk())
1254             {
1255                 TreeDataF* data2 = (TreeDataF*)m_pTreeBottom->GetItemData(item2);
1256                 if (data2)
1257                 {
1258                     if (data2->m_SpecialFolder == sfToken)
1259                     {
1260                         if (m_pTreeBottom->IsBold(item2))
1261                         {
1262                             if (!data2->m_pToken->m_Filename.IsSameAs(filename)
1263                                 || (int)data2->m_pToken->m_LineStart > line
1264                                 || (int)data2->m_pToken->m_LineEnd < line)
1265                             {
1266                                 MarkItem(m_pTreeBottom, item2, false);
1267                                 unmarked2 = true;
1268                             }
1269                             else
1270                                 unmarked2 = false;
1271                         }
1272                         if (!found)
1273                         {
1274                             if (data2->m_pToken->m_Filename.IsSameAs(filename))
1275                             {
1276                                 if (((int)data2->m_pToken->m_LineStart <= line) && ((int)data2->m_pToken->m_LineEnd >= line))
1277                                 {
1278                                     if (unmarked2)
1279                                         MarkItem(m_pTreeBottom, item2);
1280                                     found = true;
1281                                 }
1282                             }
1283                         }
1284                     }
1285                 }
1286                 item2 = m_pTreeBottom->GetNextChild(item, cookie2);
1287             }
1288         }
1289         item = m_pTreeBottom->GetNextChild(root, cookie);
1290     }
1291     return (found || foundFile);
1292 }
1293 
1294 
UnmarkBottomSymbol()1295 void WorkspaceBrowserBuilder::UnmarkBottomSymbol()
1296 {
1297     bool found = false;
1298     bool goInside = false;
1299     wxTreeItemIdValue cookie;
1300     wxTreeItemId root = m_pTreeBottom->GetRootItem();
1301     if (!root.IsOk())
1302         return;
1303     wxTreeItemId item = m_pTreeBottom->GetFirstChild(root, cookie);
1304     while (item.IsOk())
1305     {
1306         TreeDataF* data = (TreeDataF*)m_pTreeBottom->GetItemData(item);
1307         if (data)
1308         {
1309             if (m_pTreeBottom->IsBold(item))
1310             {
1311                 MarkItem(m_pTreeBottom, item, false);
1312                 found = true;
1313                 goInside = true;
1314             }
1315         }
1316         else
1317             goInside = true;
1318 
1319         if (goInside)
1320         {
1321             wxTreeItemIdValue cookie2;
1322             wxTreeItemId item2 = m_pTreeBottom->GetFirstChild(item, cookie2);
1323             while (item2.IsOk())
1324             {
1325                 TreeDataF* data2 = (TreeDataF*)m_pTreeBottom->GetItemData(item2);
1326                 if (data2)
1327                 {
1328                     if (data2->m_SpecialFolder == sfToken)
1329                     {
1330                         if (m_pTreeBottom->IsBold(item2))
1331                         {
1332                             MarkItem(m_pTreeBottom, item2, false);
1333                             found = true;
1334                             break;
1335                         }
1336                     }
1337                 }
1338                 item2 = m_pTreeBottom->GetNextChild(item, cookie2);
1339             }
1340         }
1341         if (found)
1342             break;
1343         item = m_pTreeBottom->GetNextChild(root, cookie);
1344     }
1345 }
1346 
1347 
MarkChildSymbol(wxTreeCtrl * tree,wxTreeItemId & root,int line,bool mark)1348 void WorkspaceBrowserBuilder::MarkChildSymbol(wxTreeCtrl* tree, wxTreeItemId& root, int line, bool mark)
1349 {
1350     bool found = false;
1351     bool unmarked = true;
1352     wxTreeItemIdValue cookie;
1353     if (!root.IsOk())
1354         return;
1355     wxTreeItemId item = tree->GetFirstChild(root, cookie);
1356     while (item.IsOk())
1357     {
1358         TreeDataF* data = (TreeDataF*)tree->GetItemData(item);
1359         if (data)
1360         {
1361             if (data->m_SpecialFolder == sfToken)
1362             {
1363                 if (tree->IsBold(item))
1364                 {
1365                     if (mark)
1366                     {
1367                         if (((int)data->m_pToken->m_LineStart > line) || ((int)data->m_pToken->m_LineEnd < line))
1368                         {
1369                             MarkItem(tree, item, false);
1370                             unmarked = true;
1371                         }
1372                         else
1373                             unmarked = false;
1374                     }
1375                     else
1376                         MarkItem(tree, item, false);
1377                 }
1378                 if (!found && mark)
1379                 {
1380                     if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
1381                     {
1382                         if (unmarked)
1383                             MarkItem(tree, item);
1384                         found = true;
1385                     }
1386                 }
1387             }
1388             else if (data->m_SpecialFolder == sfFile)
1389             {
1390                 if ((tree->IsBold(item) && !mark) || (!tree->IsBold(item) && mark))
1391                     MarkItem(tree, item, mark);
1392                 MarkChildSymbol(tree, item, line, mark);
1393             }
1394         }
1395         item = tree->GetNextChild(root, cookie);
1396     }
1397 }
1398 
MarkGlobalSymbol(wxTreeCtrl * tree,wxTreeItemId & root,const wxString & filename,int line)1399 bool WorkspaceBrowserBuilder::MarkGlobalSymbol(wxTreeCtrl* tree, wxTreeItemId& root, const wxString& filename, int line)
1400 {
1401     bool found = false;
1402     bool foundFile  = false;
1403     wxTreeItemIdValue cookie;
1404     if (!root.IsOk())
1405         return false;
1406     wxTreeItemId item = tree->GetFirstChild(root, cookie);
1407     while (item.IsOk())
1408     {
1409         TreeDataF* data = (TreeDataF*)tree->GetItemData(item);
1410         if (data)
1411         {
1412             if (data->m_SpecialFolder == sfToken)
1413             {
1414                 if (tree->IsBold(item))
1415                 {
1416                     MarkItem(tree, item, false);
1417                 }
1418                 if (!found)
1419                 {
1420                     if (data->m_pToken->m_Filename.IsSameAs(filename))
1421                     {
1422                         if (((int)data->m_pToken->m_LineStart <= line) && ((int)data->m_pToken->m_LineEnd >= line))
1423                         {
1424                             MarkItem(tree, item);
1425                             found = true;
1426                         }
1427                     }
1428                 }
1429             }
1430             else if (data->m_SpecialFolder == sfFile)
1431             {
1432                 bool isSameFile = data->m_pToken->m_Filename.IsSameAs(filename);
1433                 if (isSameFile)
1434                 {
1435                     MarkItem(tree, item);
1436                     foundFile = true;
1437                 }
1438                 else
1439                     MarkItem(tree, item, false);
1440                 wxTreeItemIdValue cookie2;
1441                 wxTreeItemId item2 = tree->GetFirstChild(item, cookie2);
1442 
1443                 while (item2.IsOk())
1444                 {
1445                     TreeDataF* data2 = (TreeDataF*)tree->GetItemData(item2);
1446                     if (data2)
1447                     {
1448                         if (data2->m_SpecialFolder == sfToken)
1449                         {
1450                             if (tree->IsBold(item2))
1451                             {
1452                                 MarkItem(tree, item2, false);
1453                             }
1454                             if (!found && isSameFile)
1455                             {
1456                                 if (((int)data2->m_pToken->m_LineStart <= line) && ((int)data2->m_pToken->m_LineEnd >= line))
1457                                 {
1458                                     MarkItem(tree, item2);
1459                                     found = true;
1460                                 }
1461                             }
1462                         }
1463                     }
1464                     item2 = tree->GetNextChild(item, cookie2);
1465                 }
1466             }
1467         }
1468         item = tree->GetNextChild(root, cookie);
1469     }
1470     return (found || foundFile);
1471 }
1472 
1473 
IsLineInGlobals(const wxString & file,int line)1474 bool WorkspaceBrowserBuilder::IsLineInGlobals(const wxString& file, int line)
1475 {
1476     if (!m_pParser)
1477         return false;
1478     if (m_Options.showIncludeSeparately && m_pParser->IsIncludeFile(file))
1479         return false;
1480 
1481     int tokenKindMask = tkFunction | tkProgram | tkSubroutine;
1482     TokensArrayF* pTokens = m_pParser->GetTokens();
1483     bool found = false;
1484     bool foundFileToken = false;
1485     for (size_t i=0; i < pTokens->GetCount(); ++i)
1486     {
1487         TokenF* token = pTokens->Item(i);
1488 
1489         if (token->m_TokenKind == tkFile && token->m_Filename.IsSameAs(file))
1490         {
1491             switch (m_Options.displayFilter)
1492             {
1493                 case bdfFile:
1494                 {
1495                     foundFileToken = true;
1496                     break;
1497                 }
1498                 case bdfProject:
1499                 {
1500                     for (FilesList::iterator it = m_pActiveProject->GetFilesList().begin(); it != m_pActiveProject->GetFilesList().end(); ++it)
1501                     {
1502                         ProjectFile* pf = *it;
1503                         foundFileToken = UnixFilename(pf->file.GetFullPath()).IsSameAs(file);
1504                         if(foundFileToken)
1505                             break;
1506                     }
1507                     break;
1508                 }
1509                 default: // bdfWorkspace
1510                 {
1511                     foundFileToken = true;
1512                     break;
1513                 }
1514             }
1515             if (foundFileToken)
1516             {
1517                 TokensArrayF* children = &token->m_Children;
1518                 for (size_t j=0; j < children->GetCount(); ++j)
1519                 {
1520                     TokenF* childToken = children->Item(j);
1521                     if (childToken->m_TokenKind & tokenKindMask)
1522                     {
1523                         if ( ((int)childToken->m_LineStart <= line) && ((int)childToken->m_LineEnd >= line) )
1524                         {
1525                             found = true;
1526                             break;
1527                         }
1528                     }
1529                 }
1530             }
1531             break;
1532         }
1533     }
1534     return found;
1535 }
1536 
1537 
MakeVisibleCurrent()1538 void WorkspaceBrowserBuilder::MakeVisibleCurrent()
1539 {
1540     if (Manager::IsAppShuttingDown() || m_AtWork)
1541         return;
1542 
1543     wxTreeItemIdValue cookie;
1544     wxTreeItemId root = m_pTreeTop->GetRootItem();
1545     if (!root.IsOk())
1546         return;
1547     wxTreeItemId item = m_pTreeTop->GetFirstChild(root, cookie);
1548     while (item.IsOk())
1549     {
1550         if (m_pTreeTop->IsBold(item))
1551         {
1552             m_pTreeTop->SelectItem(item);
1553             m_pTreeTop->EnsureVisible(item);
1554             break;
1555         }
1556         item = m_pTreeTop->GetNextChild(root, cookie);
1557     }
1558 
1559     if (m_Options.visibleBottomTree)
1560     {
1561         root = m_pTreeBottom->GetRootItem();
1562         if (!root.IsOk())
1563             return;
1564         item = m_pTreeBottom->GetFirstChild(root, cookie);
1565         bool found = false;
1566         while (item.IsOk())
1567         {
1568             if (m_pTreeBottom->IsBold(item))
1569             {
1570                 m_pTreeBottom->SelectItem(item);
1571                 m_pTreeBottom->EnsureVisible(item);
1572                 break;
1573             }
1574             else if (m_pTreeBottom->HasChildren(item))
1575             {
1576                 wxTreeItemIdValue cookie2;
1577                 wxTreeItemId item2 = m_pTreeBottom->GetFirstChild(item, cookie2);
1578                 while (item2.IsOk())
1579                 {
1580                     if (m_pTreeBottom->IsBold(item2))
1581                     {
1582                         m_pTreeBottom->SelectItem(item2);
1583                         m_pTreeBottom->EnsureVisible(item2);
1584                         found = true;
1585                         break;
1586                     }
1587                     item2 = m_pTreeBottom->GetNextChild(item, cookie2);
1588                 }
1589                 if (found)
1590                     break;
1591             }
1592             item = m_pTreeBottom->GetNextChild(root, cookie);
1593         }
1594     }
1595 }
1596 
AddIncludeFiles(wxTreeCtrl * tree,wxTreeItemId parent)1597 void WorkspaceBrowserBuilder::AddIncludeFiles(wxTreeCtrl* tree, wxTreeItemId parent)
1598 {
1599     if (Manager::IsAppShuttingDown())
1600         return;
1601 
1602     int tokenKindMask = tkModule | tkFunction | tkProgram | tkSubroutine | tkInterface | tkInterfaceExplicit | tkBlockData |
1603                     tkType | tkVariable | tkProcedure | tkAccessList | tkCommonblock | tkSubmodule;
1604 
1605     bool sorted = m_Options.sortAlphabetically;
1606     switch (m_Options.displayFilter)
1607     {
1608         case bdfFile:
1609         {
1610             if (m_pParser->IsIncludeFile(m_ActiveFilename))
1611             {
1612                 TokenF* fileToken= m_pParser->FindFile(m_ActiveFilename);
1613                 if (fileToken)
1614                 {
1615                     wxChar sep = wxFileName::GetPathSeparator();
1616                     wxString tn = _("include '");
1617                     tn << m_ActiveFilename.AfterLast(sep) << _("'");
1618                     wxTreeItemId idni = AddNodeIfNotThere(tree, parent, tn, m_pImlist->GetImageIdx("symbols_folder"), new TreeDataF(sfFile, fileToken), sorted);
1619                     AddFileNodes(tree, idni, UnixFilename(m_ActiveFilename), tokenKindMask);
1620                 }
1621             }
1622             break;
1623         }
1624         case bdfProject:
1625         {
1626             for (FilesList::iterator it = m_pActiveProject->GetFilesList().begin(); it != m_pActiveProject->GetFilesList().end(); ++it)
1627             {
1628                 ProjectFile* pf = *it;
1629                 if (m_pParser->IsIncludeFile(pf->file.GetFullPath()))
1630                 {
1631                     TokenF* fileToken= m_pParser->FindFile(pf->file.GetFullPath());
1632                     if (fileToken)
1633                     {
1634                         wxString tn = _("include '");
1635                         tn << pf->file.GetFullName() << _("'");
1636                         wxTreeItemId idni = AddNodeIfNotThere(tree, parent, tn, m_pImlist->GetImageIdx("symbols_folder"), new TreeDataF(sfFile, fileToken), sorted);
1637                         AddFileNodes(tree, idni, UnixFilename(pf->file.GetFullPath()), tokenKindMask);
1638                     }
1639                 }
1640             }
1641             break;
1642         }
1643         case bdfWorkspace:
1644         {
1645             TokensArrayF* pTokens = m_pParser->GetTokens();
1646             for (size_t i=0; i< pTokens->GetCount(); ++i)
1647             {
1648                 TokenF* token = pTokens->Item(i);
1649                 if (token->m_TokenKind == tkFile &&
1650                     m_pParser->IsIncludeFile(token->m_Filename))
1651                 {
1652                     wxString tn = _("include '");
1653                     tn << token->m_DisplayName << _("'");
1654                     wxTreeItemId idni = AddNodeIfNotThere(tree, parent, tn, m_pImlist->GetImageIdx("symbols_folder"), new TreeDataF(sfFile, token), sorted);
1655                     AddChildrenNodes(tree, idni, token, tokenKindMask);
1656                 }
1657             }
1658             break;
1659         }
1660     }
1661 }
1662 
SetActiveProject(cbProject * prj)1663 void WorkspaceBrowserBuilder::SetActiveProject(cbProject* prj)
1664 {
1665     m_pActiveProject = prj;
1666 }
1667 
1668