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 "DuplicateNodesCommand.h" 21 22 #include "Model/Node.h" 23 #include "Model/NodeVisitor.h" 24 #include "View/MapDocumentCommandFacade.h" 25 26 namespace TrenchBroom { 27 namespace View { 28 const Command::CommandType DuplicateNodesCommand::Type = Command::freeType(); 29 duplicate()30 DuplicateNodesCommand::Ptr DuplicateNodesCommand::duplicate() { 31 return Ptr(new DuplicateNodesCommand()); 32 } 33 DuplicateNodesCommand()34 DuplicateNodesCommand::DuplicateNodesCommand() : 35 DocumentCommand(Type, "Duplicate Objects") {} 36 doPerformDo(MapDocumentCommandFacade * document)37 bool DuplicateNodesCommand::doPerformDo(MapDocumentCommandFacade* document) { 38 typedef std::pair<bool, Model::NodeMap::iterator> NodeMapInsertPos; 39 40 Model::NodeMap newParentMap; 41 Model::ParentChildrenMap nodesToAdd; 42 Model::NodeList nodesToSelect; 43 44 const BBox3& worldBounds = document->worldBounds(); 45 m_previouslySelectedNodes = document->selectedNodes().nodes(); 46 47 Model::NodeList::const_iterator it, end; 48 for (it = m_previouslySelectedNodes.begin(), end = m_previouslySelectedNodes.end(); it != end; ++it) { 49 const Model::Node* original = *it; 50 Model::Node* clone = original->cloneRecursively(worldBounds); 51 52 Model::Node* parent = original->parent(); 53 if (cloneParent(parent)) { 54 NodeMapInsertPos insertPos = MapUtils::findInsertPos(newParentMap, parent); 55 Model::Node* newParent = NULL; 56 if (insertPos.first) { 57 newParent = (insertPos.second)->second; 58 } else { 59 newParent = parent->clone(worldBounds); 60 newParentMap.insert(insertPos.second, std::make_pair(parent, newParent)); 61 nodesToAdd[parent->parent()].push_back(newParent); 62 } 63 64 newParent->addChild(clone); 65 } else { 66 nodesToAdd[parent].push_back(clone); 67 } 68 69 nodesToSelect.push_back(clone); 70 } 71 72 m_addedNodes = document->performAddNodes(nodesToAdd); 73 document->performDeselectAll(); 74 document->performSelect(nodesToSelect); 75 return true; 76 } 77 doPerformUndo(MapDocumentCommandFacade * document)78 bool DuplicateNodesCommand::doPerformUndo(MapDocumentCommandFacade* document) { 79 document->performDeselectAll(); 80 document->performRemoveNodes(m_addedNodes); 81 document->performSelect(m_previouslySelectedNodes); 82 83 m_previouslySelectedNodes.clear(); 84 VectorUtils::clearAndDelete(m_addedNodes); 85 return true; 86 } 87 88 class DuplicateNodesCommand::CloneParentQuery : public Model::ConstNodeVisitor, public Model::NodeQuery<bool> { 89 private: doVisit(const Model::World * world)90 void doVisit(const Model::World* world) { setResult(false); } doVisit(const Model::Layer * layer)91 void doVisit(const Model::Layer* layer) { setResult(false); } doVisit(const Model::Group * group)92 void doVisit(const Model::Group* group) { setResult(false); } doVisit(const Model::Entity * entity)93 void doVisit(const Model::Entity* entity) { setResult(true); } doVisit(const Model::Brush * brush)94 void doVisit(const Model::Brush* brush) { setResult(false); } 95 }; 96 cloneParent(const Model::Node * node) const97 bool DuplicateNodesCommand::cloneParent(const Model::Node* node) const { 98 CloneParentQuery query; 99 node->accept(query); 100 return query.result(); 101 } 102 doIsRepeatable(MapDocumentCommandFacade * document) const103 bool DuplicateNodesCommand::doIsRepeatable(MapDocumentCommandFacade* document) const { 104 return document->hasSelectedNodes(); 105 } 106 doRepeat(MapDocumentCommandFacade * document) const107 UndoableCommand::Ptr DuplicateNodesCommand::doRepeat(MapDocumentCommandFacade* document) const { 108 return UndoableCommand::Ptr(new DuplicateNodesCommand()); 109 } 110 doCollateWith(UndoableCommand::Ptr command)111 bool DuplicateNodesCommand::doCollateWith(UndoableCommand::Ptr command) { 112 return false; 113 } 114 } 115 } 116