1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "IssueBrowser.h"
21 
22 #include "Macros.h"
23 #include "Model/Issue.h"
24 #include "Model/IssueGenerator.h"
25 #include "Model/World.h"
26 #include "View/FlagChangedCommand.h"
27 #include "View/FlagsPopupEditor.h"
28 #include "View/IssueBrowserView.h"
29 #include "View/MapDocument.h"
30 #include "View/ViewConstants.h"
31 
32 #include <wx/checkbox.h>
33 #include <wx/menu.h>
34 #include <wx/simplebook.h>
35 #include <wx/sizer.h>
36 
37 #include <cassert>
38 
39 namespace TrenchBroom {
40     namespace View {
IssueBrowser(wxWindow * parent,MapDocumentWPtr document)41         IssueBrowser::IssueBrowser(wxWindow* parent, MapDocumentWPtr document) :
42         TabBookPage(parent),
43         m_document(document),
44         m_view(new IssueBrowserView(this, m_document)),
45         m_showHiddenIssuesCheckBox(NULL),
46         m_filterEditor(NULL) {
47             wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
48             sizer->Add(m_view, 1, wxEXPAND);
49             SetSizerAndFit(sizer);
50 
51             bindObservers();
52         }
53 
~IssueBrowser()54         IssueBrowser::~IssueBrowser() {
55             unbindObservers();
56         }
57 
createTabBarPage(wxWindow * parent)58         wxWindow* IssueBrowser::createTabBarPage(wxWindow* parent) {
59             wxPanel* barPage = new wxPanel(parent);
60             m_showHiddenIssuesCheckBox = new wxCheckBox(barPage, wxID_ANY, "Show hidden issues");
61             m_showHiddenIssuesCheckBox->Bind(wxEVT_CHECKBOX, &IssueBrowser::OnShowHiddenIssuesChanged, this);
62 
63             m_filterEditor = new FlagsPopupEditor(barPage, 1, "Filter", false);
64             m_filterEditor->Bind(FLAG_CHANGED_EVENT, &IssueBrowser::OnFilterChanged, this);
65 
66             wxBoxSizer* barPageSizer = new wxBoxSizer(wxHORIZONTAL);
67             barPageSizer->Add(m_showHiddenIssuesCheckBox, 0, wxALIGN_CENTER_VERTICAL);
68             barPageSizer->AddSpacer(LayoutConstants::MediumHMargin);
69             barPageSizer->Add(m_filterEditor, 0, wxALIGN_CENTER_VERTICAL);
70             barPage->SetSizer(barPageSizer);
71 
72             return barPage;
73         }
74 
OnShowHiddenIssuesChanged(wxCommandEvent & event)75         void IssueBrowser::OnShowHiddenIssuesChanged(wxCommandEvent& event) {
76             if (IsBeingDeleted()) return;
77 
78             m_view->setShowHiddenIssues(m_showHiddenIssuesCheckBox->IsChecked());
79         }
80 
OnFilterChanged(FlagChangedCommand & command)81         void IssueBrowser::OnFilterChanged(FlagChangedCommand& command) {
82             if (IsBeingDeleted()) return;
83 
84             m_view->setHiddenGenerators(~command.flagSetValue());
85         }
86 
bindObservers()87         void IssueBrowser::bindObservers() {
88             MapDocumentSPtr document = lock(m_document);
89             document->documentWasSavedNotifier.addObserver(this, &IssueBrowser::documentWasSaved);
90             document->documentWasNewedNotifier.addObserver(this, &IssueBrowser::documentWasNewedOrLoaded);
91             document->documentWasLoadedNotifier.addObserver(this, &IssueBrowser::documentWasNewedOrLoaded);
92             document->nodesWereAddedNotifier.addObserver(this, &IssueBrowser::nodesWereAdded);
93             document->nodesWereRemovedNotifier.addObserver(this, &IssueBrowser::nodesWereRemoved);
94             document->nodesDidChangeNotifier.addObserver(this, &IssueBrowser::nodesDidChange);
95             document->brushFacesDidChangeNotifier.addObserver(this, &IssueBrowser::brushFacesDidChange);
96         }
97 
unbindObservers()98         void IssueBrowser::unbindObservers() {
99             if (!expired(m_document)) {
100                 MapDocumentSPtr document = lock(m_document);
101                 document->documentWasSavedNotifier.removeObserver(this, &IssueBrowser::documentWasSaved);
102                 document->documentWasNewedNotifier.removeObserver(this, &IssueBrowser::documentWasNewedOrLoaded);
103                 document->documentWasLoadedNotifier.removeObserver(this, &IssueBrowser::documentWasNewedOrLoaded);
104                 document->nodesWereAddedNotifier.removeObserver(this, &IssueBrowser::nodesWereAdded);
105                 document->nodesWereRemovedNotifier.removeObserver(this, &IssueBrowser::nodesWereRemoved);
106                 document->nodesDidChangeNotifier.removeObserver(this, &IssueBrowser::nodesDidChange);
107                 document->brushFacesDidChangeNotifier.removeObserver(this, &IssueBrowser::brushFacesDidChange);
108             }
109         }
110 
documentWasNewedOrLoaded(MapDocument * document)111         void IssueBrowser::documentWasNewedOrLoaded(MapDocument* document) {
112             updateFilterFlags();
113             m_view->reset();
114         }
115 
documentWasSaved(MapDocument * document)116         void IssueBrowser::documentWasSaved(MapDocument* document) {
117             m_view->Refresh();
118         }
119 
nodesWereAdded(const Model::NodeList & nodes)120         void IssueBrowser::nodesWereAdded(const Model::NodeList& nodes) {
121             m_view->reset();
122         }
123 
nodesWereRemoved(const Model::NodeList & nodes)124         void IssueBrowser::nodesWereRemoved(const Model::NodeList& nodes) {
125             m_view->reset();
126         }
127 
nodesDidChange(const Model::NodeList & nodes)128         void IssueBrowser::nodesDidChange(const Model::NodeList& nodes) {
129             m_view->reset();
130         }
131 
brushFacesDidChange(const Model::BrushFaceList & faces)132         void IssueBrowser::brushFacesDidChange(const Model::BrushFaceList& faces) {
133             m_view->reset();
134         }
135 
issueIgnoreChanged(Model::Issue * issue)136         void IssueBrowser::issueIgnoreChanged(Model::Issue* issue) {
137             m_view->Refresh();
138         }
139 
updateFilterFlags()140         void IssueBrowser::updateFilterFlags() {
141             MapDocumentSPtr document = lock(m_document);
142             const Model::World* world = document->world();
143             const Model::IssueGeneratorList& generators = world->registeredIssueGenerators();
144 
145             wxArrayInt flags;
146             wxArrayString labels;
147 
148             Model::IssueGeneratorList::const_iterator it, end;
149             for (it = generators.begin(), end = generators.end(); it != end; ++it) {
150                 const Model::IssueGenerator* generator = *it;
151                 const Model::IssueType flag = generator->type();
152                 const String& description = generator->description();
153 
154                 flags.push_back(flag);
155                 labels.push_back(description);
156             }
157 
158             m_filterEditor->setFlags(flags, labels);
159             m_view->setHiddenGenerators(0);
160             m_filterEditor->setFlagValue(~0);
161         }
162     }
163 }
164