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