OpenCPN Partial API docs
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 
53 extern Routeman* g_pRouteMan;
54 extern MyConfig* pConfig;
55 extern MyFrame* gFrame;
56 extern RouteManagerDialog* pRouteManagerDialog;
57 extern MarkInfoDlg* g_pMarkInfoDialog;
58 
59 Undo::Undo(ChartCanvas* parent) {
60  m_parent = parent;
61  depthSetting = 10;
62  stackpointer = 0;
63  isInsideUndoableAction = false;
64  candidate = NULL;
65 }
66 
67 Undo::~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 
77 wxString 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 
99 void 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 
131 void 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 
140 void 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 
149 void 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 
184 void 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 
212 bool Undo::AnythingToUndo() { return undoStack.size() > stackpointer; }
213 
214 bool Undo::AnythingToRedo() { return stackpointer > 0; }
215 
216 UndoAction* Undo::GetNextUndoableAction() { return undoStack[stackpointer]; }
217 
218 UndoAction* Undo::GetNextRedoableAction() {
219  return undoStack[stackpointer - 1];
220 }
221 
222 void 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 
245 void Undo::InvalidateUndo() {
246  undoStack.clear();
247  stackpointer = 0;
248 }
249 
250 bool 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 
279 bool 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 
310 bool 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 
360 bool 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 
374 bool 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 
393 UndoAction::~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:203
Definition: route.h:75