source: git/src/aventreectrl.cc@ ed0410c1

warn-only-for-hanging-survey
Last change on this file since ed0410c1 was fccf718, checked in by Olly Betts <olly@…>, 2 years ago

Enable more show and hide actions in survey tree

  • Property mode set to 100644
File size: 17.9 KB
RevLine 
[f17e6dc6]1//
2// aventreectrl.cc
3//
4// Tree control used for the survey tree.
5//
6// Copyright (C) 2001, Mark R. Shinwell.
[672459c]7// Copyright (C) 2001-2003,2005,2006,2016,2018 Olly Betts
[887c26e]8// Copyright (C) 2005 Martin Green
[f17e6dc6]9//
10// This program is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
[ecbc6c18]22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
[f17e6dc6]23//
24
[cbfa50d]25#include <config.h>
26
[f17e6dc6]27#include "aventreectrl.h"
28#include "mainfrm.h"
[81d2ef0]29#include "osalloc.h"
[f17e6dc6]30
[17a38ded]31#include <stack>
32
33using namespace std;
34
[44e007d]35// STATE_BLANK is used for stations which are siblings of surveys which have
36// select checkboxes.
37enum { STATE_BLANK = 0, STATE_OFF, STATE_ON };
[672459c]38
39/* XPM */
[44e007d]40static const char *blank_xpm[] = {
41/* columns rows colors chars-per-pixel */
42"15 15 1 1",
43" c None",
44/* pixels */
45" ",
46" ",
47" ",
48" ",
49" ",
50" ",
51" ",
52" ",
53" ",
54" ",
55" ",
56" ",
57" ",
58" ",
59" "
60};
61
62/* XPM */
63static const char *off_xpm[] = {
[672459c]64/* columns rows colors chars-per-pixel */
[c78d5b4]65"15 15 2 1",
66". c #000000",
[672459c]67" c None",
68/* pixels */
69" ",
70" ",
[c78d5b4]71" ............ ",
72" . . ",
73" . . ",
74" . . ",
75" . . ",
76" . . ",
77" . . ",
78" . . ",
79" . . ",
80" . . ",
81" . . ",
82" ............ ",
[672459c]83" "
84};
85
86/* XPM */
[44e007d]87static const char *on_xpm[] = {
[672459c]88/* columns rows colors chars-per-pixel */
[c78d5b4]89"15 15 3 1",
90". c #000000",
[672459c]91"X c #007F28",
92" c None",
93/* pixels */
94" ",
[c78d5b4]95" ",
96" ............XX",
97" . XXX",
98" . XXXX",
99" . XXXX ",
100" . XXXX ",
101" . XXXX. ",
102" . XX XXXX . ",
103" . XXXXXXX . ",
104" . XXXXX . ",
105" . XXX . ",
106" . X . ",
107" ............ ",
[672459c]108" "
109};
110
[f17e6dc6]111BEGIN_EVENT_TABLE(AvenTreeCtrl, wxTreeCtrl)
112 EVT_MOTION(AvenTreeCtrl::OnMouseMove)
[887c26e]113 EVT_LEAVE_WINDOW(AvenTreeCtrl::OnLeaveWindow)
[6969b17]114 EVT_TREE_SEL_CHANGED(wxID_ANY, AvenTreeCtrl::OnSelChanged)
115 EVT_TREE_ITEM_ACTIVATED(wxID_ANY, AvenTreeCtrl::OnItemActivated)
[5901b62]116 EVT_CHAR(AvenTreeCtrl::OnKeyPress)
[6969b17]117 EVT_TREE_ITEM_MENU(wxID_ANY, AvenTreeCtrl::OnMenu)
[d5fd4f4]118 EVT_MENU(menu_SURVEY_SHOW_ALL, AvenTreeCtrl::OnRestrict)
[5e0b9f9d]119 EVT_MENU(menu_SURVEY_RESTRICT, AvenTreeCtrl::OnRestrict)
[672459c]120 EVT_MENU(menu_SURVEY_HIDE, AvenTreeCtrl::OnHide)
121 EVT_MENU(menu_SURVEY_SHOW, AvenTreeCtrl::OnShow)
122 EVT_MENU(menu_SURVEY_HIDE_SIBLINGS, AvenTreeCtrl::OnHideSiblings)
[6969b17]123 EVT_TREE_STATE_IMAGE_CLICK(wxID_ANY, AvenTreeCtrl::OnStateClick)
[f17e6dc6]124END_EVENT_TABLE()
125
126AvenTreeCtrl::AvenTreeCtrl(MainFrm* parent, wxWindow* window_parent) :
[51eab3b]127 wxTreeCtrl(window_parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
128 wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT),
[b623b3e]129 m_Parent(parent),
[b4fe9fb]130 m_Enabled(false),
[3eddcaf4]131 m_LastItem(),
[efb30c4]132 m_BackgroundColour(),
[5e0b9f9d]133 m_SelValid(false),
134 menu_data(NULL)
[f17e6dc6]135{
[672459c]136 wxImageList* img_list = new wxImageList(15, 15, 2);
[44e007d]137 img_list->Add(wxBitmap(blank_xpm));
138 img_list->Add(wxBitmap(off_xpm));
139 img_list->Add(wxBitmap(on_xpm));
[672459c]140 AssignStateImageList(img_list);
[f17e6dc6]141}
142
[17a38ded]143void AvenTreeCtrl::FillTree(const wxString& root_name)
144{
145 Freeze();
146 m_Enabled = false;
147 m_LastItem = wxTreeItemId();
148 m_SelValid = false;
149 DeleteAllItems();
150
151 const wxChar separator = m_Parent->GetSeparator();
152 filter.clear();
153 filter.SetSeparator(separator);
154
[51eab3b]155 // Create the (hidden) real root of the wxTreeCtrl.
156 wxTreeItemId treeroot = AddRoot(wxString());
157
158 // Create the root of the survey tree.
159 wxTreeItemId surveyroot = AppendItem(treeroot, root_name);
[17a38ded]160
161 // Fill the tree of stations and prefixes.
162 stack<wxTreeItemId> previous_ids;
163 wxString current_prefix;
[51eab3b]164 wxTreeItemId current_id = surveyroot;
[17a38ded]165
166 list<LabelInfo*>::const_iterator pos = m_Parent->GetLabels();
167 while (pos != m_Parent->GetLabelsEnd()) {
168 LabelInfo* label = *pos++;
169
170 if (label->IsAnon()) continue;
171
172 // Determine the current prefix.
173 wxString prefix = label->GetText().BeforeLast(separator);
174
175 // Determine if we're still on the same prefix.
176 if (prefix == current_prefix) {
177 // no need to fiddle with branches...
178 }
179 // If not, then see if we've descended to a new prefix.
180 else if (prefix.length() > current_prefix.length() &&
181 prefix.StartsWith(current_prefix) &&
182 (prefix[current_prefix.length()] == separator ||
183 current_prefix.empty())) {
184 // We have, so start as many new branches as required.
185 int current_prefix_length = current_prefix.length();
186 current_prefix = prefix;
187 size_t next_dot = current_prefix_length;
188 if (!next_dot) --next_dot;
189 do {
190 size_t prev_dot = next_dot + 1;
191
192 // Extract the next bit of prefix.
193 next_dot = prefix.find(separator, prev_dot + 1);
194
195 wxString bit = prefix.substr(prev_dot, next_dot - prev_dot);
[ed7f3fc]196 // Sigh, therion can produce files with empty components in
197 // station names!
198 // assert(!bit.empty());
[17a38ded]199
200 // Add the current tree ID to the stack.
201 previous_ids.push(current_id);
202
203 // Append the new item to the tree and set this as the current branch.
204 current_id = AppendItem(current_id, bit);
205 SetItemData(current_id, new TreeData(prefix.substr(0, next_dot)));
206 } while (next_dot != wxString::npos);
207 }
208 // Otherwise, we must have moved up, and possibly then down again.
209 else {
210 size_t count = 0;
211 bool ascent_only = (prefix.length() < current_prefix.length() &&
212 current_prefix.StartsWith(prefix) &&
213 (current_prefix[prefix.length()] == separator ||
214 prefix.empty()));
215 if (!ascent_only) {
216 // Find out how much of the current prefix and the new prefix
217 // are the same.
218 // Note that we require a match of a whole number of parts
219 // between dots!
220 size_t n = min(prefix.length(), current_prefix.length());
221 size_t i;
222 for (i = 0; i < n && prefix[i] == current_prefix[i]; ++i) {
223 if (prefix[i] == separator) count = i + 1;
224 }
225 } else {
226 count = prefix.length() + 1;
227 }
228
229 // Extract the part of the current prefix after the bit (if any)
230 // which has matched.
231 // This gives the prefixes to ascend over.
232 wxString prefixes_ascended = current_prefix.substr(count);
233
234 // Count the number of prefixes to ascend over.
235 int num_prefixes = prefixes_ascended.Freq(separator);
236
237 // Reverse up over these prefixes.
238 for (int i = 1; i <= num_prefixes; i++) {
239 previous_ids.pop();
240 }
241 current_id = previous_ids.top();
242 previous_ids.pop();
243
244 if (!ascent_only) {
245 // Add branches for this new part.
246 size_t next_dot = count - 1;
247 do {
248 size_t prev_dot = next_dot + 1;
249
250 // Extract the next bit of prefix.
251 next_dot = prefix.find(separator, prev_dot + 1);
252
253 wxString bit = prefix.substr(prev_dot, next_dot - prev_dot);
[ed7f3fc]254 // Sigh, therion can produce files with empty components in
255 // station names!
256 // assert(!bit.empty());
[17a38ded]257
258 // Add the current tree ID to the stack.
259 previous_ids.push(current_id);
260
261 // Append the new item to the tree and set this as the current branch.
262 current_id = AppendItem(current_id, bit);
263 SetItemData(current_id, new TreeData(prefix.substr(0, next_dot)));
264 } while (next_dot != wxString::npos);
265 }
266
267 current_prefix = prefix;
268 }
269
270 // Now add the leaf.
271 wxString bit = label->GetText().AfterLast(separator);
[ed7f3fc]272 // Sigh, therion can produce files with empty components in station
273 // names!
274 // assert(!bit.empty());
[17a38ded]275 wxTreeItemId id = AppendItem(current_id, bit);
276 SetItemData(id, new TreeData(label));
277 label->tree_id = id;
278 // Set the colour for an item in the survey tree.
279 if (label->IsEntrance()) {
280 // Entrances are green (like entrance blobs).
281 SetItemTextColour(id, wxColour(0, 255, 40));
282 } else if (label->IsSurface()) {
283 // Surface stations are dark green.
284 SetItemTextColour(id, wxColour(49, 158, 79));
285 }
286 }
287
[51eab3b]288 Expand(surveyroot);
[17a38ded]289 m_Enabled = true;
290 Thaw();
291}
292
[9e8e1d6]293constexpr auto TREE_MASK = wxTREE_HITTEST_ONITEMLABEL |
294 wxTREE_HITTEST_ONITEMRIGHT |
295 wxTREE_HITTEST_ONITEMSTATEICON;
[97dd0d2]296
[f17e6dc6]297void AvenTreeCtrl::OnMouseMove(wxMouseEvent& event)
298{
[0ae40fa]299 if (!m_Enabled || m_Parent->Animating())
300 return;
301
302 int flags;
303 wxTreeItemId pos = HitTest(event.GetPosition(), flags);
304 if (!(flags & TREE_MASK)) {
305 pos = wxTreeItemId();
306 }
307 if (pos == m_LastItem) return;
308 if (pos.IsOk()) {
[0642381]309 const TreeData* data = static_cast<const TreeData*>(GetItemData(pos));
310 m_Parent->DisplayTreeInfo(data);
311 if (data && !data->IsStation()) {
312 // For stations, MainFrm calls back to SetHere(), but for surveys
313 // we need to do that ourselves.
314 SetHere(pos);
315 }
[0ae40fa]316 } else {
317 m_Parent->DisplayTreeInfo();
[f17e6dc6]318 }
319}
320
[570d62c3]321void AvenTreeCtrl::SetHere(wxTreeItemId pos)
322{
323 if (pos == m_LastItem) return;
324
325 if (m_LastItem.IsOk()) {
326 SetItemBackgroundColour(m_LastItem, m_BackgroundColour);
327 }
328 if (pos.IsOk()) {
329 m_BackgroundColour = GetItemBackgroundColour(pos);
330 SetItemBackgroundColour(pos, wxColour(180, 180, 180));
331 }
332 m_LastItem = pos;
333}
334
[887c26e]335void AvenTreeCtrl::OnLeaveWindow(wxMouseEvent&)
336{
337 if (m_LastItem.IsOk()) {
338 SetItemBackgroundColour(m_LastItem, m_BackgroundColour);
339 m_LastItem = wxTreeItemId();
340 }
[381ae6e]341 m_Parent->DisplayTreeInfo();
[887c26e]342}
343
[5dae1ba]344void AvenTreeCtrl::OnSelChanged(wxTreeEvent&)
[f17e6dc6]345{
[b623b3e]346 m_SelValid = true;
[f17e6dc6]347}
348
[44ed489]349void AvenTreeCtrl::OnItemActivated(wxTreeEvent& e)
350{
[4dc54fa]351 if (!m_Enabled) return;
352
353 m_Parent->TreeItemSelected(GetItemData(e.GetItem()));
[44ed489]354}
355
[5e0b9f9d]356void AvenTreeCtrl::OnMenu(wxTreeEvent& e)
357{
[0ae40fa]358 if (!m_Enabled) return;
359
360 const TreeData* data = static_cast<const TreeData*>(GetItemData(e.GetItem()));
361 menu_data = data;
362 menu_item = e.GetItem();
363 if (!data) {
[51eab3b]364 // Survey tree root:
[0ae40fa]365 wxMenu menu;
366 /* TRANSLATORS: In aven's survey tree, right-clicking on the root
367 * gives a pop-up menu and this is an option (but only enabled if
368 * the view is restricted to a subsurvey). It reloads the current
369 * survey file with the who survey visible.
370 */
371 menu.Append(menu_SURVEY_SHOW_ALL, wmsg(/*Show all*/245));
372 if (m_Parent->GetSurvey().empty())
373 menu.Enable(menu_SURVEY_SHOW_ALL, false);
374 PopupMenu(&menu);
[51eab3b]375 } else if (data->IsStation()) {
[0ae40fa]376 // Station: name is data->GetLabel()->GetText()
[51eab3b]377 } else if (ItemHasChildren(menu_item)) {
[0ae40fa]378 // Survey:
379 wxMenu menu;
380 /* TRANSLATORS: In aven's survey tree, right-clicking on a survey
381 * name gives a pop-up menu and this is an option. It reloads the
382 * current survey file with the view restricted to the survey
383 * clicked upon.
384 */
385 menu.Append(menu_SURVEY_RESTRICT, wmsg(/*Hide others*/246));
386 menu.AppendSeparator();
[fccf718]387 menu.Append(menu_SURVEY_HIDE, wmsg(/*&Hide*/407));
[0ae40fa]388 menu.Append(menu_SURVEY_SHOW, wmsg(/*&Show*/409));
[fccf718]389 menu.Append(menu_SURVEY_HIDE_SIBLINGS, wmsg(/*Hide si&blings*/388));
[0ae40fa]390 switch (GetItemState(menu_item)) {
[44e007d]391 case STATE_ON: // Currently shown.
[0ae40fa]392 menu.Enable(menu_SURVEY_SHOW, false);
393 break;
[44e007d]394 case STATE_OFF:
[0ae40fa]395 menu.Enable(menu_SURVEY_HIDE, false);
396 break;
[5e0b9f9d]397 }
[0ae40fa]398 PopupMenu(&menu);
[51eab3b]399 } else {
400 // Overlay - FIXME: menu here?
[5e0b9f9d]401 }
[0ae40fa]402 menu_data = NULL;
403 e.Skip();
[5e0b9f9d]404}
405
[570d62c3]406bool AvenTreeCtrl::GetSelectionData(wxTreeItemData** data) const
[f17e6dc6]407{
408 assert(m_Enabled);
[26fac5a]409 assert(data);
[b623b3e]410
411 if (!m_SelValid) {
[421b7d2]412 return false;
[b623b3e]413 }
[421b7d2]414
[f17e6dc6]415 wxTreeItemId id = GetSelection();
416 if (id.IsOk()) {
[421b7d2]417 *data = GetItemData(id);
[f17e6dc6]418 }
419
[2d9ed8ad]420 return id.IsOk() && *data;
[f17e6dc6]421}
[b623b3e]422
423void AvenTreeCtrl::UnselectAll()
424{
425 m_SelValid = false;
426 wxTreeCtrl::UnselectAll();
427}
428
[5901b62]429void AvenTreeCtrl::OnKeyPress(wxKeyEvent &e)
430{
[a6e8d45]431 switch (e.GetKeyCode()) {
[26fac5a]432 case WXK_ESCAPE:
433 m_Parent->ClearTreeSelection();
434 break;
435 case WXK_RETURN: {
436 wxTreeItemId id = GetSelection();
437 if (id.IsOk()) {
438 if (ItemHasChildren(id)) {
439 // If on a branch, expand/contract it.
440 if (IsExpanded(id)) {
441 Collapse(id);
442 } else {
443 Expand(id);
444 }
445 } else {
[672459c]446 // If on a station, centre on it by selecting it twice.
447 m_Parent->TreeItemSelected(GetItemData(id));
448 m_Parent->TreeItemSelected(GetItemData(id));
[26fac5a]449 }
450 }
451 break;
452 }
453 case WXK_LEFT: case WXK_RIGHT: case WXK_UP: case WXK_DOWN:
454 case WXK_HOME: case WXK_END: case WXK_PAGEUP: case WXK_PAGEDOWN:
455 e.Skip();
456 break;
457 default:
458 // Pass key event to MainFrm which will pass to GfxCore which will
459 // pass to GUIControl.
460 m_Parent->OnKeyPress(e);
461 break;
[5901b62]462 }
463}
[5e0b9f9d]464
[5dae1ba]465void AvenTreeCtrl::OnRestrict(wxCommandEvent&)
[5e0b9f9d]466{
[51eab3b]467 m_Parent->RestrictTo(menu_data && menu_data->IsSurvey() ? menu_data->GetSurvey() : wxString());
468 // FIXME: Overlays
[672459c]469}
470
[5dae1ba]471void AvenTreeCtrl::OnHide(wxCommandEvent&)
[672459c]472{
473 // Shouldn't be available for the root item.
474 wxASSERT(menu_data);
475 // Hide should be disabled unless the item is explicitly shown.
[44e007d]476 wxASSERT(GetItemState(menu_item) == STATE_ON);
477 SetItemState(menu_item, STATE_OFF);
[51eab3b]478 // FIXME: Overlays?
[1a46879]479 filter.remove(menu_data->GetSurvey());
[672459c]480#if 0
481 Freeze();
482 // Show siblings if not already shown or hidden.
483 wxTreeItemId i = menu_item;
484 while ((i = GetPrevSibling(i)).IsOk()) {
485 if (GetItemState(i) == wxTREE_ITEMSTATE_NONE)
486 SetItemState(i, 1);
487 }
488 i = menu_item;
489 while ((i = GetNextSibling(i)).IsOk()) {
490 if (GetItemState(i) == wxTREE_ITEMSTATE_NONE)
491 SetItemState(i, 1);
492 }
493 Thaw();
494#endif
495 m_Parent->ForceFullRedraw();
496}
497
[5dae1ba]498void AvenTreeCtrl::OnShow(wxCommandEvent&)
[672459c]499{
500 // Shouldn't be available for the root item.
501 wxASSERT(menu_data);
[44e007d]502 auto old_state = GetItemState(menu_item);
[672459c]503 // Show should be disabled for an explicitly shown item.
[44e007d]504 wxASSERT(old_state != STATE_ON);
[672459c]505 Freeze();
[44e007d]506 SetItemState(menu_item, STATE_ON);
[51eab3b]507 // FIXME: Overlays?
[1a46879]508 filter.add(menu_data->GetSurvey());
[44e007d]509 if (old_state == wxTREE_ITEMSTATE_NONE) {
510 // Hide siblings if not already shown or hidden.
511 wxTreeItemId i = menu_item;
512 while ((i = GetPrevSibling(i)).IsOk()) {
513 if (GetItemState(i) == wxTREE_ITEMSTATE_NONE) {
514 const TreeData* data = static_cast<const TreeData*>(GetItemData(i));
515 SetItemState(i, data->IsStation() ? STATE_BLANK : STATE_OFF);
516 }
517 }
518 i = menu_item;
519 while ((i = GetNextSibling(i)).IsOk()) {
520 if (GetItemState(i) == wxTREE_ITEMSTATE_NONE) {
521 const TreeData* data = static_cast<const TreeData*>(GetItemData(i));
522 SetItemState(i, data->IsStation() ? STATE_BLANK : STATE_OFF);
523 }
524 }
[672459c]525 }
526 Thaw();
527 m_Parent->ForceFullRedraw();
528}
529
[5dae1ba]530void AvenTreeCtrl::OnHideSiblings(wxCommandEvent&)
[672459c]531{
532 // Shouldn't be available for the root item.
533 wxASSERT(menu_data);
534 Freeze();
[51eab3b]535 // FIXME: Overlays?
[44e007d]536 SetItemState(menu_item, STATE_ON);
[1a46879]537 filter.add(menu_data->GetSurvey());
[672459c]538
539 wxTreeItemId i = menu_item;
540 while ((i = GetPrevSibling(i)).IsOk()) {
541 const TreeData* data = static_cast<const TreeData*>(GetItemData(i));
[1a46879]542 filter.remove(data->GetSurvey());
[44e007d]543 SetItemState(i, data->IsStation() ? STATE_BLANK : STATE_OFF);
[672459c]544 }
545 i = menu_item;
546 while ((i = GetNextSibling(i)).IsOk()) {
547 const TreeData* data = static_cast<const TreeData*>(GetItemData(i));
[1a46879]548 filter.remove(data->GetSurvey());
[44e007d]549 SetItemState(i, data->IsStation() ? STATE_BLANK : STATE_OFF);
[672459c]550 }
551 Thaw();
552 m_Parent->ForceFullRedraw();
553}
554
555void AvenTreeCtrl::OnStateClick(wxTreeEvent& e)
556{
557 auto item = e.GetItem();
558 const TreeData* data = static_cast<const TreeData*>(GetItemData(item));
[44e007d]559 switch (GetItemState(item)) {
560 case STATE_BLANK:
561 // Click on blank state icon for a station - let the tree handle
562 // this in the same way as a click on the label.
563 return;
564 case STATE_ON:
[51eab3b]565 if (!ItemHasChildren(item)) {
566 // Overlay.
567 m_Parent->InvalidateOverlays();
568 } else {
569 // Survey.
570 if (data) filter.remove(data->GetSurvey());
571 }
[44e007d]572 SetItemState(item, STATE_OFF);
573 break;
574 case STATE_OFF:
[51eab3b]575 if (!ItemHasChildren(item)) {
576 // Overlay.
577 m_Parent->InvalidateOverlays();
578 } else {
579 // Survey.
580 if (data) filter.add(data->GetSurvey());
581 }
[44e007d]582 SetItemState(item, STATE_ON);
583 break;
[672459c]584 }
[5e0b9f9d]585 e.Skip();
[672459c]586 m_Parent->ForceFullRedraw();
587}
[51eab3b]588
589void AvenTreeCtrl::AddOverlay(const wxString& file)
590{
[81d2ef0]591 char* leaf = leaf_from_fnm(file.utf8_str());
592 auto id = AppendItem(GetRootItem(), leaf);
593 osfree(leaf);
[51eab3b]594 SetItemState(id, STATE_ON);
595 SetItemData(id, new TreeData(file));
596}
597
598void AvenTreeCtrl::RemoveOverlay(const wxString& file)
599{
600 // If we add an overlay but fail to load it and remove it again, the
601 // overlay will be the last one, so search from the last one back.
602 for (auto item = GetLastChild(GetRootItem());
603 item.IsOk();
604 item = GetPrevSibling(item)) {
605 if (ItemHasChildren(item)) {
606 // Not an overlay.
607 continue;
608 }
609 const TreeData* data = static_cast<const TreeData*>(GetItemData(item));
610 if (data->GetSurvey() == file) {
611 Delete(item);
612 break;
613 }
614 }
615}
616
617wxTreeItemId AvenTreeCtrl::FirstOverlay()
618{
619 wxTreeItemIdValue cookie;
620 auto item = GetFirstChild(GetRootItem(), cookie);
621 while (item.IsOk() &&
622 (ItemHasChildren(item) || GetItemState(item) != STATE_ON)) {
623 item = GetNextSibling(item);
624 }
625 return item;
626}
627
628wxTreeItemId AvenTreeCtrl::NextOverlay(wxTreeItemId item)
629{
630 do {
631 item = GetNextSibling(item);
632 } while (item.IsOk() &&
633 (ItemHasChildren(item) || GetItemState(item) != STATE_ON));
634 return item;
635}
636
637wxTreeItemId AvenTreeCtrl::RemoveOverlay(wxTreeItemId id)
638{
639 wxTreeItemId item = NextOverlay(id);
640 Delete(id);
641 return item;
642}
643
644const wxString& AvenTreeCtrl::GetOverlayFilename(wxTreeItemId item)
645{
646 if (ItemHasChildren(item)) {
647not_an_overlay:
648 static const wxString empty_string;
649 return empty_string;
650 }
651
652 const TreeData* data = static_cast<const TreeData*>(GetItemData(item));
653 if (!data) goto not_an_overlay;
654 return data->GetSurvey();
655}
Note: See TracBrowser for help on using the repository browser.