1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2014, 2015 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_MAP_UNDO_H
23 #define OPENORIENTEERING_MAP_UNDO_H
24 
25 #include <cstddef>
26 #include <map>
27 #include <utility>
28 #include <vector>
29 
30 #include <QObject>
31 
32 #include "core/objects/object.h"
33 #include "core/symbols/symbol.h"
34 #include "undo/undo.h"
35 
36 class QXmlStreamReader;
37 class QXmlStreamWriter;
38 
39 namespace OpenOrienteering {
40 
41 class Map;
42 class XmlElementReader;
43 class XmlElementWriter;
44 
45 
46 /**
47  * Base class for undo steps which modify objects of a single map part.
48  */
49 class ObjectModifyingUndoStep : public UndoStep
50 {
51 public:
52 	/**
53 	 * Creates an ObjectModifyingUndoStep for the given map and its current part.
54 	 */
55 	ObjectModifyingUndoStep(Type type, Map* map);
56 
57 	/**
58 	 * Creates an ObjectModifyingUndoStep for the given map and part.
59 	 */
60 	ObjectModifyingUndoStep(Type type, Map* map, int part_index);
61 
62 	/**
63 	 * Destructor.
64 	 */
65 	~ObjectModifyingUndoStep() override;
66 
67 
68 	/**
69 	 * Returns the index of the map part modified by this undo step.
70 	 */
71 	int getPartIndex() const;
72 
73 	/**
74 	 * Set the index of the map part modified by this undo step.
75 	 *
76 	 * This must not be called after object have been added.
77 	 */
78 	void setPartIndex(int part_index);
79 
80 
81 	/**
82 	 * Returns true if no objects are modified by this undo step.
83 	 */
84 	virtual bool isEmpty() const;
85 
86 	/**
87 	 * Adds an object (by index) to this step.
88 	 *
89 	 * The object must belong to the step's part.
90 	 */
91 	virtual void addObject(int index);
92 
93 
94 	/**
95 	 * Adds the the step's modified part to the container provided by out.
96 	 *
97 	 * @return True if there are objects modified by this undo step, false otherwise.
98 	 */
99 	bool getModifiedParts(PartSet& out) const override;
100 
101 	/**
102 	 * Adds the list of the step's modified objects to the container provided by out.
103 	 *
104 	 * Only adds objects when the given part_index matches this step's part index.
105 	 */
106 	void getModifiedObjects(int part_index, ObjectSet& out) const override;
107 
108 
109 protected:
110 	/**
111 	 * Saves undo properties to the the xml stream.
112 	 *
113 	 * Implementations in derived classes shall first call the parent class'
114 	 * implementation, and then start a new element for additional properties.
115 	 */
116 	void saveImpl(QXmlStreamWriter& xml) const override;
117 
118 	/**
119 	 * Saves object details to the the xml stream.
120 	 *
121 	 * The default implemenentation does nothing.
122 	 */
123 	virtual void saveObject(XmlElementWriter& xml, int index) const;
124 
125 	/**
126 	 * Loads undo properties from the the xml stream.
127 	 *
128 	 * Implementations in derived classes shall first check the element's name
129 	 * for one of their own elements, and otherwise call the parent class'
130 	 * implementation.
131 	 */
132 	void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict) override;
133 
134 	/**
135 	 * Loads object details from the the xml stream.
136 	 *
137 	 * The default implemenentation does nothing.
138 	 */
139 	virtual void loadObject(XmlElementReader& xml, int index);
140 
141 
142 private:
143 	/**
144 	 * The index of the part all modified objects belong to.
145 	 */
146 	int part_index;
147 
148 protected:
149 	/**
150 	 * A list of indices referring to objects in a map part.
151 	 */
152 	typedef std::vector<int> ObjectList;
153 
154 	/**
155 	 * Indices of the existing objects that are modified by this step.
156 	 */
157 	ObjectList modified_objects;
158 };
159 
160 
161 
162 /**
163  * Base class for undo steps which add new objects to the map.
164  *
165  * Takes care of correctly reacting to symbol changes in the map,
166  * which are not covered by the undo / redo system.
167  *
168  */
169 class ObjectCreatingUndoStep : public QObject, public ObjectModifyingUndoStep
170 {
171 Q_OBJECT
172 public:
173 	/**
174 	 * Constructor.
175 	 */
176 	ObjectCreatingUndoStep(Type type, Map* map);
177 
178 	/**
179 	 * Destructor.
180 	 */
181 	~ObjectCreatingUndoStep() override;
182 
183 
184 	/**
185 	 * Returns true if the step can still be undone.
186 	 *
187 	 * The value returned by this function is taken from the "valid" member variable.
188 	 */
189 	bool isValid() const override;
190 
191 	/**
192 	 * Must not be called.
193 	 *
194 	 * Use the two-parameter signatures instead of this one.
195 	 *
196 	 * Does nothing in release builds. Aborts the program in non-release builds.
197 	 * Reimplemented from ObjectModifyingUndoStep::addObject()).
198 	 */
199 	void addObject(int index) override;
200 
201 	/**
202 	 * Adds an object to the undo step with given index.
203 	 */
204 	void addObject(int existing_index, Object* object);
205 
206 	/**
207 	 * Adds an object to the undo step with the index of the existing object.
208 	 */
209 	void addObject(Object* existing, Object* object);
210 
211 	/**
212 	 * @copybrief ObjectModifyingUndoStep::getModifiedObjects
213 	 */
214 	void getModifiedObjects(int, ObjectSet&) const override;
215 
216 
217 public slots:
218 	/**
219 	 * Adapts the symbol pointers of objects referencing the changed symbol.
220 	 */
221 	virtual void symbolChanged(int pos, const OpenOrienteering::Symbol* new_symbol, const OpenOrienteering::Symbol* old_symbol);
222 
223 	/**
224 	 * Invalidates the undo step if a contained object references the deleted symbol.
225 	 */
226 	virtual void symbolDeleted(int pos, const OpenOrienteering::Symbol* old_symbol);
227 
228 protected:
229 	/**
230 	 * @copybrief UndoStep::saveImpl()
231 	 */
232 	void saveImpl(QXmlStreamWriter& xml) const override;
233 
234 	/**
235 	 * @copybrief UndoStep::loadImpl()
236 	 */
237 	void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict) override;
238 
239 	/**
240 	 * A list of object instance which are currently not part of the map.
241 	 */
242 	std::vector<Object*> objects;
243 
244 	/**
245 	 * A flag indicating whether this step is still valid.
246 	 */
247 	bool valid;
248 };
249 
250 
251 
252 /**
253  * Map undo step which replaces all affected objects by another set of objects.
254  */
255 class ReplaceObjectsUndoStep : public ObjectCreatingUndoStep
256 {
257 Q_OBJECT
258 public:
259 	ReplaceObjectsUndoStep(Map* map);
260 
261 	~ReplaceObjectsUndoStep() override;
262 
263 	UndoStep* undo() override;
264 
265 private:
266 	bool undone;
267 };
268 
269 /**
270  * Map undo step which deletes the referenced objects.
271  *
272  * Take care of correct application order when mixing with an add step to
273  * make sure that the object indices are preserved.
274  */
275 class DeleteObjectsUndoStep : public ObjectModifyingUndoStep
276 {
277 public:
278 	DeleteObjectsUndoStep(Map* map);
279 
280 	~DeleteObjectsUndoStep() override;
281 
282 	UndoStep* undo() override;
283 
284 	bool getModifiedParts(PartSet& out) const override;
285 
286 	void getModifiedObjects(int part_index, ObjectSet& out) const override;
287 };
288 
289 /**
290  * Map undo step which adds the contained objects.
291  *
292  * Take care of correct application order when mixing with a delete step to
293  * make sure that the object indices are preserved.
294  */
295 class AddObjectsUndoStep : public ObjectCreatingUndoStep
296 {
297 Q_OBJECT
298 public:
299 	AddObjectsUndoStep(Map* map);
300 
301 	~AddObjectsUndoStep() override;
302 
303 	UndoStep* undo() override;
304 
305 	/**
306 	 * Removes all contained objects from the map.
307 	 *
308 	 * This can be useful after constructing the undo step,
309 	 * as it is often impractical to remove the objects directly
310 	 * when adding them as the indexing would be changed this way.
311 	 */
312 	void removeContainedObjects(bool emit_selection_changed);
313 
314 protected:
315 	static bool sortOrder(const std::pair<int, int>& a, const std::pair<int, int>& b);
316 
317 private:
318 	bool undone;
319 };
320 
321 
322 
323 /**
324  * Map undo step which assigns the referenced objects to another part.
325  */
326 class SwitchPartUndoStep : public ObjectModifyingUndoStep
327 {
328 public:
329 	SwitchPartUndoStep(Map* map, int source_index, int target_index);
330 
331 	SwitchPartUndoStep(Map* map);
332 
333 	~SwitchPartUndoStep() override;
334 
335 	bool getModifiedParts(PartSet& out) const override;
336 
337 	void getModifiedObjects(int part_index, ObjectSet& out) const override;
338 
339 	UndoStep* undo() override;
340 
341 
342 protected:
343 	void saveImpl(QXmlStreamWriter& xml) const override;
344 
345 	void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict) override;
346 
347 	int source_index;
348 
349 	bool reverse = false;
350 };
351 
352 
353 
354 /**
355  * Map undo step which changes the symbols of referenced objects.
356  */
357 class SwitchSymbolUndoStep : public QObject, public ObjectModifyingUndoStep
358 {
359 Q_OBJECT
360 public:
361 	SwitchSymbolUndoStep(Map* map);
362 
363 	~SwitchSymbolUndoStep() override;
364 
365 	bool isValid() const override;
366 
367 	using ObjectModifyingUndoStep::addObject;
368 	virtual void addObject(int index, const Symbol* target_symbol);
369 
370 	UndoStep* undo() override;
371 
372 
373 public slots:
374 	virtual void symbolChanged(int pos, const OpenOrienteering::Symbol* new_symbol, const OpenOrienteering::Symbol* old_symbol);
375 
376 	virtual void symbolDeleted(int pos, const OpenOrienteering::Symbol* old_symbol);
377 
378 protected:
379 	void saveImpl(QXmlStreamWriter& xml) const override;
380 
381 	void loadImpl(QXmlStreamReader& xml, SymbolDictionary& symbol_dict) override;
382 
383 	std::vector<const Symbol*> target_symbols;
384 
385 	bool valid;
386 };
387 
388 
389 
390 /**
391  * Map undo step which reverses the directions of referenced objects,
392  *
393  * thereby switching the side of any line mid symbols (often dashes of fences).
394  */
395 class SwitchDashesUndoStep : public ObjectModifyingUndoStep
396 {
397 public:
398 	SwitchDashesUndoStep(Map* map);
399 
400 	~SwitchDashesUndoStep() override;
401 
402 	UndoStep* undo() override;
403 };
404 
405 
406 
407 /**
408  * Undo step which modifies object tags.
409  */
410 class ObjectTagsUndoStep : public ObjectModifyingUndoStep
411 {
412 public:
413 	ObjectTagsUndoStep(Map* map);
414 
415 	~ObjectTagsUndoStep() override;
416 
417 	void addObject(int index) override;
418 
419 	UndoStep* undo() override;
420 
421 protected:
422 	void saveObject(XmlElementWriter& xml, int index) const override;
423 
424 	void loadObject(XmlElementReader& xml, int index) override;
425 
426 	typedef std::map<int, Object::Tags> ObjectTagsMap;
427 
428 	ObjectTagsMap object_tags_map;
429 };
430 
431 
432 // ### ObjectModifyingUndoStep inline code ###
433 
434 inline
getPartIndex()435 int ObjectModifyingUndoStep::getPartIndex() const
436 {
437 	return part_index;
438 }
439 
440 
441 }  // namespace OpenOrienteering
442 
443 #endif
444