OpenCPN Partial API docs
Loading...
Searching...
No Matches
undo.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Framework for Undo features
5 * Author: Jesper Weissglas
6 *
7 ***************************************************************************
8 * Copyright (C) 2012 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 *
27 */
28
29#include "config.h"
30
31#include <wx/wxprec.h>
32
33#ifndef WX_PRECOMP
34#include <wx/wx.h>
35#endif
36
37#include <wx/file.h>
38#include <wx/datetime.h>
39#include <wx/clipbrd.h>
40
41#include "model/route.h"
42#include "model/routeman.h"
43#include "model/select.h"
44
45#include "chcanv.h"
46#include "MarkInfo.h"
47#include "navutil.h"
48#include "ocpn_frame.h"
49#include "routemanagerdialog.h"
50#include "styles.h"
51#include "undo.h"
52
53extern Routeman* g_pRouteMan;
54extern MyConfig* pConfig;
55extern MyFrame* gFrame;
56extern RouteManagerDialog* pRouteManagerDialog;
57extern MarkInfoDlg* g_pMarkInfoDialog;
58
59Undo::Undo(ChartCanvas* parent) {
60 m_parent = parent;
61 depthSetting = 10;
62 stackpointer = 0;
63 isInsideUndoableAction = false;
64 candidate = NULL;
65}
66
67Undo::~Undo() {
68 for (unsigned int i = 0; i < undoStack.size(); i++) {
69 if (undoStack[i]) {
70 delete undoStack[i];
71 undoStack[i] = NULL;
72 }
73 }
74 undoStack.clear();
75}
76
77wxString UndoAction::Description() {
78 wxString descr;
79 switch (type) {
80 case Undo_CreateWaypoint:
81 descr = _("Create Mark");
82 break;
83 case Undo_DeleteWaypoint:
84 descr = _("Delete Mark");
85 break;
86 case Undo_MoveWaypoint:
87 descr = _("Move Waypoint");
88 break;
89 case Undo_AppendWaypoint:
90 descr = _("Append Waypoint");
91 break;
92 default:
93 descr = _T("");
94 break;
95 }
96 return descr;
97}
98
99void doUndoMoveWaypoint(UndoAction* action, ChartCanvas* cc) {
100 double lat, lon;
101 RoutePoint* currentPoint = (RoutePoint*)action->after[0];
102 wxRealPoint* lastPoint = (wxRealPoint*)action->before[0];
103 lat = currentPoint->m_lat;
104 lon = currentPoint->m_lon;
105 currentPoint->m_lat = lastPoint->y;
106 currentPoint->m_lon = lastPoint->x;
107 lastPoint->y = lat;
108 lastPoint->x = lon;
109 SelectItem* selectable = (SelectItem*)action->selectable[0];
110 selectable->m_slat = currentPoint->m_lat;
111 selectable->m_slon = currentPoint->m_lon;
112
113 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
114 if (currentPoint == g_pMarkInfoDialog->GetRoutePoint())
115 g_pMarkInfoDialog->UpdateProperties(true);
116 }
117
118 wxArrayPtrVoid* routeArray =
119 g_pRouteMan->GetRouteArrayContaining(currentPoint);
120 if (routeArray) {
121 for (unsigned int ir = 0; ir < routeArray->GetCount(); ir++) {
122 Route* pr = (Route*)routeArray->Item(ir);
123 pr->FinalizeForRendering();
124 pr->UpdateSegmentDistances();
125 pConfig->UpdateRoute(pr);
126 }
127 delete routeArray;
128 }
129}
130
131void doUndoDeleteWaypoint(UndoAction* action, ChartCanvas* cc) {
132 RoutePoint* point = (RoutePoint*)action->before[0];
133 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
134 pConfig->AddNewWayPoint(point, -1);
135 // transfer ownership to WayPointman which eventually deletes it.
136 // This is certainly not how things should be and needs an overhaul.
137 if (NULL != pWayPointMan) pWayPointMan->AddRoutePoint(point);
138 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
139 pRouteManagerDialog->UpdateWptListCtrl();
140}
141
142void doRedoDeleteWaypoint(UndoAction* action, ChartCanvas* cc) {
143 RoutePoint* point = (RoutePoint*)action->before[0];
144 pConfig->DeleteWayPoint(point);
145 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
146 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
147 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
148 pRouteManagerDialog->UpdateWptListCtrl();
149}
150
151void doUndoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
152 RoutePoint* point = (RoutePoint*)action->before[0];
153 Route* route = (Route*)action->after[0];
154
155 bool noRouteLeftToRedo = false;
156 if ((route->GetnPoints() == 2) && (cc->m_routeState == 0))
157 noRouteLeftToRedo = true;
158
159 g_pRouteMan->RemovePointFromRoute(point, route, cc->m_routeState);
160 gFrame->InvalidateAllGL();
161
162 if (action->beforeType[0] == Undo_IsOrphanded) {
163 pConfig->DeleteWayPoint(point);
164 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
165 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
166 }
167
168 if (noRouteLeftToRedo) {
169 cc->undo->InvalidateRedo();
170 }
171
172 if (RouteManagerDialog::getInstanceFlag()) {
173 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
174 pRouteManagerDialog->UpdateWptListCtrl();
175 }
176
177 if (cc->m_routeState > 1) {
178 cc->m_routeState--;
179 cc->m_prev_pMousePoint = route->GetLastPoint();
180 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
181 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
182 route->m_lastMousePointIndex = route->GetnPoints();
183 }
184}
185
186void doRedoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
187 RoutePoint* point = (RoutePoint*)action->before[0];
188 Route* route = (Route*)action->after[0];
189
190 if (action->beforeType[0] == Undo_IsOrphanded) {
191 pConfig->AddNewWayPoint(point, -1);
192 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
193 }
194
195 RoutePoint* prevpoint = route->GetLastPoint();
196
197 route->AddPoint(point);
198 pSelect->AddSelectableRouteSegment(prevpoint->m_lat, prevpoint->m_lon,
199 point->m_lat, point->m_lon, prevpoint,
200 point, route);
201
202 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
203 pRouteManagerDialog->UpdateWptListCtrl();
204
205 if (cc->m_routeState > 1) {
206 cc->m_routeState++;
207 cc->m_prev_pMousePoint = route->GetLastPoint();
208 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
209 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
210 route->m_lastMousePointIndex = route->GetnPoints();
211 }
212}
213
214bool Undo::AnythingToUndo() { return undoStack.size() > stackpointer; }
215
216bool Undo::AnythingToRedo() { return stackpointer > 0; }
217
218UndoAction* Undo::GetNextUndoableAction() { return undoStack[stackpointer]; }
219
220UndoAction* Undo::GetNextRedoableAction() {
221 return undoStack[stackpointer - 1];
222}
223
224void Undo::InvalidateRedo() {
225 if (stackpointer == 0) return;
226
227 // Make sure we are not deleting any objects pointed to by
228 // potential redo actions.
229
230 for (unsigned int i = 0; i < stackpointer; i++) {
231 switch (undoStack[i]->type) {
232 case Undo_DeleteWaypoint:
233 undoStack[i]->before[0] = NULL;
234 break;
235 case Undo_CreateWaypoint:
236 case Undo_MoveWaypoint:
237 case Undo_AppendWaypoint:
238 break;
239 }
240 delete undoStack[i];
241 }
242
243 undoStack.erase(undoStack.begin(), undoStack.begin() + stackpointer);
244 stackpointer = 0;
245}
246
247void Undo::InvalidateUndo() {
248 undoStack.clear();
249 stackpointer = 0;
250}
251
252bool Undo::UndoLastAction() {
253 if (!AnythingToUndo()) return false;
254 UndoAction* action = GetNextUndoableAction();
255
256 switch (action->type) {
257 case Undo_CreateWaypoint:
258 doRedoDeleteWaypoint(action,
259 GetParent()); // Same as delete but reversed.
260 stackpointer++;
261 break;
262
263 case Undo_MoveWaypoint:
264 doUndoMoveWaypoint(action, GetParent());
265 stackpointer++;
266 break;
267
268 case Undo_DeleteWaypoint:
269 doUndoDeleteWaypoint(action, GetParent());
270 stackpointer++;
271 break;
272
273 case Undo_AppendWaypoint:
274 stackpointer++;
275 doUndoAppendWaypoint(action, GetParent());
276 break;
277 }
278 return true;
279}
280
281bool Undo::RedoNextAction() {
282 if (!AnythingToRedo()) return false;
283 UndoAction* action = GetNextRedoableAction();
284
285 switch (action->type) {
286 case Undo_CreateWaypoint:
287 doUndoDeleteWaypoint(action,
288 GetParent()); // Same as delete but reversed.
289 stackpointer--;
290 break;
291
292 case Undo_MoveWaypoint:
293 doUndoMoveWaypoint(
294 action,
295 GetParent()); // For Wpt move, redo is same as undo (swap lat/long);
296 stackpointer--;
297 break;
298
299 case Undo_DeleteWaypoint:
300 doRedoDeleteWaypoint(action, GetParent());
301 stackpointer--;
302 break;
303
304 case Undo_AppendWaypoint:
305 doRedoAppendWaypoint(action, GetParent());
306 stackpointer--;
307 break;
308 }
309 return true;
310}
311
312bool Undo::BeforeUndoableAction(UndoType type, UndoItemPointer before,
313 UndoBeforePointerType beforeType,
314 UndoItemPointer selectable) {
315 if (CancelUndoableAction()) return false;
316 ;
317 InvalidateRedo();
318
319 candidate = new UndoAction;
320 candidate->before.clear();
321 candidate->beforeType.clear();
322 candidate->selectable.clear();
323 candidate->after.clear();
324
325 candidate->type = type;
326 UndoItemPointer subject = before;
327
328 switch (beforeType) {
329 case Undo_NeedsCopy: {
330 switch (candidate->type) {
331 case Undo_MoveWaypoint: {
332 wxRealPoint* point = new wxRealPoint;
333 RoutePoint* rp = (RoutePoint*)before;
334 point->x = rp->m_lon;
335 point->y = rp->m_lat;
336 subject = point;
337 break;
338 }
339 case Undo_CreateWaypoint:
340 break;
341 case Undo_DeleteWaypoint:
342 break;
343 case Undo_AppendWaypoint:
344 break;
345 }
346 break;
347 }
348 case Undo_IsOrphanded:
349 break;
350 case Undo_HasParent:
351 break;
352 }
353
354 candidate->before.push_back(subject);
355 candidate->beforeType.push_back(beforeType);
356 candidate->selectable.push_back(selectable);
357
358 isInsideUndoableAction = true;
359 return true;
360}
361
362bool Undo::AfterUndoableAction(UndoItemPointer after) {
363 if (!isInsideUndoableAction) return false;
364
365 candidate->after.push_back(after);
366 undoStack.push_front(candidate);
367
368 if (undoStack.size() > depthSetting) {
369 undoStack.pop_back();
370 }
371
372 isInsideUndoableAction = false;
373 return true;
374}
375
376bool Undo::CancelUndoableAction(bool noDataDelete) {
377 if (isInsideUndoableAction) {
378 if (noDataDelete) {
379 for (unsigned int i = 0; i < candidate->beforeType.size(); i++) {
380 if (candidate->beforeType[i] == Undo_IsOrphanded) {
381 candidate->beforeType[i] = Undo_HasParent;
382 }
383 }
384 }
385 if (candidate) delete candidate;
386 candidate = NULL;
387 isInsideUndoableAction = false;
388 return true;
389 }
390 return false;
391}
392
393//-----------------------------------------------------------------------------------
394
395UndoAction::~UndoAction() {
396 assert(before.size() == beforeType.size());
397
398 for (unsigned int i = 0; i < before.size(); i++) {
399 switch (beforeType[i]) {
400 case Undo_NeedsCopy: {
401 switch (type) {
402 case Undo_MoveWaypoint:
403 if (before[i]) {
404 delete (wxRealPoint*)before[i];
405 before[i] = NULL;
406 }
407 break;
408 case Undo_DeleteWaypoint:
409 break;
410 case Undo_CreateWaypoint:
411 break;
412 case Undo_AppendWaypoint:
413 break;
414 }
415 break;
416 }
417 case Undo_IsOrphanded: {
418 switch (type) {
419 case Undo_DeleteWaypoint:
420 if (before[i]) {
421 delete (RoutePoint*)before[i];
422 }
423 break;
424 case Undo_CreateWaypoint:
425 break;
426 case Undo_MoveWaypoint:
427 break;
428 case Undo_AppendWaypoint:
429 if (before[i]) {
430 delete (RoutePoint*)before[i];
431 before[i] = NULL;
432 }
433 break;
434 }
435 break;
436 }
437 case Undo_HasParent:
438 break;
439 }
440 }
441 before.clear();
442}
Chart display canvas.
Definition chcanv.h:135
Dialog for displaying and editing waypoint properties.
Definition MarkInfo.h:212
Main application frame.
Definition ocpn_frame.h:136
Definition route.h:75
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.