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 #ifndef TrenchBroom_NodeVisitor
21 #define TrenchBroom_NodeVisitor
22 
23 #include "Model/ModelTypes.h"
24 
25 namespace TrenchBroom {
26     namespace Model {
27         class BaseNodeVisitor {
28         private:
29             bool m_cancelled;
30             bool m_recursionStopped;
31         protected:
32             BaseNodeVisitor();
33         public:
34             virtual ~BaseNodeVisitor();
35             bool cancelled() const;
36             bool recursionStopped();
37         protected:
38             void cancel();
39             void stopRecursion();
40         };
41 
42         class NodeVisitor : public BaseNodeVisitor {
43         protected:
44             NodeVisitor();
45         public:
46             virtual ~NodeVisitor();
47 
48             virtual void visit(World* world);
49             virtual void visit(Layer* layer);
50             virtual void visit(Group* group);
51             virtual void visit(Entity* entity);
52             virtual void visit(Brush* brush);
53         private:
54             virtual void doVisit(World* world)   = 0;
55             virtual void doVisit(Layer* layer)   = 0;
56             virtual void doVisit(Group* group)   = 0;
57             virtual void doVisit(Entity* entity) = 0;
58             virtual void doVisit(Brush* brush)   = 0;
59         };
60 
61         class ConstNodeVisitor : public BaseNodeVisitor {
62         protected:
63             ConstNodeVisitor();
64         public:
65             virtual ~ConstNodeVisitor();
66 
67             virtual void visit(const World* world);
68             virtual void visit(const Layer* layer);
69             virtual void visit(const Group* group);
70             virtual void visit(const Entity* entity);
71             virtual void visit(const Brush* brush);
72         private:
73             virtual void doVisit(const World* world)   = 0;
74             virtual void doVisit(const Layer* layer)   = 0;
75             virtual void doVisit(const Group* group)   = 0;
76             virtual void doVisit(const Entity* entity) = 0;
77             virtual void doVisit(const Brush* brush)   = 0;
78         };
79 
80 
81         struct NeverStopRecursion {
82             bool operator()(const Node* node, bool matched) const;
83         };
84 
85         struct StopRecursionIfMatched {
86             bool operator()(const Node* node, bool matched) const;
87         };
88 
89         template <class P, class S = NeverStopRecursion>
90         class MatchingNodeVisitor : public NodeVisitor {
91         private:
92             P m_p;
93             S m_s;
94         protected:
m_p(p)95             MatchingNodeVisitor(const P& p = P(), const S& s = S()) : m_p(p), m_s(s) {}
96         public:
~MatchingNodeVisitor()97             virtual ~MatchingNodeVisitor() {}
98 
visit(World * world)99             void visit(World* world) {
100                 const bool match = m_p(world);
101                 if (match) NodeVisitor::visit(world);
102                 if (m_s(world, match)) stopRecursion();
103             }
104 
visit(Layer * layer)105             void visit(Layer* layer) {
106                 const bool match = m_p(layer);
107                 if (match) NodeVisitor::visit(layer);
108                 if (m_s(layer, match)) stopRecursion();
109             }
110 
visit(Group * group)111             void visit(Group* group) {
112                 const bool match = m_p(group);
113                 if (match) NodeVisitor::visit(group);
114                 if (m_s(group, match)) stopRecursion();
115             }
116 
visit(Entity * entity)117             void visit(Entity* entity) {
118                 const bool match = m_p(entity);
119                 if (match) NodeVisitor::visit(entity);
120                 if (m_s(entity, match)) stopRecursion();
121             }
122 
visit(Brush * brush)123             void visit(Brush* brush) {
124                 const bool match = m_p(brush);
125                 if (match) NodeVisitor::visit(brush);
126                 if (m_s(brush, match)) stopRecursion();
127             }
128         };
129 
130         template <class P, class S = NeverStopRecursion>
131         class ConstMatchingNodeVisitor : public ConstNodeVisitor {
132         private:
133             P m_p;
134             S m_s;
135         protected:
m_p(p)136             ConstMatchingNodeVisitor(const P& p = P(), const S& s = S()) : m_p(p), m_s(s) {}
137         public:
~ConstMatchingNodeVisitor()138             virtual ~ConstMatchingNodeVisitor() {}
139 
visit(const World * world)140             void visit(const World* world) {
141                 const bool match = m_p(world);
142                 if (match) ConstNodeVisitor::visit(world);
143                 if (m_s(world, match)) stopRecursion();
144             }
145 
visit(const Layer * layer)146             void visit(const Layer* layer) {
147                 const bool match = m_p(layer);
148                 if (match) ConstNodeVisitor::visit(layer);
149                 if (m_s(layer, match)) stopRecursion();
150             }
151 
visit(const Group * group)152             void visit(const Group* group) {
153                 const bool match = m_p(group);
154                 if (match) ConstNodeVisitor::visit(group);
155                 if (m_s(group, match)) stopRecursion();
156             }
157 
visit(const Entity * entity)158             void visit(const Entity* entity) {
159                 const bool match = m_p(entity);
160                 if (match) ConstNodeVisitor::visit(entity);
161                 if (m_s(entity, match)) stopRecursion();
162             }
163 
visit(const Brush * brush)164             void visit(const Brush* brush) {
165                 const bool match = m_p(brush);
166                 if (match) ConstNodeVisitor::visit(brush);
167                 if (m_s(brush, match)) stopRecursion();
168             }
169         };
170 
171         template <typename T>
172         class NodeQuery {
173         private:
174             bool m_hasResult;
175             T m_result;
176         public:
177             NodeQuery(const T& defaultResult = T()) :
m_hasResult(false)178             m_hasResult(false),
179             m_result(defaultResult) {}
180 
~NodeQuery()181             virtual ~NodeQuery() {}
182 
hasResult()183             bool hasResult() const {
184                 return m_hasResult;
185             }
186 
result()187             T result() const {
188                 assert(hasResult());
189                 return m_result;
190             }
191         protected:
setResult(T result)192             void setResult(T result) {
193                 if (!m_hasResult) {
194                     m_result = result;
195                     m_hasResult = true;
196                 } else {
197                     m_result = doCombineResults(m_result, result);
198                 }
199             }
200         private:
doCombineResults(T oldResult,T newResult)201             virtual T doCombineResults(T oldResult, T newResult) const { return newResult; }
202         };
203     }
204 }
205 
206 #endif /* defined(TrenchBroom_NodeVisitor) */
207