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#include "gl_headers.h" // Must be included before anything using GL stuff
26
27#include <wx/wxprec.h>
28#ifndef WX_PRECOMP
29#include <wx/wx.h>
30#endif
31
32#include <wx/clipbrd.h>
33#include <wx/dynarray.h>
34#include <wx/gdicmn.h>
35
36#include "model/navobj_db.h"
37#include "model/route.h"
38#include "model/routeman.h"
39#include "model/select.h"
40
41#include "chcanv.h"
42#include "mark_info.h"
43#include "navutil.h"
44#include "ocpn_frame.h"
45#include "routemanagerdialog.h"
46#include "styles.h"
47#include "undo.h"
48
49Undo::Undo(ChartCanvas* parent) {
50 m_parent = parent;
51 depthSetting = 10;
52 stackpointer = 0;
53 isInsideUndoableAction = false;
54 candidate = NULL;
55}
56
57Undo::~Undo() {
58 for (unsigned int i = 0; i < undoStack.size(); i++) {
59 if (undoStack[i]) {
60 delete undoStack[i];
61 undoStack[i] = NULL;
62 }
63 }
64 undoStack.clear();
65}
66
67wxString UndoAction::Description() {
68 wxString descr;
69 switch (type) {
70 case Undo_CreateWaypoint:
71 descr = _("Create Mark");
72 break;
73 case Undo_DeleteWaypoint:
74 descr = _("Delete Mark");
75 break;
76 case Undo_MoveWaypoint:
77 descr = _("Move Waypoint");
78 break;
79 case Undo_AppendWaypoint:
80 descr = _("Append Waypoint");
81 break;
82 default:
83 descr = "";
84 break;
85 }
86 return descr;
87}
88
89void doUndoMoveWaypoint(UndoAction* action, ChartCanvas* cc) {
90 double lat, lon;
91 RoutePoint* currentPoint = (RoutePoint*)action->after[0];
92 wxRealPoint* lastPoint = (wxRealPoint*)action->before[0];
93 lat = currentPoint->m_lat;
94 lon = currentPoint->m_lon;
95 currentPoint->m_lat = lastPoint->y;
96 currentPoint->m_lon = lastPoint->x;
97 lastPoint->y = lat;
98 lastPoint->x = lon;
99 SelectItem* selectable = (SelectItem*)action->selectable[0];
100 selectable->m_slat = currentPoint->m_lat;
101 selectable->m_slon = currentPoint->m_lon;
102
103 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
104 if (currentPoint == g_pMarkInfoDialog->GetRoutePoint())
105 g_pMarkInfoDialog->UpdateProperties(true);
106 }
107
108 wxArrayPtrVoid* routeArray =
110 if (routeArray) {
111 for (unsigned int ir = 0; ir < routeArray->GetCount(); ir++) {
112 Route* pr = (Route*)routeArray->Item(ir);
113 pr->FinalizeForRendering();
114 pr->UpdateSegmentDistances();
115 NavObj_dB::GetInstance().UpdateRoute(pr);
116 }
117 delete routeArray;
118 }
119}
120
121void doUndoDeleteWaypoint(UndoAction* action, ChartCanvas* cc) {
122 RoutePoint* point = (RoutePoint*)action->before[0];
123 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
124 NavObj_dB::GetInstance().InsertRoutePoint(point);
125
126 // transfer ownership to WayPointman which eventually deletes it.
127 // This is certainly not how things should be and needs an overhaul.
128 if (NULL != pWayPointMan) pWayPointMan->AddRoutePoint(point);
129 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
130 pRouteManagerDialog->UpdateWptListCtrl();
131}
132
133void doRedoDeleteWaypoint(UndoAction* action, ChartCanvas* cc) {
134 RoutePoint* point = (RoutePoint*)action->before[0];
135 NavObj_dB::GetInstance().DeleteRoutePoint(point);
136 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
137 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
138 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
139 pRouteManagerDialog->UpdateWptListCtrl();
140}
141
142void doUndoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
143 RoutePoint* point = (RoutePoint*)action->before[0];
144 Route* route = (Route*)action->after[0];
145
146 bool noRouteLeftToRedo = false;
147 if ((route->GetnPoints() == 2) && (cc->m_routeState == 0))
148 noRouteLeftToRedo = true;
149
150 g_pRouteMan->RemovePointFromRoute(point, route, cc->m_routeState);
151 gFrame->InvalidateAllGL();
152
153 if (action->beforeType[0] == Undo_IsOrphanded) {
154 NavObj_dB::GetInstance().DeleteRoutePoint(point);
155 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
156 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
157 }
158
159 if (noRouteLeftToRedo) {
160 cc->undo->InvalidateRedo();
161 }
162
163 if (RouteManagerDialog::getInstanceFlag()) {
164 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
165 pRouteManagerDialog->UpdateWptListCtrl();
166 }
167
168 if (cc->m_routeState > 1) {
169 cc->m_routeState--;
170 cc->m_prev_pMousePoint = route->GetLastPoint();
171 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
172 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
173 route->m_lastMousePointIndex = route->GetnPoints();
174 }
175}
176
177void doRedoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
178 RoutePoint* point = (RoutePoint*)action->before[0];
179 Route* route = (Route*)action->after[0];
180
181 if (action->beforeType[0] == Undo_IsOrphanded) {
182 NavObj_dB::GetInstance().InsertRoutePoint(point);
183 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
184 }
185
186 RoutePoint* prevpoint = route->GetLastPoint();
187
188 route->AddPoint(point);
189 pSelect->AddSelectableRouteSegment(prevpoint->m_lat, prevpoint->m_lon,
190 point->m_lat, point->m_lon, prevpoint,
191 point, route);
192
193 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
194 pRouteManagerDialog->UpdateWptListCtrl();
195
196 if (cc->m_routeState > 1) {
197 cc->m_routeState++;
198 cc->m_prev_pMousePoint = route->GetLastPoint();
199 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
200 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
201 route->m_lastMousePointIndex = route->GetnPoints();
202 }
203}
204
205bool Undo::AnythingToUndo() { return undoStack.size() > stackpointer; }
206
207bool Undo::AnythingToRedo() { return stackpointer > 0; }
208
209UndoAction* Undo::GetNextUndoableAction() { return undoStack[stackpointer]; }
210
211UndoAction* Undo::GetNextRedoableAction() {
212 return undoStack[stackpointer - 1];
213}
214
215void Undo::InvalidateRedo() {
216 if (stackpointer == 0) return;
217
218 // Make sure we are not deleting any objects pointed to by
219 // potential redo actions.
220
221 for (unsigned int i = 0; i < stackpointer; i++) {
222 switch (undoStack[i]->type) {
223 case Undo_DeleteWaypoint:
224 undoStack[i]->before[0] = NULL;
225 break;
226 case Undo_CreateWaypoint:
227 case Undo_MoveWaypoint:
228 case Undo_AppendWaypoint:
229 break;
230 }
231 delete undoStack[i];
232 }
233
234 undoStack.erase(undoStack.begin(), undoStack.begin() + stackpointer);
235 stackpointer = 0;
236}
237
238void Undo::InvalidateUndo() {
239 undoStack.clear();
240 stackpointer = 0;
241}
242
243bool Undo::UndoLastAction() {
244 if (!AnythingToUndo()) return false;
245 UndoAction* action = GetNextUndoableAction();
246
247 switch (action->type) {
248 case Undo_CreateWaypoint:
249 doRedoDeleteWaypoint(action,
250 GetParent()); // Same as delete but reversed.
251 stackpointer++;
252 break;
253
254 case Undo_MoveWaypoint:
255 doUndoMoveWaypoint(action, GetParent());
256 stackpointer++;
257 break;
258
259 case Undo_DeleteWaypoint:
260 doUndoDeleteWaypoint(action, GetParent());
261 stackpointer++;
262 break;
263
264 case Undo_AppendWaypoint:
265 stackpointer++;
266 doUndoAppendWaypoint(action, GetParent());
267 break;
268 }
269 return true;
270}
271
272bool Undo::RedoNextAction() {
273 if (!AnythingToRedo()) return false;
274 UndoAction* action = GetNextRedoableAction();
275
276 switch (action->type) {
277 case Undo_CreateWaypoint:
278 doUndoDeleteWaypoint(action,
279 GetParent()); // Same as delete but reversed.
280 stackpointer--;
281 break;
282
283 case Undo_MoveWaypoint:
284 doUndoMoveWaypoint(
285 action,
286 GetParent()); // For Wpt move, redo is same as undo (swap lat/long);
287 stackpointer--;
288 break;
289
290 case Undo_DeleteWaypoint:
291 doRedoDeleteWaypoint(action, GetParent());
292 stackpointer--;
293 break;
294
295 case Undo_AppendWaypoint:
296 doRedoAppendWaypoint(action, GetParent());
297 stackpointer--;
298 break;
299 }
300 return true;
301}
302
303bool Undo::BeforeUndoableAction(UndoType type, UndoItemPointer before,
304 UndoBeforePointerType beforeType,
305 UndoItemPointer selectable) {
306 if (CancelUndoableAction()) return false;
307 ;
308 InvalidateRedo();
309
310 candidate = new UndoAction;
311 candidate->before.clear();
312 candidate->beforeType.clear();
313 candidate->selectable.clear();
314 candidate->after.clear();
315
316 candidate->type = type;
317 UndoItemPointer subject = before;
318
319 switch (beforeType) {
320 case Undo_NeedsCopy: {
321 switch (candidate->type) {
322 case Undo_MoveWaypoint: {
323 wxRealPoint* point = new wxRealPoint;
324 RoutePoint* rp = (RoutePoint*)before;
325 point->x = rp->m_lon;
326 point->y = rp->m_lat;
327 subject = point;
328 break;
329 }
330 case Undo_CreateWaypoint:
331 break;
332 case Undo_DeleteWaypoint:
333 break;
334 case Undo_AppendWaypoint:
335 break;
336 }
337 break;
338 }
339 case Undo_IsOrphanded:
340 break;
341 case Undo_HasParent:
342 break;
343 }
344
345 candidate->before.push_back(subject);
346 candidate->beforeType.push_back(beforeType);
347 candidate->selectable.push_back(selectable);
348
349 isInsideUndoableAction = true;
350 return true;
351}
352
353bool Undo::AfterUndoableAction(UndoItemPointer after) {
354 if (!isInsideUndoableAction) return false;
355
356 candidate->after.push_back(after);
357 undoStack.push_front(candidate);
358
359 if (undoStack.size() > depthSetting) {
360 undoStack.pop_back();
361 }
362
363 isInsideUndoableAction = false;
364 return true;
365}
366
367bool Undo::CancelUndoableAction(bool noDataDelete) {
368 if (isInsideUndoableAction) {
369 if (noDataDelete) {
370 for (unsigned int i = 0; i < candidate->beforeType.size(); i++) {
371 if (candidate->beforeType[i] == Undo_IsOrphanded) {
372 candidate->beforeType[i] = Undo_HasParent;
373 }
374 }
375 }
376 if (candidate) delete candidate;
377 candidate = NULL;
378 isInsideUndoableAction = false;
379 return true;
380 }
381 return false;
382}
383
384//-----------------------------------------------------------------------------------
385
386UndoAction::~UndoAction() {
387 assert(before.size() == beforeType.size());
388
389 for (unsigned int i = 0; i < before.size(); i++) {
390 switch (beforeType[i]) {
391 case Undo_NeedsCopy: {
392 switch (type) {
393 case Undo_MoveWaypoint:
394 if (before[i]) {
395 delete (wxRealPoint*)before[i];
396 before[i] = NULL;
397 }
398 break;
399 case Undo_DeleteWaypoint:
400 break;
401 case Undo_CreateWaypoint:
402 break;
403 case Undo_AppendWaypoint:
404 break;
405 }
406 break;
407 }
408 case Undo_IsOrphanded: {
409 switch (type) {
410 case Undo_DeleteWaypoint:
411 if (before[i]) {
412 delete (RoutePoint*)before[i];
413 }
414 break;
415 case Undo_CreateWaypoint:
416 break;
417 case Undo_MoveWaypoint:
418 break;
419 case Undo_AppendWaypoint:
420 if (before[i]) {
421 delete (RoutePoint*)before[i];
422 before[i] = NULL;
423 }
424 break;
425 }
426 break;
427 }
428 case Undo_HasParent:
429 break;
430 }
431 }
432 before.clear();
433}
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.
Platform independent GL includes.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Definition mark_info.cpp:77
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.