1 /*
2 * Copyright 2012, 2013 Thomas Schöps
3 * Copyright 2014 Kai Pastor
4 *
5 * This file is part of OpenOrienteering.
6 *
7 * OpenOrienteering is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * OpenOrienteering is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 #ifndef OPENORIENTEERING_UNDO_H
23 #define OPENORIENTEERING_UNDO_H
24
25 #include "core/symbols/symbol.h"
26
27 #include <set>
28 #include <vector>
29
30 class QXmlStreamReader;
31 class QXmlStreamWriter;
32
33 namespace OpenOrienteering {
34
35 class Map;
36 class Object;
37
38
39 /**
40 * Abstract base class for map editing undo steps.
41 *
42 * UndoStep stores information which is necessary for executing an undo step.
43 * While executing the step, creates a new UndoStep for the corresponding
44 * redo step.
45 *
46 * @see UndoManager
47 */
48 class UndoStep
49 {
50 public:
51 /**
52 * Types of undo steps for identification.
53 *
54 * This is used by the file formats - do not change
55 * existing values.
56 */
57 enum Type
58 {
59 ReplaceObjectsUndoStepType = 0,
60 DeleteObjectsUndoStepType = 1,
61 AddObjectsUndoStepType = 2,
62 SwitchSymbolUndoStepType = 3,
63 SwitchDashesUndoStepType = 4,
64 CombinedUndoStepType = 5,
65 ValidNoOpUndoStepType = 6,
66 ObjectTagsUndoStepType = 7,
67 MapPartUndoStepType = 8,
68 SwitchPartUndoStepTypeV0 = 9,
69 SwitchPartUndoStepType = 10,
70 InvalidUndoStepType = 999
71 };
72
73 /**
74 * A set of integers referring to parts.
75 */
76 typedef std::set<int> PartSet;
77
78
79 /**
80 * A set of pointers to objects.
81 */
82 typedef std::set<Object*> ObjectSet;
83
84
85 /**
86 * Constructs an undo step of the given type.
87 */
88 static UndoStep* getUndoStepForType(Type type, Map* map);
89
90
91 /**
92 * Constructs an undo step having the given type.
93 */
94 UndoStep(Type type, Map* map);
95
96 UndoStep(const UndoStep&) = delete;
97 UndoStep(UndoStep&&) = delete;
98
99 /**
100 * Destructor.
101 */
102 virtual ~UndoStep();
103
104
105 UndoStep& operator=(const UndoStep&) = delete;
106 UndoStep& operator=(UndoStep&&) = delete;
107
108
109 /**
110 * Returns the type of the undo step.
111 */
112 Type getType() const;
113
114
115 /**
116 * Returns true if the step can still be undone.
117 *
118 * Initially (after generating the step) this must return true.
119 * (However, this is different for InvalidUndoStep.)
120 *
121 * Derived classes may return false to indicate that the step is no longer valid.
122 * This may happen after an object the step depends on,
123 * which is not tracked by the undo system, is deleted.
124 *
125 * Example: changing a map object's symbol to a different one,
126 * then deleting the first symbol. Then changing the symbol cannot be undone
127 * as the old symbol does not exist anymore.
128 */
129 virtual bool isValid() const;
130
131
132 /**
133 * Undoes the action and returns a new UndoStep.
134 *
135 * The returned UndoStep can redo the action again.
136 */
137 virtual UndoStep* undo() = 0;
138
139
140 /**
141 * Adds the list of the step's modified parts to the container provided by out.
142 *
143 * The default implementation does nothing and returns false.
144 *
145 * @return True if there are parts (and objects!) modified by this undo step, false otherwise.
146 */
147 virtual bool getModifiedParts(PartSet& out) const;
148
149 /**
150 * Adds the list of the step's modified objects to the container provided by out.
151 *
152 * Only objects which belong to the given part are dealt with.
153 *
154 * The default implementation does nothing.
155 */
156 virtual void getModifiedObjects(int part_index, ObjectSet& out) const;
157
158
159 /**
160 * Loads the undo step from the stream in xml format.
161 */
162 static UndoStep* load(QXmlStreamReader& xml, Map* map, SymbolDictionary& symbol_dict);
163
164 /**
165 * Saves the undo step to the stream in xml format.
166 *
167 * This method is not to be overwritten.
168 *
169 * @see saveImpl()
170 */
171 void save(QXmlStreamWriter& xml) const;
172
173 protected:
174 /**
175 * Saves undo properties to the the xml stream.
176 *
177 * Implementations in derived classes shall first call the parent class'
178 * implementation, and then start a new element for additional properties.
179 */
180 virtual void saveImpl(QXmlStreamWriter& xml) const;
181
182 /**
183 * Loads undo properties from the the xml stream.
184 *
185 * Implementations in derived classes shall first check the element's name
186 * for one of their own elements, and otherwise call the parent class'
187 * implementation.
188 */
189 virtual void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict);
190
191 protected:
192 /**
193 * The type of the undo step.
194 */
195 Type const type;
196
197 /**
198 * The map this undo step belongs.
199 */
200 Map* const map;
201 };
202
203
204
205 /**
206 * @brief An undo step which is actually a sequence of sub UndoSteps.
207 *
208 * A CombinedUndoStep bundles a sequence of one or more UndoSteps,
209 * which it executes in reverse order.
210 */
211 class CombinedUndoStep : public UndoStep
212 {
213 public:
214 /**
215 * Constructs a composite undo step for the given map.
216 */
217 CombinedUndoStep(Map* map);
218
219 /**
220 * Destructor.
221 */
222 ~CombinedUndoStep() override;
223
224
225 /**
226 * Returns true if all sub step can still be undone.
227 */
228 bool isValid() const override;
229
230 /**
231 * Undoes all sub steps in-order and returns a corresponding UndoStep.
232 */
233 UndoStep* undo() override;
234
235
236 /**
237 * Adds the modified parts of all sub steps to the given set.
238 */
239 bool getModifiedParts(PartSet& out) const override;
240
241 /**
242 * Adds the modified objects of all sub steps to the given set.
243 */
244 void getModifiedObjects(int part_index, ObjectSet& out) const override;
245
246
247 /**
248 * Returns the number of sub steps.
249 */
250 int getNumSubSteps() const;
251
252 /**
253 * Adds a sub step.
254 */
255 void push(UndoStep* step);
256
257 /**
258 * Returns the i-th sub step.
259 */
260 UndoStep* getSubStep(int i);
261
262
263 protected:
264 /**
265 * @copybrief UndoStep::saveImpl()
266 */
267 void saveImpl(QXmlStreamWriter& xml) const override;
268
269 /**
270 * @copybrief UndoStep::loadImpl()
271 */
272 void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict) override;
273
274 private:
275 typedef std::vector<UndoStep*> StepList;
276
277 StepList steps;
278 };
279
280
281
282 /**
283 * An undo step which does nothing.
284 *
285 * Its validness depends on the argument given to the constructor.
286 * It always returns a valid NoOpUndoStep from undo().
287 *
288 * This class is used to catch unknown types of undo step when loading files
289 * from newer version of Mapper. Another use is unit-testing the UndoManager.
290 */
291 class NoOpUndoStep : public UndoStep
292 {
293 public:
294 /**
295 * Constructs an undo step for the given map, and determines its validness.
296 */
297 NoOpUndoStep(Map* map, bool valid);
298
299 /**
300 * Destructor.
301 */
302 ~NoOpUndoStep() override;
303
304
305 /**
306 * Returns the validness as given to the constructor.
307 */
308 bool isValid() const override;
309
310
311 /**
312 * Returns a valid NoOpUndoStep.
313 *
314 * Prints a warning if this undo step is not valid.
315 */
316 UndoStep* undo() override;
317
318
319 private:
320 bool const valid;
321 };
322
323
324
325 // ### UndoStep inline code ###
326
327 inline
getType()328 UndoStep::Type UndoStep::getType() const
329 {
330 return type;
331 }
332
333
334 // ### CombinedUndoStep inline code ###
335
336 inline
getNumSubSteps()337 int CombinedUndoStep::getNumSubSteps() const
338 {
339 return (int)steps.size();
340 }
341
342 inline
push(UndoStep * step)343 void CombinedUndoStep::push(UndoStep* step)
344 {
345 steps.push_back(step);
346 }
347
348 inline
getSubStep(int i)349 UndoStep* CombinedUndoStep::getSubStep(int i)
350 {
351 return steps[i];
352 }
353
354
355 } // namespace OpenOrienteering
356
357 #endif
358