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