source: git/src/aventreectrl.cc @ 25c7ef4

warn-only-for-hanging-survey
Last change on this file since 25c7ef4 was 51eab3b, checked in by Olly Betts <olly@…>, 3 months ago

aven: Support overlaying geodata

GDAL is now a required dependency.

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