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