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 "LayerEditor.h"
21 
22 #include "Model/Brush.h"
23 #include "Model/CollectSelectableNodesVisitor.h"
24 #include "Model/Entity.h"
25 #include "Model/FindGroupVisitor.h"
26 #include "Model/FindLayerVisitor.h"
27 #include "Model/Group.h"
28 #include "Model/Layer.h"
29 #include "Model/World.h"
30 #include "View/LayerListView.h"
31 #include "View/MapDocument.h"
32 #include "View/ViewConstants.h"
33 #include "View/wxUtils.h"
34 
35 #include <wx/bmpbuttn.h>
36 #include <wx/menu.h>
37 #include <wx/msgdlg.h>
38 #include <wx/sizer.h>
39 #include <wx/textdlg.h>
40 
41 #include <set>
42 
43 namespace TrenchBroom {
44     namespace View {
LayerEditor(wxWindow * parent,MapDocumentWPtr document)45         LayerEditor::LayerEditor(wxWindow* parent, MapDocumentWPtr document) :
46         wxPanel(parent),
47         m_document(document),
48         m_layerList(NULL) {
49             createGui();
50         }
51 
OnSetCurrentLayer(LayerCommand & event)52         void LayerEditor::OnSetCurrentLayer(LayerCommand& event) {
53             if (IsBeingDeleted()) return;
54 
55             Model::Layer* layer = event.layer();
56             MapDocumentSPtr document = lock(m_document);
57             if (layer->locked())
58                 document->resetLock(Model::NodeList(1, layer));
59             if (layer->hidden())
60                 document->resetVisibility(Model::NodeList(1, layer));
61             document->setCurrentLayer(event.layer());
62         }
63 
OnLayerRightClick(LayerCommand & event)64         void LayerEditor::OnLayerRightClick(LayerCommand& event) {
65             if (IsBeingDeleted()) return;
66 
67             const Model::Layer* layer = event.layer();
68 
69             wxMenu popupMenu;
70             popupMenu.Append(MoveSelectionToLayerCommandId, "Move selection to layer");
71             popupMenu.Append(SelectAllInLayerCommandId, "Select all in layer");
72             popupMenu.AppendSeparator();
73             popupMenu.Append(ToggleLayerVisibleCommandId, layer->hidden() ? "Show layer" : "Hide layer");
74             popupMenu.Append(ToggleLayerLockedCommandId, layer->locked() ? "Unlock layer" : "Lock layer");
75             popupMenu.AppendSeparator();
76             popupMenu.Append(RemoveLayerCommandId, "Remove layer");
77 
78             popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnMoveSelectionToLayer, this, MoveSelectionToLayerCommandId);
79             popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateMoveSelectionToLayerUI, this, MoveSelectionToLayerCommandId);
80             popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnSelectAllInLayer, this, SelectAllInLayerCommandId);
81             popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnToggleLayerVisibleFromMenu, this, ToggleLayerVisibleCommandId);
82             popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateToggleLayerVisibleUI, this, ToggleLayerVisibleCommandId);
83             popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnToggleLayerLockedFromMenu, this, ToggleLayerLockedCommandId);
84             popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateToggleLayerLockedUI, this, ToggleLayerLockedCommandId);
85             popupMenu.Bind(wxEVT_MENU, &LayerEditor::OnRemoveLayer, this, RemoveLayerCommandId);
86             popupMenu.Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateRemoveLayerUI, this, RemoveLayerCommandId);
87 
88             PopupMenu(&popupMenu);
89         }
90 
OnToggleLayerVisibleFromMenu(wxCommandEvent & event)91         void LayerEditor::OnToggleLayerVisibleFromMenu(wxCommandEvent& event) {
92             if (IsBeingDeleted()) return;
93 
94             toggleLayerVisible(m_layerList->selectedLayer());
95         }
96 
OnToggleLayerVisibleFromList(LayerCommand & event)97         void LayerEditor::OnToggleLayerVisibleFromList(LayerCommand& event) {
98             if (IsBeingDeleted()) return;
99 
100             toggleLayerVisible(event.layer());
101         }
102 
OnUpdateToggleLayerVisibleUI(wxUpdateUIEvent & event)103         void LayerEditor::OnUpdateToggleLayerVisibleUI(wxUpdateUIEvent& event) {
104             Model::Layer* layer = m_layerList->selectedLayer();
105             if (layer == NULL) {
106                 event.Enable(false);
107                 return;
108             }
109 
110             MapDocumentSPtr document = lock(m_document);
111             if (!layer->hidden() && layer == document->currentLayer()) {
112                 event.Enable(false);
113                 return;
114             }
115 
116             event.Enable(true);
117         }
118 
toggleLayerVisible(Model::Layer * layer)119         void LayerEditor::toggleLayerVisible(Model::Layer* layer) {
120             assert(layer != NULL);
121             MapDocumentSPtr document = lock(m_document);
122             if (!layer->hidden())
123                 document->hide(Model::NodeList(1, layer));
124             else
125                 document->resetVisibility(Model::NodeList(1, layer));
126         }
127 
OnToggleLayerLockedFromMenu(wxCommandEvent & event)128         void LayerEditor::OnToggleLayerLockedFromMenu(wxCommandEvent& event) {
129             if (IsBeingDeleted()) return;
130 
131             toggleLayerLocked(m_layerList->selectedLayer());
132         }
133 
OnToggleLayerLockedFromList(LayerCommand & event)134         void LayerEditor::OnToggleLayerLockedFromList(LayerCommand& event) {
135             if (IsBeingDeleted()) return;
136 
137             toggleLayerLocked(event.layer());
138         }
139 
OnUpdateToggleLayerLockedUI(wxUpdateUIEvent & event)140         void LayerEditor::OnUpdateToggleLayerLockedUI(wxUpdateUIEvent& event) {
141             Model::Layer* layer = m_layerList->selectedLayer();
142             if (layer == NULL) {
143                 event.Enable(false);
144                 return;
145             }
146 
147             MapDocumentSPtr document = lock(m_document);
148             if (!layer->locked() && layer == document->currentLayer()) {
149                 event.Enable(false);
150                 return;
151             }
152 
153             event.Enable(true);
154         }
155 
toggleLayerLocked(Model::Layer * layer)156         void LayerEditor::toggleLayerLocked(Model::Layer* layer) {
157             assert(layer != NULL);
158             MapDocumentSPtr document = lock(m_document);
159             if (!layer->locked())
160                 document->lock(Model::NodeList(1, layer));
161             else
162                 document->resetLock(Model::NodeList(1, layer));
163         }
164 
165         class LayerEditor::CollectMoveableNodes : public Model::NodeVisitor {
166         private:
167             Model::World* m_world;
168             Model::NodeSet m_selectNodes;
169             Model::NodeSet m_moveNodes;
170         public:
CollectMoveableNodes(Model::World * world)171             CollectMoveableNodes(Model::World* world) : m_world(world) {}
172 
selectNodes() const173             const Model::NodeList selectNodes() const {
174                 return Model::NodeList(m_selectNodes.begin(), m_selectNodes.end());
175             }
176 
moveNodes() const177             const Model::NodeList moveNodes() const {
178                 return Model::NodeList(m_moveNodes.begin(), m_moveNodes.end());
179             }
180         private:
doVisit(Model::World * world)181             void doVisit(Model::World* world)   {}
doVisit(Model::Layer * layer)182             void doVisit(Model::Layer* layer)   {}
183 
doVisit(Model::Group * group)184             void doVisit(Model::Group* group)   {
185                 assert(group->selected());
186 
187                 if (group->group() == NULL) {
188                     m_moveNodes.insert(group);
189                     m_selectNodes.insert(group);
190                 }
191             }
192 
doVisit(Model::Entity * entity)193             void doVisit(Model::Entity* entity) {
194                 assert(entity->selected());
195 
196                 if (entity->group() == NULL) {
197                     m_moveNodes.insert(entity);
198                     m_selectNodes.insert(entity);
199                 }
200             }
201 
doVisit(Model::Brush * brush)202             void doVisit(Model::Brush* brush)   {
203                 assert(brush->selected());
204                 if (brush->group() == NULL) {
205                     Model::AttributableNode* entity = brush->entity();
206                     if (entity == m_world) {
207                         m_moveNodes.insert(brush);
208                         m_selectNodes.insert(brush);
209                     } else {
210                         if (m_moveNodes.insert(entity).second) {
211                             const Model::NodeList& siblings = entity->children();
212                             m_selectNodes.insert(siblings.begin(), siblings.end());
213                         }
214                     }
215                 }
216             }
217         };
218 
OnMoveSelectionToLayer(wxCommandEvent & event)219         void LayerEditor::OnMoveSelectionToLayer(wxCommandEvent& event) {
220             if (IsBeingDeleted()) return;
221 
222             Model::Layer* layer = m_layerList->selectedLayer();
223             assert(layer != NULL);
224 
225             MapDocumentSPtr document = lock(m_document);
226             Transaction transaction(document, "Move Nodes to " + layer->name());
227             moveSelectedNodesToLayer(document, layer);
228         }
229 
OnUpdateMoveSelectionToLayerUI(wxUpdateUIEvent & event)230         void LayerEditor::OnUpdateMoveSelectionToLayerUI(wxUpdateUIEvent& event) {
231             if (IsBeingDeleted()) return;
232 
233             const Model::Layer* layer = m_layerList->selectedLayer();
234             if (layer == NULL) {
235                 event.Enable(false);
236                 return;
237             }
238 
239             MapDocumentSPtr document = lock(m_document);
240             const Model::NodeList& nodes = document->selectedNodes().nodes();
241             if (nodes.empty()) {
242                 event.Enable(false);
243                 return;
244             }
245 
246             Model::NodeList::const_iterator it, end;
247             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
248                 Model::Node* node = *it;
249                 Model::Group* nodeGroup = Model::findGroup(node);
250                 if (nodeGroup != NULL) {
251                     event.Enable(false);
252                     return;
253                 }
254             }
255 
256             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
257                 Model::Node* node = *it;
258                 Model::Layer* nodeLayer = Model::findLayer(node);
259                 if (nodeLayer != layer) {
260                     event.Enable(true);
261                     return;
262                 }
263             }
264 
265             event.Enable(false);
266         }
267 
OnSelectAllInLayer(wxCommandEvent & event)268         void LayerEditor::OnSelectAllInLayer(wxCommandEvent& event) {
269             if (IsBeingDeleted()) return;
270 
271             Model::Layer* layer = m_layerList->selectedLayer();
272             assert(layer != NULL);
273 
274             MapDocumentSPtr document = lock(m_document);
275 
276             Model::CollectSelectableNodesVisitor visitor(document->editorContext());
277             layer->recurse(visitor);
278 
279             const Model::NodeList& nodes = visitor.nodes();
280             document->deselectAll();
281             document->select(nodes);
282         }
283 
OnAddLayer(wxCommandEvent & event)284         void LayerEditor::OnAddLayer(wxCommandEvent& event) {
285             if (IsBeingDeleted()) return;
286 
287             const String name = queryLayerName();
288             if (!name.empty()) {
289                 MapDocumentSPtr document = lock(m_document);
290                 Model::World* world = document->world();
291                 Model::Layer* layer = world->createLayer(name, document->worldBounds());
292 
293                 Transaction transaction(document, "Create Layer " + layer->name());
294                 document->addNode(layer, world);
295                 document->setCurrentLayer(layer);
296                 m_layerList->setSelectedLayer(layer);
297             }
298         }
299 
queryLayerName()300         String LayerEditor::queryLayerName() {
301             while (true) {
302                 wxTextEntryDialog dialog(this, "Enter a name", "Layer Name", "Unnamed");
303                 dialog.CentreOnParent();
304                 if (dialog.ShowModal() != wxID_OK)
305                     return "";
306 
307                 const String name = dialog.GetValue().ToStdString();
308                 if (StringUtils::isBlank(name)) {
309                     if (wxMessageBox("Layer names cannot be blank.", "Error", wxOK | wxCANCEL | wxCENTRE, this) != wxOK)
310                         return "";
311                 } else if (StringUtils::containsCaseInsensitive(name, "\"")) {
312                     if (wxMessageBox("Layer names cannot contain double quotes.", "Error", wxOK | wxCANCEL | wxCENTRE, this) != wxOK)
313                         return "";
314                 } else {
315                     return name;
316                 }
317             }
318         }
319 
OnRemoveLayer(wxCommandEvent & event)320         void LayerEditor::OnRemoveLayer(wxCommandEvent& event) {
321             if (IsBeingDeleted()) return;
322 
323             Model::Layer* layer = m_layerList->selectedLayer();
324             assert(layer != NULL);
325 
326             Model::Layer* newCurrentLayer = findVisibleAndUnlockedLayer(layer);
327             assert(newCurrentLayer != NULL);
328 
329             MapDocumentSPtr document = lock(m_document);
330             Model::Layer* defaultLayer = document->world()->defaultLayer();
331 
332             Model::CollectSelectableNodesVisitor collectSelectableNodes(document->editorContext());
333             layer->recurse(collectSelectableNodes);
334 
335             Transaction transaction(document, "Remove Layer " + layer->name());
336             document->deselectAll();
337             document->select(collectSelectableNodes.nodes());
338             if (layer->hasChildren())
339                 document->reparentNodes(defaultLayer, layer->children());
340             if (document->currentLayer() == layer)
341                 document->setCurrentLayer(newCurrentLayer);
342             document->removeNode(layer);
343         }
344 
OnUpdateRemoveLayerUI(wxUpdateUIEvent & event)345         void LayerEditor::OnUpdateRemoveLayerUI(wxUpdateUIEvent& event) {
346             if (IsBeingDeleted()) return;
347 
348             const Model::Layer* layer = m_layerList->selectedLayer();
349             if (layer == NULL) {
350                 event.Enable(false);
351                 return;
352             }
353 
354             if (findVisibleAndUnlockedLayer(layer) == NULL) {
355                 event.Enable(false);
356                 return;
357             }
358 
359             MapDocumentSPtr document = lock(m_document);
360             event.Enable(layer != document->world()->defaultLayer());
361         }
362 
OnShowAllLayers(wxCommandEvent & event)363         void LayerEditor::OnShowAllLayers(wxCommandEvent& event) {
364             if (IsBeingDeleted()) return;
365 
366             MapDocumentSPtr document = lock(m_document);
367             const Model::LayerList& layers = document->world()->allLayers();
368             document->resetVisibility(Model::NodeList(layers.begin(), layers.end()));
369         }
370 
findVisibleAndUnlockedLayer(const Model::Layer * except) const371         Model::Layer* LayerEditor::findVisibleAndUnlockedLayer(const Model::Layer* except) const {
372             MapDocumentSPtr document = lock(m_document);
373             if (!document->world()->defaultLayer()->locked() && !document->world()->defaultLayer()->hidden())
374                 return document->world()->defaultLayer();
375 
376             const Model::LayerList& layers = document->world()->customLayers();
377             Model::LayerList::const_iterator it, end;
378             for (it = layers.begin(), end = layers.end(); it != end; ++it) {
379                 Model::Layer* layer = *it;
380                 if (layer != except && !layer->locked() && !layer->hidden())
381                     return layer;
382             }
383 
384             return NULL;
385         }
386 
moveSelectedNodesToLayer(MapDocumentSPtr document,Model::Layer * layer)387         void LayerEditor::moveSelectedNodesToLayer(MapDocumentSPtr document, Model::Layer* layer) {
388             const Model::NodeList& selectedNodes = document->selectedNodes().nodes();
389 
390             CollectMoveableNodes visitor(document->world());
391             Model::Node::accept(selectedNodes.begin(), selectedNodes.end(), visitor);
392 
393             const Model::NodeList moveNodes = visitor.moveNodes();
394             if (!moveNodes.empty()) {
395                 const Model::NodeList selectNodes = visitor.selectNodes();
396                 document->deselectAll();
397                 document->reparentNodes(layer, visitor.moveNodes());
398                 if (!layer->hidden() && !layer->locked())
399                     document->select(visitor.selectNodes());
400             }
401         }
402 
createGui()403         void LayerEditor::createGui() {
404             SetBackgroundColour(*wxWHITE);
405 
406             m_layerList = new LayerListView(this, m_document);
407             m_layerList->Bind(LAYER_SET_CURRENT_EVENT, &LayerEditor::OnSetCurrentLayer, this);
408             m_layerList->Bind(LAYER_RIGHT_CLICK_EVENT, &LayerEditor::OnLayerRightClick, this);
409             m_layerList->Bind(LAYER_TOGGLE_VISIBLE_EVENT, &LayerEditor::OnToggleLayerVisibleFromList, this);
410             m_layerList->Bind(LAYER_TOGGLE_LOCKED_EVENT, &LayerEditor::OnToggleLayerLockedFromList, this);
411 
412             wxWindow* addLayerButton = createBitmapButton(this, "Add.png", "Add a new layer from the current selection");
413             wxWindow* removeLayerButton = createBitmapButton(this, "Remove.png", "Remove the selected layer and move its objects to the default layer");
414             wxWindow* showAllLayersButton = createBitmapButton(this, "Visible.png", "Show all layers");
415 
416             addLayerButton->Bind(wxEVT_BUTTON, &LayerEditor::OnAddLayer, this);
417             removeLayerButton->Bind(wxEVT_BUTTON, &LayerEditor::OnRemoveLayer, this);
418             removeLayerButton->Bind(wxEVT_UPDATE_UI, &LayerEditor::OnUpdateRemoveLayerUI, this);
419             showAllLayersButton->Bind(wxEVT_BUTTON, &LayerEditor::OnShowAllLayers, this);
420 
421             wxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
422             buttonSizer->Add(addLayerButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
423             buttonSizer->Add(removeLayerButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
424             buttonSizer->Add(showAllLayersButton, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, LayoutConstants::NarrowVMargin);
425             buttonSizer->AddStretchSpacer();
426 
427             wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
428             sizer->Add(m_layerList, 1, wxEXPAND);
429             sizer->Add(buttonSizer, 0, wxEXPAND);
430             SetSizer(sizer);
431         }
432     }
433 }
434