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