1 #include "calltreeview.h"
2
3 #include <sdk.h>
4 #ifndef CB_PRECOMP
5 #include <wx/sizer.h>
6 #include <wx/xrc/xmlres.h>
7 #include <wx/menu.h>
8
9 #include <sdk_events.h>
10 #include <manager.h>
11 #include <editormanager.h>
12 #include <logmanager.h>
13 #include <configmanager.h>
14 #include <cbeditor.h>
15 #endif
16 #include <cmath>
17
18 #include "fortranproject.h"
19 #include "lineaddress.h"
20
CallTreeToken(TokenFlat * tf,CallTreeToken * parent)21 CallTreeToken::CallTreeToken(TokenFlat* tf, CallTreeToken* parent)
22 {
23 m_TokenKind = tf->m_TokenKind;
24 m_DisplayName = tf->m_DisplayName;
25 m_Name = tf->m_Name;
26 m_Filename = tf->m_Filename;
27 m_LineStart = tf->m_LineStart;
28 m_LineEnd = tf->m_LineEnd;
29 m_TokenAccess = tf->m_TokenAccess;
30
31 m_pParent = parent;
32 }
33
CallTreeToken(TokenF * tf,CallTreeToken * parent)34 CallTreeToken::CallTreeToken(TokenF* tf, CallTreeToken* parent)
35 {
36 m_TokenKind = tf->m_TokenKind;
37 m_DisplayName = tf->m_DisplayName;
38 m_Name = tf->m_Name;
39 m_Filename = tf->m_Filename;
40 m_LineStart = tf->m_LineStart;
41 m_LineEnd = tf->m_LineEnd;
42 m_TokenAccess = tf->m_TokenAccess;
43
44 m_pParent = parent;
45 }
46
CTVData(TokenF * token)47 CTVData::CTVData(TokenF* token)
48 {
49 if (token)
50 {
51 CallTreeToken* cttok = static_cast<CallTreeToken*>(token);
52 m_DefFilename = cttok->m_Filename;
53 m_DefLineStart = cttok->m_LineStart;
54 m_DefTokenKind = cttok->m_TokenKind;
55
56 m_CallFilename = cttok->m_CallFilename;
57 m_CallLine = cttok->m_CallLine;
58 }
59 }
60
61 namespace
62 {
63 int idMenuRefreshTree = wxNewId();
64 int idMenuDoNotSort = wxNewId();
65 int idMenuSortAlphabetically = wxNewId();
66 int idMenuGoToProcedure = wxNewId();
67 int idMenuGoToCall = wxNewId();
68 };
69
BEGIN_EVENT_TABLE(CallTreeView,wxPanel)70 BEGIN_EVENT_TABLE(CallTreeView, wxPanel)
71 EVT_TREE_ITEM_ACTIVATED(XRCID("treeCallTreeView"), CallTreeView::OnTreeDoubleClick)
72 EVT_TREE_ITEM_RIGHT_CLICK(XRCID("treeCallTreeView"), CallTreeView::OnTreeItemRightClick)
73
74 EVT_MENU(idMenuRefreshTree, CallTreeView::OnRefreshTree)
75 EVT_MENU(idMenuDoNotSort, CallTreeView::OnChangeSort)
76 EVT_MENU(idMenuSortAlphabetically, CallTreeView::OnChangeSort)
77 EVT_MENU(idMenuGoToProcedure, CallTreeView::OnGoToProcedure)
78 EVT_MENU(idMenuGoToCall, CallTreeView::OnGoToCall)
79 END_EVENT_TABLE()
80
81 CallTreeView::CallTreeView(wxWindow* parentWindow, FortranProject* forproj)
82 {
83 wxXmlResource::Get()->LoadPanel(this, parentWindow, _T("pnlCallTreeView"));
84 m_pTree = XRCCTRL(*this, "treeCallTreeView", wxTreeCtrl);
85
86 int targetHeight = floor(16 * cbGetActualContentScaleFactor(*parentWindow));
87 m_pImgList = new FPImageList(targetHeight);
88 m_pTree->SetImageList(m_pImgList->GetImageList());
89
90 m_pFortranProject = forproj;
91 m_IsCallTree = true;
92 }
93
~CallTreeView()94 CallTreeView::~CallTreeView()
95 {
96 //dtor
97 delete m_pImgList;
98 }
99
ShowCallTree(TokensArrayF * tokArr)100 void CallTreeView::ShowCallTree(TokensArrayF* tokArr)
101 {
102 RereadOptions();
103 m_IsCallTree = true;
104 m_pTree->DeleteAllItems();
105 wxTreeItemId root = m_pTree->AddRoot(_("Call Tree"));
106
107 ShowCallTreeChildren(tokArr, root, 0);
108 }
109
ShowCalledByTree(TokensArrayF * tokArr)110 void CallTreeView::ShowCalledByTree(TokensArrayF* tokArr)
111 {
112 RereadOptions();
113 m_IsCallTree = false;
114 m_pTree->DeleteAllItems();
115 wxTreeItemId root = m_pTree->AddRoot(_("Called-By Tree"));
116
117 ShowCallTreeChildren(tokArr, root, 0);
118 }
119
ShowCallTreeChildren(TokensArrayF * tokArr,wxTreeItemId & parent,int callLevel)120 void CallTreeView::ShowCallTreeChildren(TokensArrayF* tokArr, wxTreeItemId& parent, int callLevel)
121 {
122 callLevel += 1;
123 for (size_t i=0; i<tokArr->size(); i++)
124 {
125 wxTreeItemData* tidata = new CTVData(tokArr->Item(i));
126 int iind;
127 if (callLevel == 1)
128 {
129 // show for first level different image
130 if (m_IsCallTree)
131 {
132 if (tokArr->Item(i)->m_TokenKind == tkFunction)
133 iind = m_pImgList->GetImageIdx("function_call");
134 else
135 iind = m_pImgList->GetImageIdx("subroutine_call");
136 }
137 else // CalledBy tree
138 {
139 if (tokArr->Item(i)->m_TokenKind == tkFunction)
140 iind = m_pImgList->GetImageIdx("function_calledby");
141 else
142 iind = m_pImgList->GetImageIdx("subroutine_calledby");
143 }
144 }
145 else
146 {
147 iind = m_pImgList->GetTokenKindImageIdx(tokArr->Item(i));
148 }
149 wxTreeItemId addedId = InsertTreeItem(parent, tokArr->Item(i)->m_DisplayName, iind, tidata);
150
151 ShowCallTreeChildren(&tokArr->Item(i)->m_Children, addedId, callLevel);
152 if (callLevel == 1)
153 m_pTree->Expand(addedId);
154 }
155 }
156
InsertTreeItem(wxTreeItemId & parent,const wxString & displayName,int imageIdx,wxTreeItemData * tidata)157 wxTreeItemId CallTreeView::InsertTreeItem(wxTreeItemId& parent, const wxString& displayName, int imageIdx, wxTreeItemData* tidata)
158 {
159 if (!m_SortAlphabetically)
160 return m_pTree->AppendItem(parent, displayName, imageIdx, -1, tidata);
161
162 wxTreeItemId insertAfter;
163 wxTreeItemIdValue cookie;
164 wxTreeItemId item = m_pTree->GetFirstChild(parent, cookie);
165
166 while (item.IsOk())
167 {
168 wxString itemText = m_pTree->GetItemText(item);
169 if (displayName.CmpNoCase(itemText) >= 0)
170 {
171 insertAfter = item;
172 }
173 else
174 {
175 break;
176 }
177 item = m_pTree->GetNextChild(parent, cookie);
178 }
179
180 wxTreeItemId addedId;
181 if (insertAfter.IsOk())
182 addedId = m_pTree->InsertItem(parent, insertAfter, displayName, imageIdx, -1, tidata);
183 else
184 addedId = m_pTree->InsertItem(parent, 0, displayName, imageIdx, -1, tidata);
185
186 return addedId;
187 }
188
OnTreeDoubleClick(wxTreeEvent & event)189 void CallTreeView::OnTreeDoubleClick(wxTreeEvent& event)
190 {
191 wxTreeItemId id = event.GetItem();
192 if (!id.IsOk())
193 return;
194
195 CTVData* ctd = (CTVData*)m_pTree->GetItemData(id);
196 if (!ctd)
197 return;
198
199 if (ctd->m_DefFilename == wxEmptyString)
200 return;
201
202 GoToLine(ctd->m_DefFilename, ctd->m_DefLineStart);
203 }
204
GoToLine(wxString & filename,unsigned int line)205 void CallTreeView::GoToLine(wxString& filename, unsigned int line)
206 {
207 TokenFlat token;
208 token.m_Filename = filename;
209 token.m_LineStart = line;
210 cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
211 m_pFortranProject->GotoToken(&token, ed);
212
213 ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
214 if (ed)
215 {
216 wxFocusEvent ev(wxEVT_SET_FOCUS);
217 ev.SetWindow(this);
218 #if wxCHECK_VERSION(3, 0, 0)
219 ed->GetControl()->GetEventHandler()->AddPendingEvent(ev);
220 #else
221 ed->GetControl()->AddPendingEvent(ev);
222 #endif
223 }
224 }
225
ShowMenu(wxTreeItemId id,const wxPoint & pt,bool isFirstLevelItem)226 void CallTreeView::ShowMenu(wxTreeItemId id, const wxPoint& pt, bool isFirstLevelItem)
227 {
228 if ( !id.IsOk() )
229 return;
230
231 #if wxUSE_MENUS
232 wxString caption;
233 wxMenu *menu=new wxMenu(wxEmptyString);
234
235 if (isFirstLevelItem)
236 {
237 menu->Append(idMenuRefreshTree, _("&Refresh tree"));
238
239 menu->AppendCheckItem(idMenuDoNotSort, _("Do not sort"));
240 menu->Check(idMenuDoNotSort, !m_SortAlphabetically);
241 menu->AppendCheckItem(idMenuSortAlphabetically, _("Sort alphabetically"));
242 menu->Check(idMenuSortAlphabetically, m_SortAlphabetically);
243 }
244 else
245 {
246 menu->Append(idMenuGoToProcedure, _("Go to &procedure"));
247 menu->Append(idMenuGoToCall, _("Go to &caller"));
248 }
249
250 if (menu->GetMenuItemCount() != 0)
251 PopupMenu(menu);
252 delete menu; // Prevents memory leak
253 #endif // wxUSE_MENUS
254 }
255
OnTreeItemRightClick(wxTreeEvent & event)256 void CallTreeView::OnTreeItemRightClick(wxTreeEvent& event)
257 {
258 wxTreeItemId idRoot = m_pTree->GetRootItem();
259 if (!idRoot.IsOk())
260 return;
261
262 bool isFirstLevelItem = false;
263 wxTreeItemIdValue cookie;
264 wxTreeItemId item = m_pTree->GetFirstChild(idRoot, cookie);
265 while (item.IsOk())
266 {
267 if (item == event.GetItem())
268 {
269 isFirstLevelItem = true;
270 break;
271 }
272 item = m_pTree->GetNextChild(idRoot, cookie);
273 }
274
275 m_pTree->SelectItem(event.GetItem());
276 ShowMenu(event.GetItem(), event.GetPoint(), isFirstLevelItem);
277 }
278
OnRefreshTree(wxCommandEvent & event)279 void CallTreeView::OnRefreshTree(wxCommandEvent& event)
280 {
281 UpdateView();
282 }
283
OnChangeSort(wxCommandEvent & event)284 void CallTreeView::OnChangeSort(wxCommandEvent& event)
285 {
286 if (event.GetId() == idMenuDoNotSort)
287 m_SortAlphabetically = !event.IsChecked();
288 else if (event.GetId() == idMenuSortAlphabetically)
289 m_SortAlphabetically = event.IsChecked();
290
291 ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
292 cfg->Write(_T("/calltree_sort_alphabetically"), m_SortAlphabetically);
293
294 UpdateView();
295 }
296
OnGoToProcedure(wxCommandEvent & event)297 void CallTreeView::OnGoToProcedure(wxCommandEvent& event)
298 {
299 wxTreeItemId id = m_pTree->GetSelection();
300 if (!id.IsOk())
301 return;
302
303 CTVData* ctd = (CTVData*)m_pTree->GetItemData(id);
304 if (!ctd)
305 return;
306
307 if (ctd->m_DefFilename == wxEmptyString)
308 return;
309
310 GoToLine(ctd->m_DefFilename, ctd->m_DefLineStart);
311 }
312
OnGoToCall(wxCommandEvent & event)313 void CallTreeView::OnGoToCall(wxCommandEvent& event)
314 {
315 wxTreeItemId id = m_pTree->GetSelection();
316 if (!id.IsOk())
317 return;
318
319 CTVData* ctd = (CTVData*)m_pTree->GetItemData(id);
320 if (!ctd)
321 return;
322
323 if (ctd->m_CallFilename == wxEmptyString)
324 return;
325
326 GoToLine(ctd->m_CallFilename, ctd->m_CallLine);
327 }
328
RereadOptions()329 void CallTreeView::RereadOptions()
330 {
331 ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
332 m_SortAlphabetically = cfg->ReadBool(_("/calltree_sort_alphabetically"), true);
333 }
334
UpdateView()335 void CallTreeView::UpdateView()
336 {
337
338 wxTreeItemId id = m_pTree->GetSelection();
339 if (!id.IsOk())
340 return;
341
342 CTVData* ctd = (CTVData*)m_pTree->GetItemData(id);
343 if (!ctd)
344 return;
345
346 if (ctd->m_DefFilename == wxEmptyString)
347 return;
348
349 TokenFlat token;
350 token.m_Filename = ctd->m_DefFilename;
351 token.m_LineStart = ctd->m_DefLineStart;
352 cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
353 if (!ed)
354 return;
355 m_pFortranProject->GotoToken(&token, ed);
356
357 ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
358 if (!ed)
359 return;
360 cbStyledTextCtrl* control = ed->GetControl();
361 const int pos = control->GetCurrentPos();
362 int curLine = control->LineFromPosition(pos);
363 int lineStart;
364 if (curLine == 0)
365 lineStart = 0;
366 else
367 lineStart = control->GetLineEndPosition(curLine-1);
368 int lineEnd = control->GetLineEndPosition(curLine);
369 int wordStart = control->FindText(lineStart, lineEnd, m_pTree->GetItemText(id), wxSCI_FIND_WHOLEWORD);
370 control->GotoPos(wordStart+1);
371
372 m_pFortranProject->ShowCallTree(m_IsCallTree);
373 }
374