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 "MapDocumentCommandFacade.h"
21 
22 #include "CollectionUtils.h"
23 #include "Assets/EntityDefinitionFileSpec.h"
24 #include "Assets/TextureManager.h"
25 #include "Model/Brush.h"
26 #include "Model/BrushFace.h"
27 #include "Model/ChangeBrushFaceAttributesRequest.h"
28 #include "Model/CollectNodesWithDescendantSelectionCountVisitor.h"
29 #include "Model/CollectRecursivelySelectedNodesVisitor.h"
30 #include "Model/CollectSelectableBrushFacesVisitor.h"
31 #include "Model/CollectSelectableNodesVisitor.h"
32 #include "Model/EditorContext.h"
33 #include "Model/Entity.h"
34 #include "Model/Group.h"
35 #include "Model/Issue.h"
36 #include "Model/ModelUtils.h"
37 #include "Model/Snapshot.h"
38 #include "Model/TransformObjectVisitor.h"
39 #include "Model/World.h"
40 #include "View/Selection.h"
41 
42 namespace TrenchBroom {
43     namespace View {
newMapDocument()44         MapDocumentSPtr MapDocumentCommandFacade::newMapDocument() {
45             return MapDocumentSPtr(new MapDocumentCommandFacade());
46         }
47 
MapDocumentCommandFacade()48         MapDocumentCommandFacade::MapDocumentCommandFacade() :
49         m_commandProcessor(this) {
50             bindObservers();
51         }
52 
performSelect(const Model::NodeList & nodes)53         void MapDocumentCommandFacade::performSelect(const Model::NodeList& nodes) {
54             selectionWillChangeNotifier();
55             updateLastSelectionBounds();
56 
57             Model::NodeList selected;
58             selected.reserve(nodes.size());
59 
60             Model::CollectNodesWithDescendantSelectionCountVisitor ancestors(0);
61             Model::CollectRecursivelySelectedNodesVisitor descendants(false);
62 
63             Model::NodeList::const_iterator it, end;
64             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
65                 Model::Node* node = *it;
66                 if (!node->selected() && m_editorContext->selectable(node)) {
67                     node->escalate(ancestors);
68                     node->recurse(descendants);
69                     node->select();
70                     selected.push_back(node);
71                 }
72             }
73 
74             const Model::NodeList& partiallySelected = ancestors.nodes();
75             const Model::NodeList& recursivelySelected = descendants.nodes();
76 
77             m_selectedNodes.addNodes(selected);
78             m_partiallySelectedNodes.addNodes(partiallySelected);
79 
80             Selection selection;
81             selection.addSelectedNodes(selected);
82             selection.addPartiallySelectedNodes(partiallySelected);
83             selection.addRecursivelySelectedNodes(recursivelySelected);
84 
85             selectionDidChangeNotifier(selection);
86             invalidateSelectionBounds();
87         }
88 
performSelect(const Model::BrushFaceList & faces)89         void MapDocumentCommandFacade::performSelect(const Model::BrushFaceList& faces) {
90             selectionWillChangeNotifier();
91 
92             Model::BrushFaceList selected;
93             selected.reserve(faces.size());
94 
95             Model::CollectNodesWithDescendantSelectionCountVisitor visitor(0);
96 
97             Model::BrushFaceList::const_iterator it, end;
98             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
99                 Model::BrushFace* face = *it;
100                 if (!face->selected() && m_editorContext->selectable(face)) {
101                     face->brush()->acceptAndEscalate(visitor);
102                     face->select();
103                     selected.push_back(face);
104                 }
105             }
106 
107             const Model::NodeList& partiallySelected = visitor.nodes();
108 
109             VectorUtils::append(m_selectedBrushFaces, selected);
110             m_partiallySelectedNodes.addNodes(partiallySelected);
111 
112             Selection selection;
113             selection.addSelectedBrushFaces(selected);
114             selection.addPartiallySelectedNodes(partiallySelected);
115 
116             selectionDidChangeNotifier(selection);
117         }
118 
performSelectAllNodes()119         void MapDocumentCommandFacade::performSelectAllNodes() {
120             performDeselectAll();
121 
122             Model::CollectSelectableNodesVisitor visitor(*m_editorContext);
123             m_world->acceptAndRecurse(visitor);
124             performSelect(visitor.nodes());
125         }
126 
performSelectAllBrushFaces()127         void MapDocumentCommandFacade::performSelectAllBrushFaces() {
128             performDeselectAll();
129 
130             Model::CollectSelectableBrushFacesVisitor visitor(*m_editorContext);
131             m_world->acceptAndRecurse(visitor);
132             performSelect(visitor.faces());
133         }
134 
performConvertToBrushFaceSelection()135         void MapDocumentCommandFacade::performConvertToBrushFaceSelection() {
136             Model::CollectSelectableBrushFacesVisitor visitor(*m_editorContext);
137             Model::Node::acceptAndRecurse(m_selectedNodes.begin(), m_selectedNodes.end(), visitor);
138 
139             performDeselectAll();
140             performSelect(visitor.faces());
141         }
142 
performDeselect(const Model::NodeList & nodes)143         void MapDocumentCommandFacade::performDeselect(const Model::NodeList& nodes) {
144             selectionWillChangeNotifier();
145             updateLastSelectionBounds();
146 
147             Model::NodeList deselected;
148             deselected.reserve(nodes.size());
149 
150             Model::CollectNodesWithDescendantSelectionCountVisitor ancestors(0);
151             Model::CollectRecursivelySelectedNodesVisitor descendants(false);
152 
153             Model::NodeList::const_iterator it, end;
154             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
155                 Model::Node* node = *it;
156                 if (node->selected()) {
157                     node->deselect();
158                     deselected.push_back(node);
159                     node->escalate(ancestors);
160                     node->recurse(descendants);
161                 }
162             }
163 
164             const Model::NodeList& partiallyDeselected = ancestors.nodes();
165             const Model::NodeList& recursivelyDeselected = descendants.nodes();
166 
167             m_selectedNodes.removeNodes(deselected);
168             m_partiallySelectedNodes.removeNodes(partiallyDeselected);
169 
170             Selection selection;
171             selection.addDeselectedNodes(deselected);
172             selection.addPartiallyDeselectedNodes(partiallyDeselected);
173             selection.addRecursivelyDeselectedNodes(recursivelyDeselected);
174 
175             selectionDidChangeNotifier(selection);
176             invalidateSelectionBounds();
177         }
178 
performDeselect(const Model::BrushFaceList & faces)179         void MapDocumentCommandFacade::performDeselect(const Model::BrushFaceList& faces) {
180             selectionWillChangeNotifier();
181 
182             Model::BrushFaceList deselected;
183             deselected.reserve(faces.size());
184 
185             Model::CollectNodesWithDescendantSelectionCountVisitor visitor(0);
186 
187             Model::BrushFaceList::const_iterator it, end;
188             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
189                 Model::BrushFace* face = *it;
190                 if (face->selected()) {
191                     face->deselect();
192                     deselected.push_back(face);
193                     face->brush()->acceptAndEscalate(visitor);
194                 }
195             }
196 
197             const Model::NodeList& partiallyDeselected = visitor.nodes();
198 
199             VectorUtils::eraseAll(m_selectedBrushFaces, deselected);
200             m_selectedNodes.removeNodes(partiallyDeselected);
201 
202             Selection selection;
203             selection.addDeselectedBrushFaces(deselected);
204             selection.addPartiallyDeselectedNodes(partiallyDeselected);
205 
206             selectionDidChangeNotifier(selection);
207         }
208 
performDeselectAll()209         void MapDocumentCommandFacade::performDeselectAll() {
210             if (hasSelectedNodes())
211                 deselectAllNodes();
212             if (hasSelectedBrushFaces())
213                 deselectAllBrushFaces();
214         }
215 
deselectAllNodes()216         void MapDocumentCommandFacade::deselectAllNodes() {
217             selectionWillChangeNotifier();
218             updateLastSelectionBounds();
219 
220             Model::CollectRecursivelySelectedNodesVisitor descendants(false);
221 
222             Model::NodeList::const_iterator it, end;
223             for (it = m_selectedNodes.begin(), end = m_selectedNodes.end(); it != end; ++it) {
224                 Model::Node* node = *it;
225                 node->deselect();
226                 node->recurse(descendants);
227             }
228 
229             Selection selection;
230             selection.addDeselectedNodes(m_selectedNodes.nodes());
231             selection.addPartiallyDeselectedNodes(m_partiallySelectedNodes.nodes());
232             selection.addRecursivelyDeselectedNodes(descendants.nodes());
233 
234             m_selectedNodes.clear();
235             m_partiallySelectedNodes.clear();
236 
237             selectionDidChangeNotifier(selection);
238             invalidateSelectionBounds();
239         }
240 
deselectAllBrushFaces()241         void MapDocumentCommandFacade::deselectAllBrushFaces() {
242             selectionWillChangeNotifier();
243 
244             Model::BrushFaceList::const_iterator it, end;
245             for (it = m_selectedBrushFaces.begin(), end = m_selectedBrushFaces.end(); it != end; ++it) {
246                 Model::BrushFace* face = *it;
247                 face->deselect();
248             }
249 
250             Selection selection;
251             selection.addDeselectedBrushFaces(m_selectedBrushFaces);
252             selection.addPartiallyDeselectedNodes(m_partiallySelectedNodes.nodes());
253 
254             m_selectedBrushFaces.clear();
255             m_partiallySelectedNodes.clear();
256 
257             selectionDidChangeNotifier(selection);
258         }
259 
performAddNodes(const Model::ParentChildrenMap & nodes)260         Model::NodeList MapDocumentCommandFacade::performAddNodes(const Model::ParentChildrenMap& nodes) {
261             const Model::NodeList parents = collectParents(nodes);
262             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
263 
264             Model::NodeList addedNodes;
265             Model::ParentChildrenMap::const_iterator pIt, pEnd;
266             for (pIt = nodes.begin(), pEnd = nodes.end(); pIt != pEnd; ++pIt) {
267                 Model::Node* parent = pIt->first;
268                 const Model::NodeList& children = pIt->second;
269                 parent->addChildren(children);
270                 VectorUtils::append(addedNodes, children);
271             }
272 
273             setEntityDefinitions(addedNodes);
274             setEntityModels(addedNodes);
275             setTextures(addedNodes);
276             invalidateSelectionBounds();
277 
278             nodesWereAddedNotifier(addedNodes);
279             return addedNodes;
280         }
281 
performRemoveNodes(const Model::NodeList & nodes)282         Model::ParentChildrenMap MapDocumentCommandFacade::performRemoveNodes(const Model::NodeList& nodes) {
283             Model::ParentChildrenMap removedNodes = parentChildrenMap(nodes);
284             addEmptyNodes(removedNodes);
285 
286             const Model::NodeList parents = collectParents(removedNodes);
287             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
288 
289             const Model::NodeList allChildren = collectChildren(removedNodes);
290             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyChildren(nodesWillBeRemovedNotifier, nodesWereRemovedNotifier, allChildren);
291 
292             Model::ParentChildrenMap::const_iterator it, end;
293             for (it = removedNodes.begin(), end = removedNodes.end(); it != end; ++it) {
294                 Model::Node* parent = it->first;
295                 const Model::NodeList& children = it->second;
296                 unsetEntityDefinitions(children);
297                 unsetTextures(children);
298                 parent->removeChildren(children.begin(), children.end());
299             }
300 
301             invalidateSelectionBounds();
302 
303             return removedNodes;
304         }
305 
addEmptyNodes(Model::ParentChildrenMap & nodes) const306         void MapDocumentCommandFacade::addEmptyNodes(Model::ParentChildrenMap& nodes) const {
307             Model::NodeList emptyNodes = collectEmptyNodes(nodes);
308             while (!emptyNodes.empty()) {
309                 removeEmptyNodes(nodes, emptyNodes);
310                 emptyNodes = collectEmptyNodes(nodes);
311             }
312         }
313 
collectEmptyNodes(const Model::ParentChildrenMap & nodes) const314         Model::NodeList MapDocumentCommandFacade::collectEmptyNodes(const Model::ParentChildrenMap& nodes) const {
315             Model::NodeList result;
316 
317             Model::ParentChildrenMap::const_iterator it, end;
318             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
319                 Model::Node* node = it->first;
320                 const Model::NodeList& children = it->second;
321                 if (node->removeIfEmpty() && node->childCount() == children.size())
322                     result.push_back(node);
323             }
324 
325             return result;
326         }
327 
removeEmptyNodes(Model::ParentChildrenMap & nodes,const Model::NodeList & emptyNodes) const328         void MapDocumentCommandFacade::removeEmptyNodes(Model::ParentChildrenMap& nodes, const Model::NodeList& emptyNodes) const {
329             Model::NodeList::const_iterator it, end;
330             for (it = emptyNodes.begin(), end = emptyNodes.end(); it != end; ++it) {
331                 Model::Node* node = *it;
332                 Model::Node* parent = node->parent();
333                 nodes.erase(node);
334                 assert(!VectorUtils::contains(nodes[parent], node));
335                 nodes[parent].push_back(node);
336             }
337         }
338 
ReparentResult(const Model::ParentChildrenMap & i_movedNodes,const Model::ParentChildrenMap & i_removedNodes)339         MapDocumentCommandFacade::ReparentResult::ReparentResult(const Model::ParentChildrenMap& i_movedNodes, const Model::ParentChildrenMap& i_removedNodes) :
340         movedNodes(i_movedNodes),
341         removedNodes(i_removedNodes) {}
342 
performReparentNodes(const Model::ParentChildrenMap & nodes,const EmptyNodePolicy emptyNodePolicy)343         MapDocumentCommandFacade::ReparentResult MapDocumentCommandFacade::performReparentNodes(const Model::ParentChildrenMap& nodes, const EmptyNodePolicy emptyNodePolicy) {
344             const Model::NodeList emptyParents = emptyNodePolicy == RemoveEmptyNodes ? findRemovableEmptyParentNodes(nodes) : Model::EmptyNodeList;
345 
346             const Model::NodeList nodesToNotify = Model::collectChildren(nodes);
347             const Model::NodeList parentsToNotify = VectorUtils::eraseAll(Model::collectParents(nodes), emptyParents);
348 
349             Model::NodeList nodesWithChangedLockState;
350             Model::NodeList nodesWithChangedVisibilityState;
351 
352             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parentsToNotify);
353             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodesToNotify);
354 
355             Model::ParentChildrenMap movedNodes;
356 
357             Model::ParentChildrenMap::const_iterator pcIt, pcEnd;
358             Model::NodeList::const_iterator nIt, nEnd;
359 
360             for (pcIt = nodes.begin(), pcEnd = nodes.end(); pcIt != pcEnd; ++pcIt) {
361                 Model::Node* newParent = pcIt->first;
362                 const Model::NodeList& children = pcIt->second;
363 
364                 for (nIt = children.begin(), nEnd = children.end(); nIt != nEnd; ++nIt) {
365                     Model::Node* child = *nIt;
366                     Model::Node* oldParent = child->parent();
367                     assert(oldParent != NULL);
368 
369                     const bool wasLocked = child->locked();
370                     const bool wasHidden = child->hidden();
371 
372                     movedNodes[oldParent].push_back(child);
373                     oldParent->removeChild(child);
374                     newParent->addChild(child);
375 
376                     if (wasLocked != child->locked())
377                         nodesWithChangedLockState.push_back(child);
378                     if (wasHidden != child->hidden())
379                         nodesWithChangedVisibilityState.push_back(child);
380                 }
381             }
382 
383             nodeLockingDidChangeNotifier(nodesWithChangedLockState);
384             nodeVisibilityDidChangeNotifier(nodesWithChangedVisibilityState);
385 
386             const Model::ParentChildrenMap removedNodes = performRemoveNodes(emptyParents);
387             return ReparentResult(movedNodes, removedNodes);
388         }
389 
findRemovableEmptyParentNodes(const Model::ParentChildrenMap & nodes) const390         Model::NodeList MapDocumentCommandFacade::findRemovableEmptyParentNodes(const Model::ParentChildrenMap& nodes) const {
391             Model::NodeList emptyParents;
392 
393             typedef std::map<Model::Node*, size_t> RemoveCounts;
394             RemoveCounts counts;
395 
396             Model::ParentChildrenMap::const_iterator pcIt, pcEnd;
397             Model::NodeList::const_iterator nIt, nEnd;
398 
399             for (pcIt = nodes.begin(), pcEnd = nodes.end(); pcIt != pcEnd; ++pcIt) {
400                 const Model::NodeList& children = pcIt->second;
401 
402                 for (nIt = children.begin(), nEnd = children.end(); nIt != nEnd; ++nIt) {
403                     Model::Node* child = *nIt;
404                     Model::Node* oldParent = child->parent();
405                     assert(oldParent != NULL);
406 
407                     const size_t count = MapUtils::find(counts, oldParent, size_t(0)) + 1;
408                     MapUtils::insertOrReplace(counts, oldParent, count);
409 
410                     if (oldParent->removeIfEmpty() && oldParent->childCount() == count)
411                         emptyParents.push_back(oldParent);
412                 }
413             }
414 
415             return emptyParents;
416         }
417 
setVisibilityState(const Model::NodeList & nodes,const Model::VisibilityState visibilityState)418         Model::VisibilityMap MapDocumentCommandFacade::setVisibilityState(const Model::NodeList& nodes, const Model::VisibilityState visibilityState) {
419             Model::VisibilityMap result;
420 
421             Model::NodeList changedNodes;
422             changedNodes.reserve(nodes.size());
423 
424             Model::NodeList::const_iterator it, end;
425             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
426                 Model::Node* node = *it;
427                 const Model::VisibilityState oldState = node->visibilityState();
428                 if (node->setVisiblityState(visibilityState)) {
429                     changedNodes.push_back(node);
430                     result[node] = oldState;
431                 }
432             }
433 
434             nodeVisibilityDidChangeNotifier(changedNodes);
435             return result;
436         }
437 
setVisibilityEnsured(const Model::NodeList & nodes)438         Model::VisibilityMap MapDocumentCommandFacade::setVisibilityEnsured(const Model::NodeList& nodes) {
439             Model::VisibilityMap result;
440 
441             Model::NodeList changedNodes;
442             changedNodes.reserve(nodes.size());
443 
444             Model::NodeList::const_iterator it, end;
445             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
446                 Model::Node* node = *it;
447                 const Model::VisibilityState oldState = node->visibilityState();
448                 if (node->ensureVisible()) {
449                     changedNodes.push_back(node);
450                     result[node] = oldState;
451                 }
452             }
453 
454             nodeVisibilityDidChangeNotifier(changedNodes);
455             return result;
456         }
457 
restoreVisibilityState(const Model::VisibilityMap & nodes)458         void MapDocumentCommandFacade::restoreVisibilityState(const Model::VisibilityMap& nodes) {
459             Model::NodeList changedNodes;
460             changedNodes.reserve(nodes.size());
461 
462             Model::VisibilityMap::const_iterator it, end;
463             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
464                 Model::Node* node = it->first;
465                 const Model::VisibilityState state = it->second;
466                 if (node->setVisiblityState(state))
467                     changedNodes.push_back(node);
468             }
469 
470             nodeVisibilityDidChangeNotifier(changedNodes);
471         }
472 
setLockState(const Model::NodeList & nodes,const Model::LockState lockState)473         Model::LockStateMap MapDocumentCommandFacade::setLockState(const Model::NodeList& nodes, const Model::LockState lockState) {
474             Model::LockStateMap result;
475 
476             Model::NodeList changedNodes;
477             changedNodes.reserve(nodes.size());
478 
479             Model::NodeList::const_iterator it, end;
480             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
481                 Model::Node* node = *it;
482                 const Model::LockState oldState = node->lockState();
483                 if (node->setLockState(lockState)) {
484                     changedNodes.push_back(node);
485                     result[node] = oldState;
486                 }
487             }
488 
489             nodeLockingDidChangeNotifier(changedNodes);
490             return result;
491         }
492 
restoreLockState(const Model::LockStateMap & nodes)493         void MapDocumentCommandFacade::restoreLockState(const Model::LockStateMap& nodes) {
494             Model::NodeList changedNodes;
495             changedNodes.reserve(nodes.size());
496 
497             Model::LockStateMap::const_iterator it, end;
498             for (it = nodes.begin(), end = nodes.end(); it != end; ++it) {
499                 Model::Node* node = it->first;
500                 const Model::LockState state = it->second;
501                 if (node->setLockState(state))
502                     changedNodes.push_back(node);
503             }
504 
505             nodeLockingDidChangeNotifier(changedNodes);
506         }
507 
508         class MapDocumentCommandFacade::RenameGroupsVisitor : public Model::NodeVisitor {
509         private:
510             const String& m_newName;
511             Model::GroupNameMap m_oldNames;
512         public:
RenameGroupsVisitor(const String & newName)513             RenameGroupsVisitor(const String& newName) : m_newName(newName) {}
oldNames() const514             const Model::GroupNameMap& oldNames() const { return m_oldNames; }
515         private:
doVisit(Model::World * world)516             void doVisit(Model::World* world)   {}
doVisit(Model::Layer * layer)517             void doVisit(Model::Layer* layer)   {}
doVisit(Model::Group * group)518             void doVisit(Model::Group* group)   {
519                 m_oldNames[group] = group->name();
520                 group->setName(m_newName);
521             }
doVisit(Model::Entity * entity)522             void doVisit(Model::Entity* entity) {}
doVisit(Model::Brush * brush)523             void doVisit(Model::Brush* brush)   {}
524         };
525 
526         class MapDocumentCommandFacade::UndoRenameGroupsVisitor : public Model::NodeVisitor {
527         private:
528             const Model::GroupNameMap& m_newNames;
529         public:
UndoRenameGroupsVisitor(const Model::GroupNameMap & newNames)530             UndoRenameGroupsVisitor(const Model::GroupNameMap& newNames) : m_newNames(newNames) {}
531         private:
doVisit(Model::World * world)532             void doVisit(Model::World* world)   {}
doVisit(Model::Layer * layer)533             void doVisit(Model::Layer* layer)   {}
doVisit(Model::Group * group)534             void doVisit(Model::Group* group)   {
535                 assert(m_newNames.count(group) == 1);
536                 const String& newName = MapUtils::find(m_newNames, group, group->name());
537                 group->setName(newName);
538             }
doVisit(Model::Entity * entity)539             void doVisit(Model::Entity* entity) {}
doVisit(Model::Brush * brush)540             void doVisit(Model::Brush* brush)   {}
541         };
542 
performRenameGroups(const String & newName)543         Model::GroupNameMap MapDocumentCommandFacade::performRenameGroups(const String& newName) {
544             const Model::NodeList& nodes = m_selectedNodes.nodes();
545             const Model::NodeList parents = collectParents(nodes);
546 
547             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
548             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
549 
550             RenameGroupsVisitor visitor(newName);
551             Model::Node::accept(nodes.begin(), nodes.end(), visitor);
552             return visitor.oldNames();
553         }
554 
performUndoRenameGroups(const Model::GroupNameMap & newNames)555         void MapDocumentCommandFacade::performUndoRenameGroups(const Model::GroupNameMap& newNames) {
556             const Model::NodeList& nodes = m_selectedNodes.nodes();
557             const Model::NodeList parents = collectParents(nodes);
558 
559             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
560             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
561 
562             UndoRenameGroupsVisitor visitor(newNames);
563             Model::Node::accept(nodes.begin(), nodes.end(), visitor);
564         }
565 
performPushGroup(Model::Group * group)566         void MapDocumentCommandFacade::performPushGroup(Model::Group* group) {
567             m_editorContext->pushGroup(group);
568             groupWasOpenedNotifier(group);
569         }
570 
performPopGroup()571         void MapDocumentCommandFacade::performPopGroup() {
572             Model::Group* previousGroup = m_editorContext->currentGroup();
573             m_editorContext->popGroup();
574             groupWasClosedNotifier(previousGroup);
575         }
576 
performTransform(const Mat4x4 & transform,const bool lockTextures)577         void MapDocumentCommandFacade::performTransform(const Mat4x4& transform, const bool lockTextures) {
578             const Model::NodeList& nodes = m_selectedNodes.nodes();
579             const Model::NodeList parents = collectParents(nodes);
580 
581             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
582             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
583 
584             Model::TransformObjectVisitor visitor(transform, lockTextures, m_worldBounds);
585             Model::Node::accept(nodes.begin(), nodes.end(), visitor);
586 
587             invalidateSelectionBounds();
588         }
589 
performSetAttribute(const Model::AttributeName & name,const Model::AttributeValue & value)590         Model::EntityAttributeSnapshot::Map MapDocumentCommandFacade::performSetAttribute(const Model::AttributeName& name, const Model::AttributeValue& value) {
591             const Model::AttributableNodeList attributableNodes = allSelectedAttributableNodes();
592             const Model::NodeList nodes(attributableNodes.begin(), attributableNodes.end());
593             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
594 
595             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
596             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
597 
598             Model::EntityAttributeSnapshot::Map snapshot;
599 
600             Model::AttributableNodeList::const_iterator it, end;
601             for (it = attributableNodes.begin(), end = attributableNodes.end(); it != end; ++it) {
602                 Model::AttributableNode* node = *it;
603                 snapshot.insert(std::make_pair(node, node->attributeSnapshot(name)));
604                 node->addOrUpdateAttribute(name, value);
605             }
606 
607             setEntityDefinitions(nodes);
608 
609             return snapshot;
610         }
611 
performRemoveAttribute(const Model::AttributeName & name)612         Model::EntityAttributeSnapshot::Map MapDocumentCommandFacade::performRemoveAttribute(const Model::AttributeName& name) {
613             const Model::AttributableNodeList attributableNodes = allSelectedAttributableNodes();
614             const Model::NodeList nodes(attributableNodes.begin(), attributableNodes.end());
615             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
616 
617             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
618             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
619 
620             static const Model::AttributeValue DefaultValue = "";
621             Model::EntityAttributeSnapshot::Map snapshot;
622 
623             Model::AttributableNodeList::const_iterator it, end;
624             for (it = attributableNodes.begin(), end = attributableNodes.end(); it != end; ++it) {
625                 Model::AttributableNode* node = *it;
626                 snapshot.insert(std::make_pair(node, node->attributeSnapshot(name)));
627                 node->removeAttribute(name);
628             }
629 
630             setEntityDefinitions(nodes);
631 
632             return snapshot;
633         }
634 
performConvertColorRange(const Model::AttributeName & name,Assets::ColorRange::Type colorRange)635         Model::EntityAttributeSnapshot::Map MapDocumentCommandFacade::performConvertColorRange(const Model::AttributeName& name, Assets::ColorRange::Type colorRange) {
636             const Model::AttributableNodeList attributableNodes = allSelectedAttributableNodes();
637             const Model::NodeList nodes(attributableNodes.begin(), attributableNodes.end());
638             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
639 
640             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
641             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
642 
643             static const Model::AttributeValue DefaultValue = "";
644             Model::EntityAttributeSnapshot::Map snapshot;
645 
646             Model::AttributableNodeList::const_iterator it, end;
647             for (it = attributableNodes.begin(), end = attributableNodes.end(); it != end; ++it) {
648                 Model::AttributableNode* node = *it;
649 
650                 const Model::AttributeValue& oldValue = node->attribute(name, DefaultValue);
651                 if (oldValue != DefaultValue) {
652                     snapshot.insert(std::make_pair(node, node->attributeSnapshot(name)));
653                     node->addOrUpdateAttribute(name, Model::convertEntityColor(oldValue, colorRange));
654                 }
655             }
656 
657             return snapshot;
658         }
659 
performRenameAttribute(const Model::AttributeName & oldName,const Model::AttributeName & newName)660         void MapDocumentCommandFacade::performRenameAttribute(const Model::AttributeName& oldName, const Model::AttributeName& newName) {
661             const Model::AttributableNodeList attributableNodes = allSelectedAttributableNodes();
662             const Model::NodeList nodes(attributableNodes.begin(), attributableNodes.end());
663             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
664 
665             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
666             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
667 
668             Model::AttributableNodeList::const_iterator it, end;
669             for (it = attributableNodes.begin(), end = attributableNodes.end(); it != end; ++it) {
670                 Model::AttributableNode* node = *it;
671                 node->renameAttribute(oldName, newName);
672             }
673 
674             setEntityDefinitions(nodes);
675         }
676 
restoreAttributes(const Model::EntityAttributeSnapshot::Map & attributes)677         void MapDocumentCommandFacade::restoreAttributes(const Model::EntityAttributeSnapshot::Map& attributes) {
678             const Model::AttributableNodeList attributableNodes = MapUtils::keyList(attributes);
679             const Model::NodeList nodes(attributableNodes.begin(), attributableNodes.end());
680 
681             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
682             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
683             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
684 
685             Model::EntityAttributeSnapshot::Map::const_iterator it, end;
686             for (it = attributes.begin(), end = attributes.end(); it != end; ++it) {
687                 Model::AttributableNode* node = it->first;
688                 assert(node->selected() || node->descendantSelected());
689 
690                 const Model::EntityAttributeSnapshot& snapshot = it->second;
691                 snapshot.restore(node);
692             }
693 
694             setEntityDefinitions(nodes);
695         }
696 
performResizeBrushes(const Model::BrushFaceList & faces,const Vec3 & delta)697         bool MapDocumentCommandFacade::performResizeBrushes(const Model::BrushFaceList& faces, const Vec3& delta) {
698             Model::NodeList nodes;
699 
700             Model::BrushFaceList::const_iterator it, end;
701             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
702                 Model::BrushFace* face = *it;
703                 Model::Brush* brush = face->brush();
704                 assert(brush->selected());
705 
706                 if (!brush->canMoveBoundary(m_worldBounds, face, delta))
707                     return false;
708 
709                 nodes.push_back(brush);
710             }
711 
712             const Model::NodeList parents = collectParents(nodes.begin(), nodes.end());
713             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
714             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
715 
716             for (it = faces.begin(), faces.end(); it != end; ++it) {
717                 Model::BrushFace* face = *it;
718                 Model::Brush* brush = face->brush();
719                 brush->moveBoundary(m_worldBounds, face, delta, textureLock());
720             }
721 
722             invalidateSelectionBounds();
723 
724             return true;
725         }
726 
performMoveTextures(const Vec3f & cameraUp,const Vec3f & cameraRight,const Vec2f & delta)727         void MapDocumentCommandFacade::performMoveTextures(const Vec3f& cameraUp, const Vec3f& cameraRight, const Vec2f& delta) {
728             Model::BrushFaceList::const_iterator it, end;
729             for (it = m_selectedBrushFaces.begin(), end = m_selectedBrushFaces.end(); it != end; ++it) {
730                 Model::BrushFace* face = *it;
731                 face->moveTexture(cameraUp, cameraRight, delta);
732             }
733             brushFacesDidChangeNotifier(m_selectedBrushFaces);
734         }
735 
performRotateTextures(const float angle)736         void MapDocumentCommandFacade::performRotateTextures(const float angle) {
737             Model::BrushFaceList::const_iterator it, end;
738             for (it = m_selectedBrushFaces.begin(), end = m_selectedBrushFaces.end(); it != end; ++it) {
739                 Model::BrushFace* face = *it;
740                 face->rotateTexture(angle);
741             }
742             brushFacesDidChangeNotifier(m_selectedBrushFaces);
743         }
744 
performShearTextures(const Vec2f & factors)745         void MapDocumentCommandFacade::performShearTextures(const Vec2f& factors) {
746             Model::BrushFaceList::const_iterator it, end;
747             for (it = m_selectedBrushFaces.begin(), end = m_selectedBrushFaces.end(); it != end; ++it) {
748                 Model::BrushFace* face = *it;
749                 face->shearTexture(factors);
750             }
751             brushFacesDidChangeNotifier(m_selectedBrushFaces);
752         }
753 
performChangeBrushFaceAttributes(const Model::ChangeBrushFaceAttributesRequest & request)754         void MapDocumentCommandFacade::performChangeBrushFaceAttributes(const Model::ChangeBrushFaceAttributesRequest& request) {
755             const Model::BrushFaceList& faces = allSelectedBrushFaces();
756             request.evaluate(faces);
757             setTextures(faces);
758             brushFacesDidChangeNotifier(faces);
759         }
760 
performFindPlanePoints()761         Model::Snapshot* MapDocumentCommandFacade::performFindPlanePoints() {
762             const Model::BrushList& brushes = m_selectedNodes.brushes();
763             Model::Snapshot* snapshot = new Model::Snapshot(brushes.begin(), brushes.end());
764 
765             const Model::NodeList nodes(brushes.begin(), brushes.end());
766             const Model::NodeList parents = collectParents(nodes);
767 
768             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
769             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
770 
771             Model::BrushList::const_iterator it, end;
772             for (it = brushes.begin(), end = brushes.end(); it != end; ++it) {
773                 Model::Brush* brush = *it;
774                 brush->findIntegerPlanePoints(m_worldBounds);
775             }
776 
777             return snapshot;
778         }
779 
performSnapVertices(const Model::BrushVerticesMap & vertices,const size_t snapTo)780         Vec3::List MapDocumentCommandFacade::performSnapVertices(const Model::BrushVerticesMap& vertices, const size_t snapTo) {
781             const Model::NodeList& nodes = m_selectedNodes.nodes();
782             const Model::NodeList parents = collectParents(nodes);
783 
784             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
785             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
786 
787             size_t succeededBrushCount = 0;
788             size_t failedBrushCount = 0;
789             size_t failedVertexCount = 0;
790 
791             Vec3::List newVertexPositions;
792             Model::BrushVerticesMap::const_iterator it, end;
793             for (it = vertices.begin(), end = vertices.end(); it != end; ++it) {
794                 Model::Brush* brush = it->first;
795                 const Vec3::List& oldPositions = it->second;
796                 if (brush->canSnapVertices(m_worldBounds, oldPositions, snapTo)) {
797                     const Vec3::List newPositions = brush->snapVertices(m_worldBounds, oldPositions, snapTo);
798                     VectorUtils::append(newVertexPositions, newPositions);
799                     succeededBrushCount += 1;
800                 } else {
801                     failedBrushCount += 1;
802                     failedVertexCount += oldPositions.size();
803                 }
804             }
805 
806             invalidateSelectionBounds();
807 
808             if (!newVertexPositions.empty()) {
809                 StringStream msg;
810                 msg << "Snapped " << newVertexPositions.size() << " " << StringUtils::safePlural(newVertexPositions.size(), "vertex", "vertices") << " of " << succeededBrushCount << " " << StringUtils::safePlural(succeededBrushCount, "brush", "brushes");
811                 info(msg.str());
812             }
813             if (failedVertexCount > 0) {
814                 StringStream msg;
815                 msg << "Failed to snap " << failedVertexCount << " " << StringUtils::safePlural(failedVertexCount, "vertex", "vertices") << " of " << failedBrushCount << " " << StringUtils::safePlural(failedBrushCount, "brush", "brushes");
816                 info(msg.str());
817             }
818 
819             return newVertexPositions;
820         }
821 
performMoveVertices(const Model::BrushVerticesMap & vertices,const Vec3 & delta)822         Vec3::List MapDocumentCommandFacade::performMoveVertices(const Model::BrushVerticesMap& vertices, const Vec3& delta) {
823             const Model::NodeList& nodes = m_selectedNodes.nodes();
824             const Model::NodeList parents = collectParents(nodes);
825 
826             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
827             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
828 
829             Vec3::List newVertexPositions;
830             Model::BrushVerticesMap::const_iterator it, end;
831             for (it = vertices.begin(), end = vertices.end(); it != end; ++it) {
832                 Model::Brush* brush = it->first;
833                 const Vec3::List& oldPositions = it->second;
834                 const Vec3::List newPositions = brush->moveVertices(m_worldBounds, oldPositions, delta);
835                 VectorUtils::append(newVertexPositions, newPositions);
836             }
837 
838             invalidateSelectionBounds();
839 
840             return newVertexPositions;
841         }
842 
performMoveEdges(const Model::BrushEdgesMap & edges,const Vec3 & delta)843         Edge3::List MapDocumentCommandFacade::performMoveEdges(const Model::BrushEdgesMap& edges, const Vec3& delta) {
844             const Model::NodeList& nodes = m_selectedNodes.nodes();
845             const Model::NodeList parents = collectParents(nodes);
846 
847             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
848             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
849 
850             Edge3::List newEdgePositions;
851             Model::BrushEdgesMap::const_iterator it, end;
852             for (it = edges.begin(), end = edges.end(); it != end; ++it) {
853                 Model::Brush* brush = it->first;
854                 const Edge3::List& oldPositions = it->second;
855                 const Edge3::List newPositions = brush->moveEdges(m_worldBounds, oldPositions, delta);
856                 VectorUtils::append(newEdgePositions, newPositions);
857             }
858 
859             return newEdgePositions;
860         }
861 
performMoveFaces(const Model::BrushFacesMap & faces,const Vec3 & delta)862         Polygon3::List MapDocumentCommandFacade::performMoveFaces(const Model::BrushFacesMap& faces, const Vec3& delta) {
863             const Model::NodeList& nodes = m_selectedNodes.nodes();
864             const Model::NodeList parents = collectParents(nodes);
865 
866             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
867             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
868 
869             Polygon3::List newFacePositions;
870             Model::BrushFacesMap::const_iterator it, end;
871             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
872                 Model::Brush* brush = it->first;
873                 const Polygon3::List& oldPositions = it->second;
874                 const Polygon3::List newPositions = brush->moveFaces(m_worldBounds, oldPositions, delta);
875                 VectorUtils::append(newFacePositions, newPositions);
876             }
877 
878             invalidateSelectionBounds();
879 
880             return newFacePositions;
881         }
882 
performSplitEdges(const Model::BrushEdgesMap & edges,const Vec3 & delta)883         Vec3::List MapDocumentCommandFacade::performSplitEdges(const Model::BrushEdgesMap& edges, const Vec3& delta) {
884             const Model::NodeList& nodes = m_selectedNodes.nodes();
885             const Model::NodeList parents = collectParents(nodes);
886 
887             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
888             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
889 
890             Vec3::List newVertexPositions;
891             Model::BrushEdgesMap::const_iterator it, end;
892             for (it = edges.begin(), end = edges.end(); it != end; ++it) {
893                 Model::Brush* brush = it->first;
894                 const Edge3::List& oldPositions = it->second;
895                 for (size_t i = 0; i < oldPositions.size(); ++i) {
896                     const Edge3& edgePosition = oldPositions[i];
897                     const Vec3 vertexPosition = brush->splitEdge(m_worldBounds, edgePosition, delta);
898                     newVertexPositions.push_back(vertexPosition);
899                 }
900             }
901 
902             invalidateSelectionBounds();
903 
904             return newVertexPositions;
905         }
906 
performSplitFaces(const Model::BrushFacesMap & faces,const Vec3 & delta)907         Vec3::List MapDocumentCommandFacade::performSplitFaces(const Model::BrushFacesMap& faces, const Vec3& delta) {
908             const Model::NodeList& nodes = m_selectedNodes.nodes();
909             const Model::NodeList parents = collectParents(nodes);
910 
911             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
912             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
913 
914             Vec3::List newVertexPositions;
915             Model::BrushFacesMap::const_iterator it, end;
916             for (it = faces.begin(), end = faces.end(); it != end; ++it) {
917                 Model::Brush* brush = it->first;
918                 const Polygon3::List& oldPositions = it->second;
919                 for (size_t i = 0; i < oldPositions.size(); ++i) {
920                     const Polygon3& facePosition = oldPositions[i];
921                     const Vec3 vertexPosition = brush->splitFace(m_worldBounds, facePosition, delta);
922                     newVertexPositions.push_back(vertexPosition);
923                 }
924             }
925 
926             invalidateSelectionBounds();
927 
928             return newVertexPositions;
929         }
930 
performRebuildBrushGeometry(const Model::BrushList & brushes)931         void MapDocumentCommandFacade::performRebuildBrushGeometry(const Model::BrushList& brushes) {
932             const Model::NodeList nodes = VectorUtils::cast<Model::Node*>(brushes);
933             const Model::NodeList parents = collectParents(nodes);
934 
935             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
936             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
937 
938             Model::BrushList::const_iterator it, end;
939             for (it = brushes.begin(), end = brushes.end(); it != end; ++it) {
940                 Model::Brush* brush = *it;
941                 brush->rebuildGeometry(m_worldBounds);
942             }
943 
944             invalidateSelectionBounds();
945         }
946 
restoreSnapshot(Model::Snapshot * snapshot)947         void MapDocumentCommandFacade::restoreSnapshot(Model::Snapshot* snapshot) {
948             if (!m_selectedNodes.empty()) {
949                 const Model::NodeList& nodes = m_selectedNodes.nodes();
950                 const Model::NodeList parents = collectParents(nodes);
951 
952                 Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyParents(nodesWillChangeNotifier, nodesDidChangeNotifier, parents);
953                 Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
954 
955                 snapshot->restoreNodes(m_worldBounds);
956 
957                 invalidateSelectionBounds();
958             }
959 
960             const Model::BrushFaceList brushFaces = allSelectedBrushFaces();
961             if (!brushFaces.empty()) {
962                 snapshot->restoreBrushFaces();
963                 setTextures(brushFaces);
964                 brushFacesDidChangeNotifier(brushFaces);
965             }
966         }
967 
performSetEntityDefinitionFile(const Assets::EntityDefinitionFileSpec & spec)968         void MapDocumentCommandFacade::performSetEntityDefinitionFile(const Assets::EntityDefinitionFileSpec& spec) {
969             const Model::NodeList nodes(1, m_world);
970             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
971             Notifier0::NotifyAfter notifyEntityDefinitions(entityDefinitionsDidChangeNotifier);
972 
973             // to avoid backslashes being misinterpreted as escape sequences
974             const String formatted = StringUtils::replaceAll(spec.asString(), "\\", "/");
975             m_world->addOrUpdateAttribute(Model::AttributeNames::EntityDefinitions, formatted);
976             reloadEntityDefinitions();
977         }
978 
performAddExternalTextureCollections(const StringList & names)979         void MapDocumentCommandFacade::performAddExternalTextureCollections(const StringList& names) {
980             const Model::NodeList nodes(1, m_world);
981             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
982             Notifier0::NotifyAfter notifyTextureCollections(textureCollectionsDidChangeNotifier);
983 
984             addExternalTextureCollections(names);
985             setTextures();
986             updateExternalTextureCollectionProperty();
987         }
988 
performRemoveExternalTextureCollections(const StringList & names)989         void MapDocumentCommandFacade::performRemoveExternalTextureCollections(const StringList& names) {
990             const Model::NodeList nodes(1, m_world);
991             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
992             Notifier0::NotifyAfter notifyTextureCollections(textureCollectionsDidChangeNotifier);
993 
994             unsetTextures();
995 
996             StringList::const_iterator it, end;
997             for (it = names.begin(), end = names.end(); it != end; ++it) {
998                 const String& name = *it;
999                 m_textureManager->removeExternalTextureCollection(name);
1000             }
1001 
1002             setTextures();
1003             updateExternalTextureCollectionProperty();
1004         }
1005 
performMoveExternalTextureCollectionUp(const String & name)1006         void MapDocumentCommandFacade::performMoveExternalTextureCollectionUp(const String& name) {
1007             const Model::NodeList nodes(1, m_world);
1008             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
1009             Notifier0::NotifyAfter notifyTextureCollections(textureCollectionsDidChangeNotifier);
1010 
1011             m_textureManager->moveExternalTextureCollectionUp(name);
1012             setTextures();
1013             updateExternalTextureCollectionProperty();
1014         }
1015 
performMoveExternalTextureCollectionDown(const String & name)1016         void MapDocumentCommandFacade::performMoveExternalTextureCollectionDown(const String& name) {
1017             const Model::NodeList nodes(1, m_world);
1018             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
1019             Notifier0::NotifyAfter notifyTextureCollections(textureCollectionsDidChangeNotifier);
1020 
1021             m_textureManager->moveExternalTextureCollectionDown(name);
1022             setTextures();
1023             updateExternalTextureCollectionProperty();
1024         }
1025 
performSetMods(const StringList & mods)1026         void MapDocumentCommandFacade::performSetMods(const StringList& mods) {
1027             const Model::NodeList nodes(1, m_world);
1028             Notifier1<const Model::NodeList&>::NotifyBeforeAndAfter notifyNodes(nodesWillChangeNotifier, nodesDidChangeNotifier, nodes);
1029             Notifier0::NotifyAfter notifyMods(modsDidChangeNotifier);
1030 
1031             unsetEntityDefinitions();
1032             clearEntityModels();
1033             m_world->addOrUpdateAttribute(Model::AttributeNames::Mods, StringUtils::join(mods, ";"));
1034             updateGameSearchPaths();
1035             setEntityDefinitions();
1036             setEntityModels();
1037         }
1038 
doSetIssueHidden(Model::Issue * issue,const bool hidden)1039         void MapDocumentCommandFacade::doSetIssueHidden(Model::Issue* issue, const bool hidden) {
1040             if (issue->hidden() != hidden) {
1041                 issue->setHidden(hidden);
1042                 incModificationCount();
1043             }
1044         }
1045 
incModificationCount(const size_t delta)1046         void MapDocumentCommandFacade::incModificationCount(const size_t delta) {
1047             m_modificationCount += delta;
1048             documentModificationStateDidChangeNotifier();
1049         }
1050 
decModificationCount(const size_t delta)1051         void MapDocumentCommandFacade::decModificationCount(const size_t delta) {
1052             assert(m_modificationCount >= delta);
1053             m_modificationCount -= delta;
1054             documentModificationStateDidChangeNotifier();
1055         }
1056 
bindObservers()1057         void MapDocumentCommandFacade::bindObservers() {
1058             m_commandProcessor.commandDoNotifier.addObserver(commandDoNotifier);
1059             m_commandProcessor.commandDoneNotifier.addObserver(commandDoneNotifier);
1060             m_commandProcessor.commandDoFailedNotifier.addObserver(commandDoFailedNotifier);
1061             m_commandProcessor.commandUndoNotifier.addObserver(commandUndoNotifier);
1062             m_commandProcessor.commandUndoneNotifier.addObserver(commandUndoneNotifier);
1063             m_commandProcessor.commandUndoFailedNotifier.addObserver(commandUndoFailedNotifier);
1064             documentWasNewedNotifier.addObserver(this, &MapDocumentCommandFacade::documentWasNewed);
1065             documentWasLoadedNotifier.addObserver(this, &MapDocumentCommandFacade::documentWasLoaded);
1066         }
1067 
documentWasNewed(MapDocument * document)1068         void MapDocumentCommandFacade::documentWasNewed(MapDocument* document) {
1069             m_commandProcessor.clear();
1070         }
1071 
documentWasLoaded(MapDocument * document)1072         void MapDocumentCommandFacade::documentWasLoaded(MapDocument* document) {
1073             m_commandProcessor.clear();
1074         }
1075 
doCanUndoLastCommand() const1076         bool MapDocumentCommandFacade::doCanUndoLastCommand() const {
1077             return m_commandProcessor.hasLastCommand();
1078         }
1079 
doCanRedoNextCommand() const1080         bool MapDocumentCommandFacade::doCanRedoNextCommand() const {
1081             return m_commandProcessor.hasNextCommand();
1082         }
1083 
doGetLastCommandName() const1084         const String& MapDocumentCommandFacade::doGetLastCommandName() const {
1085             return m_commandProcessor.lastCommandName();
1086         }
1087 
doGetNextCommandName() const1088         const String& MapDocumentCommandFacade::doGetNextCommandName() const {
1089             return m_commandProcessor.nextCommandName();
1090         }
1091 
doUndoLastCommand()1092         void MapDocumentCommandFacade::doUndoLastCommand() {
1093             m_commandProcessor.undoLastCommand();
1094         }
1095 
doRedoNextCommand()1096         void MapDocumentCommandFacade::doRedoNextCommand() {
1097             m_commandProcessor.redoNextCommand();
1098         }
1099 
doRepeatLastCommands()1100         bool MapDocumentCommandFacade::doRepeatLastCommands() {
1101             return m_commandProcessor.repeatLastCommands();
1102         }
1103 
doClearRepeatableCommands()1104         void MapDocumentCommandFacade::doClearRepeatableCommands() {
1105             m_commandProcessor.clearRepeatableCommands();
1106         }
1107 
doBeginTransaction(const String & name)1108         void MapDocumentCommandFacade::doBeginTransaction(const String& name) {
1109             m_commandProcessor.beginGroup(name);
1110         }
1111 
doEndTransaction()1112         void MapDocumentCommandFacade::doEndTransaction() {
1113             m_commandProcessor.endGroup();
1114         }
1115 
doRollbackTransaction()1116         void MapDocumentCommandFacade::doRollbackTransaction() {
1117             m_commandProcessor.rollbackGroup();
1118         }
1119 
doSubmit(UndoableCommand::Ptr command)1120         bool MapDocumentCommandFacade::doSubmit(UndoableCommand::Ptr command) {
1121             return m_commandProcessor.submitAndStoreCommand(command);
1122         }
1123     }
1124 }
1125