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 "navutil.h"
42#include "styles.h"
43#include "routeman.h"
44#include "MarkInfo.h"
45#include "routemanagerdialog.h"
46#include "undo.h"
47#include "chcanv.h"
48#include "ocpn_frame.h"
49#include "route.h"
50
51extern Routeman* g_pRouteMan;
52extern MyConfig* pConfig;
53extern MyFrame* gFrame;
54extern Select* pSelect;
55extern RouteManagerDialog* pRouteManagerDialog;
56extern WayPointman* pWayPointMan;
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 Waypoint");
82 break;
83 case Undo_DeleteWaypoint:
84 descr = _("Delete Waypoint");
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 if (NULL != pWayPointMan) pWayPointMan->AddRoutePoint(point);
136 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
137 pRouteManagerDialog->UpdateWptListCtrl();
138}
139
140void doRedoDeleteWaypoint(UndoAction* action, ChartCanvas* cc) {
141 RoutePoint* point = (RoutePoint*)action->before[0];
142 pConfig->DeleteWayPoint(point);
143 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
144 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
145 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
146 pRouteManagerDialog->UpdateWptListCtrl();
147}
148
149void doUndoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
150 RoutePoint* point = (RoutePoint*)action->before[0];
151 Route* route = (Route*)action->after[0];
152
153 bool noRouteLeftToRedo = false;
154 if ((route->GetnPoints() == 2) && (cc->m_routeState == 0))
155 noRouteLeftToRedo = true;
156
157 g_pRouteMan->RemovePointFromRoute(point, route, cc->m_routeState);
158 gFrame->InvalidateAllGL();
159
160 if (action->beforeType[0] == Undo_IsOrphanded) {
161 pConfig->DeleteWayPoint(point);
162 pSelect->DeleteSelectablePoint(point, SELTYPE_ROUTEPOINT);
163 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(point);
164 }
165
166 if (noRouteLeftToRedo) {
167 cc->undo->InvalidateRedo();
168 }
169
170 if(RouteManagerDialog::getInstanceFlag()){
171 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
172 pRouteManagerDialog->UpdateWptListCtrl();
173 }
174
175 if (cc->m_routeState > 1) {
176 cc->m_routeState--;
177 cc->m_prev_pMousePoint = route->GetLastPoint();
178 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
179 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
180 route->m_lastMousePointIndex = route->GetnPoints();
181 }
182}
183
184void doRedoAppendWaypoint(UndoAction* action, ChartCanvas* cc) {
185 RoutePoint* point = (RoutePoint*)action->before[0];
186 Route* route = (Route*)action->after[0];
187
188 if (action->beforeType[0] == Undo_IsOrphanded) {
189 pConfig->AddNewWayPoint(point, -1);
190 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
191 }
192
193 RoutePoint* prevpoint = route->GetLastPoint();
194
195 route->AddPoint(point);
196 pSelect->AddSelectableRouteSegment(prevpoint->m_lat, prevpoint->m_lon,
197 point->m_lat, point->m_lon, prevpoint,
198 point, route);
199
200 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
201 pRouteManagerDialog->UpdateWptListCtrl();
202
203 if (cc->m_routeState > 1) {
204 cc->m_routeState++;
205 cc->m_prev_pMousePoint = route->GetLastPoint();
206 cc->m_prev_rlat = cc->m_prev_pMousePoint->m_lat;
207 cc->m_prev_rlon = cc->m_prev_pMousePoint->m_lon;
208 route->m_lastMousePointIndex = route->GetnPoints();
209 }
210}
211
212bool Undo::AnythingToUndo() { return undoStack.size() > stackpointer; }
213
214bool Undo::AnythingToRedo() { return stackpointer > 0; }
215
216UndoAction* Undo::GetNextUndoableAction() { return undoStack[stackpointer]; }
217
218UndoAction* Undo::GetNextRedoableAction() {
219 return undoStack[stackpointer - 1];
220}
221
222void Undo::InvalidateRedo() {
223 if (stackpointer == 0) return;
224
225 // Make sure we are not deleting any objects pointed to by
226 // potential redo actions.
227
228 for (unsigned int i = 0; i < stackpointer; i++) {
229 switch (undoStack[i]->type) {
230 case Undo_DeleteWaypoint:
231 undoStack[i]->before[0] = NULL;
232 break;
233 case Undo_CreateWaypoint:
234 case Undo_MoveWaypoint:
235 case Undo_AppendWaypoint:
236 break;
237 }
238 delete undoStack[i];
239 }
240
241 undoStack.erase(undoStack.begin(), undoStack.begin() + stackpointer);
242 stackpointer = 0;
243}
244
245void Undo::InvalidateUndo() {
246 undoStack.clear();
247 stackpointer = 0;
248}
249
250bool Undo::UndoLastAction() {
251 if (!AnythingToUndo()) return false;
252 UndoAction* action = GetNextUndoableAction();
253
254 switch (action->type) {
255 case Undo_CreateWaypoint:
256 doRedoDeleteWaypoint(action,
257 GetParent()); // Same as delete but reversed.
258 stackpointer++;
259 break;
260
261 case Undo_MoveWaypoint:
262 doUndoMoveWaypoint(action, GetParent());
263 stackpointer++;
264 break;
265
266 case Undo_DeleteWaypoint:
267 doUndoDeleteWaypoint(action, GetParent());
268 stackpointer++;
269 break;
270
271 case Undo_AppendWaypoint:
272 stackpointer++;
273 doUndoAppendWaypoint(action, GetParent());
274 break;
275 }
276 return true;
277}
278
279bool Undo::RedoNextAction() {
280 if (!AnythingToRedo()) return false;
281 UndoAction* action = GetNextRedoableAction();
282
283 switch (action->type) {
284 case Undo_CreateWaypoint:
285 doUndoDeleteWaypoint(action,
286 GetParent()); // Same as delete but reversed.
287 stackpointer--;
288 break;
289
290 case Undo_MoveWaypoint:
291 doUndoMoveWaypoint(
292 action,
293 GetParent()); // For Wpt move, redo is same as undo (swap lat/long);
294 stackpointer--;
295 break;
296
297 case Undo_DeleteWaypoint:
298 doRedoDeleteWaypoint(action, GetParent());
299 stackpointer--;
300 break;
301
302 case Undo_AppendWaypoint:
303 doRedoAppendWaypoint(action, GetParent());
304 stackpointer--;
305 break;
306 }
307 return true;
308}
309
310bool Undo::BeforeUndoableAction(UndoType type, UndoItemPointer before,
311 UndoBeforePointerType beforeType,
312 UndoItemPointer selectable) {
313 if (CancelUndoableAction()) return false;
314 ;
315 InvalidateRedo();
316
317 candidate = new UndoAction;
318 candidate->before.clear();
319 candidate->beforeType.clear();
320 candidate->selectable.clear();
321 candidate->after.clear();
322
323 candidate->type = type;
324 UndoItemPointer subject = before;
325
326 switch (beforeType) {
327 case Undo_NeedsCopy: {
328 switch (candidate->type) {
329 case Undo_MoveWaypoint: {
330 wxRealPoint* point = new wxRealPoint;
331 RoutePoint* rp = (RoutePoint*)before;
332 point->x = rp->m_lon;
333 point->y = rp->m_lat;
334 subject = point;
335 break;
336 }
337 case Undo_CreateWaypoint:
338 break;
339 case Undo_DeleteWaypoint:
340 break;
341 case Undo_AppendWaypoint:
342 break;
343 }
344 break;
345 }
346 case Undo_IsOrphanded:
347 break;
348 case Undo_HasParent:
349 break;
350 }
351
352 candidate->before.push_back(subject);
353 candidate->beforeType.push_back(beforeType);
354 candidate->selectable.push_back(selectable);
355
356 isInsideUndoableAction = true;
357 return true;
358}
359
360bool Undo::AfterUndoableAction(UndoItemPointer after) {
361 if (!isInsideUndoableAction) return false;
362
363 candidate->after.push_back(after);
364 undoStack.push_front(candidate);
365
366 if (undoStack.size() > depthSetting) {
367 undoStack.pop_back();
368 }
369
370 isInsideUndoableAction = false;
371 return true;
372}
373
374bool Undo::CancelUndoableAction(bool noDataDelete) {
375 if (isInsideUndoableAction) {
376 if (noDataDelete) {
377 for (unsigned int i = 0; i < candidate->beforeType.size(); i++) {
378 if (candidate->beforeType[i] == Undo_IsOrphanded) {
379 candidate->beforeType[i] = Undo_HasParent;
380 }
381 }
382 }
383 if (candidate) delete candidate;
384 candidate = NULL;
385 isInsideUndoableAction = false;
386 return true;
387 }
388 return false;
389}
390
391//-----------------------------------------------------------------------------------
392
393UndoAction::~UndoAction() {
394 assert(before.size() == beforeType.size());
395
396 for (unsigned int i = 0; i < before.size(); i++) {
397 switch (beforeType[i]) {
398 case Undo_NeedsCopy: {
399 switch (type) {
400 case Undo_MoveWaypoint:
401 if (before[i]) {
402 delete (wxRealPoint*)before[i];
403 before[i] = NULL;
404 }
405 break;
406 case Undo_DeleteWaypoint:
407 break;
408 case Undo_CreateWaypoint:
409 break;
410 case Undo_AppendWaypoint:
411 break;
412 }
413 break;
414 }
415 case Undo_IsOrphanded: {
416 switch (type) {
417 case Undo_DeleteWaypoint:
418 if (before[i]) {
419 delete (RoutePoint*)before[i];
420 }
421 break;
422 case Undo_CreateWaypoint:
423 break;
424 case Undo_MoveWaypoint:
425 break;
426 case Undo_AppendWaypoint:
427 if (before[i]) {
428 delete (RoutePoint*)before[i];
429 before[i] = NULL;
430 }
431 break;
432 }
433 break;
434 }
435 case Undo_HasParent:
436 break;
437 }
438 }
439 before.clear();
440}
Class MarkInfoDef.
Definition: MarkInfo.h:197
Definition: route.h:70
Definition: select.h:51