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