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