OpenCPN Partial API docs
routemanagerdialog.cpp
1 /*
2  This program is free software; you can redistribute it and/or
3  modify it under the terms of the GNU General Public License
4  as published by the Free Software Foundation; either version 2
5  of the License, or (at your option) any later version.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor,
15  Boston, MA 02110-1301, USA.
16 
17  ---
18  Copyright (C) 2010, Anders Lund <anders@alweb.dk>
19  */
20 
21 #include "config.h"
22 
23 #include "routemanagerdialog.h"
24 
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include <wx/wxprec.h>
27 
28 #ifndef WX_PRECOMP
29 #include <wx/wx.h>
30 #endif
31 
32 #include <wx/filename.h>
33 #include <wx/stdpaths.h>
34 #include <wx/progdlg.h>
35 #include <wx/clipbrd.h>
36 #include <wx/statline.h>
37 
38 #include <iostream>
39 #include <vector>
40 #include <algorithm>
41 
42 #include "model/ais_decoder.h"
43 #include "model/config_vars.h"
44 #include "model/georef.h"
45 #include "model/mdns_cache.h"
46 #include "model/mDNS_query.h"
47 #include "model/navutil_base.h"
48 #include "model/own_ship.h"
49 #include "model/route.h"
50 #include "model/routeman.h"
51 #include "model/select.h"
52 #include "model/track.h"
53 
54 #include "chartbase.h"
55 #include "chcanv.h"
56 #include "dychart.h"
57 #include "Layer.h"
58 #include "MarkInfo.h"
59 #include "navutil.h"
60 #include "ocpn_frame.h"
61 #include "OCPNPlatform.h"
62 #include "routeman_gui.h"
63 #include "route_point_gui.h"
64 #include "RoutePropDlgImpl.h"
65 #include "SendToGpsDlg.h"
66 #include "SendToPeerDlg.h"
67 #include "styles.h"
68 #include "svg_utils.h"
69 #include "TrackPropDlg.h"
70 
71 #ifdef __ANDROID__
72 #include "androidUTIL.h"
73 #endif
74 
75 #define DIALOG_MARGIN 10
76 
77 enum { rmVISIBLE = 0, rmROUTENAME, rmROUTEDESC }; // RMColumns;
78 enum { colTRKVISIBLE = 0, colTRKNAME, colTRKLENGTH, colTRKDATE };
79 enum { colLAYVISIBLE = 0, colLAYNAME, colLAYITEMS, colLAYPERSIST };
80 enum { colWPTICON = 0, colWPTSCALE, colWPTNAME, colWPTDIST };
81 
82 // GLOBALS :0
83 extern RouteList *pRouteList;
84 extern std::vector<Track*> g_TrackList;
85 extern LayerList *pLayerList;
86 extern wxString GetLayerName(int id);
87 extern RoutePropDlgImpl *pRoutePropDialog;
88 extern TrackPropDlg *pTrackPropDialog;
89 extern Routeman *g_pRouteMan;
90 extern MyConfig *pConfig;
91 extern ActiveTrack *g_pActiveTrack;
92 extern MarkInfoDlg *g_pMarkInfoDialog;
93 extern MyFrame *gFrame;
94 extern bool g_bShowLayers;
95 extern wxString g_default_wp_icon;
96 extern OCPNPlatform *g_Platform;
97 
98 // Helper for conditional file name separator
99 void appendOSDirSlash(wxString *pString);
100 
101 static int SortRouteTrack(const int order, const wxString &it1,
102  const wxString &it2) {
103  if (order & 1) return it2.CmpNoCase(it1);
104 
105  return it1.CmpNoCase(it2);
106 }
107 
108 // sort callback. Sort by route name.
109 static int sort_route_name_dir;
110 #if wxCHECK_VERSION(2, 9, 0)
111 static int wxCALLBACK SortRoutesOnName(wxIntPtr item1, wxIntPtr item2,
112  wxIntPtr list)
113 #else
114 int wxCALLBACK SortRoutesOnName(long item1, long item2, long list)
115 #endif
116 {
117  return SortRouteTrack(sort_route_name_dir, ((Route *)item1)->GetName(),
118  ((Route *)item2)->GetName());
119 }
120 
121 // sort callback. Sort by route Destination.
122 static int sort_route_to_dir;
123 #if wxCHECK_VERSION(2, 9, 0)
124 static int wxCALLBACK SortRoutesOnTo(wxIntPtr item1, wxIntPtr item2,
125  wxIntPtr list)
126 #else
127 int wxCALLBACK SortRoutesOnTo(long item1, long item2, long list)
128 #endif
129 {
130  return SortRouteTrack(sort_route_to_dir, ((Route *)item1)->GetTo(),
131  ((Route *)item2)->GetTo());
132 }
133 
134 // sort callback. Sort by track name.
135 static int sort_track_name_dir;
136 #if wxCHECK_VERSION(2, 9, 0)
137 static int wxCALLBACK SortTracksOnName(wxIntPtr item1, wxIntPtr item2,
138  wxIntPtr list)
139 #else
140 int wxCALLBACK SortTracksOnName(long item1, long item2, long list)
141 #endif
142 {
143  return SortRouteTrack(sort_track_name_dir, ((Track *)item1)->GetName(),
144  ((Track *)item2)->GetName());
145 }
146 
147 static int SortDouble(const int order, const double &it1, const double &it2) {
148  double l1;
149  double l2;
150 
151  if (order & 1) {
152  l1 = it2;
153  l2 = it1;
154  } else {
155  l1 = it1;
156  l2 = it2;
157  }
158 
159  if (l1 == l2) return 0;
160  if (l2 < l1) return 1;
161  return -1;
162 }
163 
164 // sort callback. Sort by track length.
165 static int sort_track_len_dir;
166 #if wxCHECK_VERSION(2, 9, 0)
167 static int wxCALLBACK SortTracksOnDistance(wxIntPtr item1, wxIntPtr item2,
168  wxIntPtr list)
169 #else
170 int wxCALLBACK SortTracksOnDistance(long item1, long item2, long list)
171 #endif
172 {
173  return SortDouble(sort_track_len_dir, ((Track *)item1)->Length(),
174  ((Track *)item2)->Length());
175 }
176 
177 // sort callback. Sort by track start date.
178 static int sort_track_date_dir;
179 #if wxCHECK_VERSION(2, 9, 0)
180 static int wxCALLBACK SortTracksOnDate(wxIntPtr item1, wxIntPtr item2,
181  wxIntPtr list)
182 #else
183 int wxCALLBACK SortTracksOnDate(long item1, long item2, long list)
184 #endif
185 {
186  return SortRouteTrack(sort_track_date_dir, ((Track *)item1)->GetDate(),
187  ((Track *)item2)->GetDate());
188 }
189 
190 static int sort_wp_key;
191 static int sort_track_key;
192 
193 // sort callback. Sort by wpt name.
194 static int sort_wp_name_dir;
195 #if wxCHECK_VERSION(2, 9, 0)
196 static int wxCALLBACK SortWaypointsOnName(wxIntPtr item1, wxIntPtr item2,
197  wxIntPtr list)
198 #else
199 int wxCALLBACK SortWaypointsOnName(long item1, long item2, long list)
200 #endif
201 
202 {
203  RoutePoint *pRP1 = (RoutePoint *)item1;
204  RoutePoint *pRP2 = (RoutePoint *)item2;
205 
206  if (pRP1 && pRP2) {
207  if (sort_wp_name_dir & 1)
208  return pRP2->GetName().CmpNoCase(pRP1->GetName());
209  else
210  return pRP1->GetName().CmpNoCase(pRP2->GetName());
211  } else
212  return 0;
213 }
214 
215 // sort callback. Sort by wpt distance.
216 static int sort_wp_len_dir;
217 #if wxCHECK_VERSION(2, 9, 0)
218 static int wxCALLBACK SortWaypointsOnDistance(wxIntPtr item1, wxIntPtr item2,
219  wxIntPtr list)
220 #else
221 int wxCALLBACK SortWaypointsOnDistance(long item1, long item2, long list)
222 #endif
223 {
224  double dst1, dst2;
225  DistanceBearingMercator(((RoutePoint *)item1)->m_lat,
226  ((RoutePoint *)item1)->m_lon, gLat, gLon, NULL,
227  &dst1);
228  DistanceBearingMercator(((RoutePoint *)item2)->m_lat,
229  ((RoutePoint *)item2)->m_lon, gLat, gLon, NULL,
230  &dst2);
231  return SortDouble(sort_wp_len_dir, dst1, dst2);
232 }
233 
234 // sort callback. Sort by layer name.
235 static int sort_layer_name_dir;
236 #if wxCHECK_VERSION(2, 9, 0)
237 static int wxCALLBACK SortLayersOnName(wxIntPtr item1, wxIntPtr item2,
238  wxIntPtr list)
239 #else
240 int wxCALLBACK SortLayersOnName(long item1, long item2, long list)
241 #endif
242 {
243  return SortRouteTrack(sort_layer_name_dir, ((Layer *)item1)->m_LayerName,
244  ((Layer *)item2)->m_LayerName);
245 }
246 
247 // sort callback. Sort by layer size.
248 static int sort_layer_len_dir;
249 #if wxCHECK_VERSION(2, 9, 0)
250 static int wxCALLBACK SortLayersOnSize(wxIntPtr item1, wxIntPtr item2,
251  wxIntPtr list)
252 #else
253 int wxCALLBACK SortLayersOnSize(long item1, long item2, long list)
254 #endif
255 {
256  return SortDouble(sort_layer_len_dir, ((Layer *)item1)->m_NoOfItems,
257  ((Layer *)item2)->m_NoOfItems);
258 }
259 
260 // event table. Mostly empty, because I find it much easier to see what is
261 // connected to what using Connect() where possible, so that it is visible in
262 // the code.
263 BEGIN_EVENT_TABLE(RouteManagerDialog, wxFrame)
264 EVT_NOTEBOOK_PAGE_CHANGED(
265  wxID_ANY,
266  RouteManagerDialog::OnTabSwitch) // This should work under Windows :-(
267 EVT_CLOSE(RouteManagerDialog::OnClose)
268 EVT_COMMAND(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, RouteManagerDialog::OnOK)
269 EVT_CHAR_HOOK(RouteManagerDialog::OnKey)
270 END_EVENT_TABLE()
271 
272 void RouteManagerDialog::OnKey(wxKeyEvent &ke) {
273  if (ke.GetKeyCode() == WXK_ESCAPE)
274  Close(true);
275  else
276  ke.Skip();
277 }
278 
279 void RouteManagerDialog::OnTabSwitch(wxNotebookEvent &event) {
280  if (!m_pNotebook) return;
281  int current_page = m_pNotebook->GetSelection();
282  if (current_page == 3) {
283  if (btnImport) btnImport->Enable(false);
284  if (btnExport) btnExport->Enable(false);
285  if (btnExportViz) btnExportViz->Enable(false);
286  } else {
287  if (btnImport) btnImport->Enable(true);
288  if (btnExport) btnExport->Enable(true);
289  if (btnExportViz) btnExportViz->Enable(true);
290  }
291  event.Skip(); // remove if using event table... why?
292 }
293 
294 // implementation
295 
296 bool RouteManagerDialog::instanceFlag = false;
297 RouteManagerDialog *RouteManagerDialog::single = NULL;
298 
299 RouteManagerDialog *RouteManagerDialog::getInstance(wxWindow *parent) {
300  if (!instanceFlag) {
301  single = new RouteManagerDialog(parent);
302  instanceFlag = true;
303  return single;
304  } else {
305  return single;
306  }
307 }
308 
309 RouteManagerDialog::RouteManagerDialog(wxWindow *parent) {
310  long style =
311  wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT;
312 
313  wxFrame::Create(parent, -1, wxString(_("Route & Mark Manager")),
314  wxDefaultPosition, wxDefaultSize, style);
315 
316  wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
317  SetFont(*qFont);
318 
319  m_lastWptItem = -1;
320  m_lastTrkItem = -1;
321  m_lastRteItem = -1;
322  sort_wp_key = SORT_ON_NAME;
323  sort_track_key = SORT_ON_NAME;
324 
325  btnImport = NULL;
326  btnExport = NULL;
327  btnExportViz = NULL;
328 
329  Create();
330  routes_update_listener.Init(g_pRouteMan->on_routes_update,
331  [&](wxCommandEvent) { UpdateRouteListCtrl(); });
332 }
333 
334 void RouteManagerDialog::Create() {
335  // Get a text height metric for reference
336  int char_width, char_height;
337  GetTextExtent(_T("W"), &char_width, &char_height);
338  m_charWidth = char_width;
339 
340  wxBoxSizer *itemBoxSizer1 = new wxBoxSizer(wxVERTICAL);
341  SetSizer(itemBoxSizer1);
342 
343  m_pNotebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition,
344  wxSize(-1, -1), wxNB_TOP);
345  itemBoxSizer1->Add(m_pNotebook, 1, wxALL | wxEXPAND, 5);
346 
347  // Create "Routes" panel
348  m_pPanelRte = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition,
349  wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
350 
351  wxBoxSizer *sbsRoutes = new wxBoxSizer(wxHORIZONTAL);
352  m_pPanelRte->SetSizer(sbsRoutes);
353  m_pNotebook->AddPage(m_pPanelRte, _("Routes"));
354 
355  sort_wp_len_dir = 1;
356  sort_wp_name_dir = 0;
357  sort_track_len_dir = 1;
358  sort_route_to_dir = 0;
359  sort_track_name_dir = 0;
360  sort_route_name_dir = 0;
361  sort_layer_name_dir = 0;
362  sort_layer_len_dir = 1;
363 
364  m_listIconSize = 2 * GetCharHeight();
365 
366  // Setup GUI
367  wxBoxSizer *bSizerRteContents;
368  bSizerRteContents = new wxBoxSizer(wxVERTICAL);
369 
370  wxFlexGridSizer *fgSizerFilterRte;
371  fgSizerFilterRte = new wxFlexGridSizer(0, 2, 0, 0);
372  fgSizerFilterRte->AddGrowableCol(1);
373  fgSizerFilterRte->SetFlexibleDirection(wxBOTH);
374  fgSizerFilterRte->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
375 
376  m_stFilterRte = new wxStaticText(m_pPanelRte, wxID_ANY, _("Filter"),
377  wxDefaultPosition, wxDefaultSize, 0);
378  m_stFilterRte->Wrap(-1);
379  fgSizerFilterRte->Add(m_stFilterRte, 0, wxALL, 5);
380 
381  m_tFilterRte = new wxTextCtrl(m_pPanelRte, wxID_ANY, wxEmptyString,
382  wxDefaultPosition, wxDefaultSize, 0);
383  fgSizerFilterRte->Add(m_tFilterRte, 1, wxALL | wxEXPAND, 5);
384 
385  bSizerRteContents->Add(fgSizerFilterRte, 0, wxEXPAND, 5);
386  m_tFilterRte->Connect(
387  wxEVT_COMMAND_TEXT_UPDATED,
388  wxCommandEventHandler(RouteManagerDialog::OnFilterChanged), NULL, this);
389 
390  m_cbShowAllRte = new wxCheckBox(m_pPanelRte, wxID_ANY, _("Show all routes"));
391  bSizerRteContents->Add(m_cbShowAllRte, 0, wxEXPAND | wxLEFT, 5);
392  m_cbShowAllRte->Connect(
393  wxEVT_COMMAND_CHECKBOX_CLICKED,
394  wxCommandEventHandler(RouteManagerDialog::OnShowAllRteCBClicked), NULL,
395  this);
396 
397  m_pRouteListCtrl =
398  new wxListCtrl(m_pPanelRte, -1, wxDefaultPosition, wxSize(-1, -1),
399  wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES |
400  wxBORDER_SUNKEN /*|wxLC_VRULES*/);
401 #ifdef __ANDROID__
402  m_pRouteListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
403 #endif
404 
405  m_pRouteListCtrl->Connect(
406  wxEVT_COMMAND_LIST_ITEM_SELECTED,
407  wxListEventHandler(RouteManagerDialog::OnRteSelected), NULL, this);
408  m_pRouteListCtrl->Connect(
409  wxEVT_COMMAND_LIST_ITEM_DESELECTED,
410  wxListEventHandler(RouteManagerDialog::OnRteSelected), NULL, this);
411  m_pRouteListCtrl->Connect(
412  wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
413  wxListEventHandler(RouteManagerDialog::OnRteDefaultAction), NULL, this);
414  m_pRouteListCtrl->Connect(
415  wxEVT_LEFT_DOWN,
416  wxMouseEventHandler(RouteManagerDialog::OnRteToggleVisibility), NULL,
417  this);
418  m_pRouteListCtrl->Connect(
419  wxEVT_COMMAND_LIST_COL_CLICK,
420  wxListEventHandler(RouteManagerDialog::OnRteColumnClicked), NULL, this);
421  bSizerRteContents->Add(m_pRouteListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
422  sbsRoutes->Add(bSizerRteContents, 1, wxEXPAND, 5);
423 
424  // Columns: visibility ctrl, name
425  // note that under MSW for SetColumnWidth() to work we need to create the
426  // items with images initially even if we specify dummy image id
427  m_pRouteListCtrl->InsertColumn(rmVISIBLE, _("Show"), wxLIST_FORMAT_LEFT,
428  10 /*4 * char_width*/);
429  m_pRouteListCtrl->InsertColumn(rmROUTENAME, _("Route Name"),
430  wxLIST_FORMAT_LEFT, 15 * char_width);
431  m_pRouteListCtrl->InsertColumn(rmROUTEDESC, _("From <-> To"),
432  wxLIST_FORMAT_LEFT, 10 * char_width);
433 
434  // Buttons: Delete, Properties...
435  wxBoxSizer *bsRouteButtons = new wxBoxSizer(wxVERTICAL);
436  sbsRoutes->Add(bsRouteButtons, 0, wxEXPAND);
437 
438  wxScrolledWindow *winr = new wxScrolledWindow(
439  m_pPanelRte, wxID_ANY, wxDefaultPosition, wxDefaultSize,
440  wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL);
441  winr->SetScrollRate(0, 5);
442 
443  bsRouteButtons->Add(winr, 1, wxALL | wxEXPAND, DIALOG_MARGIN);
444 
445  wxBoxSizer *bsRouteButtonsInner = new wxBoxSizer(wxVERTICAL);
446  winr->SetSizer(bsRouteButtonsInner);
447 
448  btnRteProperties = new wxButton(winr, -1, _("&Properties") + _T("..."));
449  bsRouteButtonsInner->Add(btnRteProperties, 0, wxALL | wxEXPAND,
450  DIALOG_MARGIN);
451  btnRteProperties->Connect(
452  wxEVT_COMMAND_BUTTON_CLICKED,
453  wxCommandEventHandler(RouteManagerDialog::OnRtePropertiesClick), NULL,
454  this);
455 
456  btnRteActivate = new wxButton(winr, -1, _("&Activate"));
457  bsRouteButtonsInner->Add(btnRteActivate, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
458  btnRteActivate->Connect(
459  wxEVT_COMMAND_BUTTON_CLICKED,
460  wxCommandEventHandler(RouteManagerDialog::OnRteActivateClick), NULL,
461  this);
462  btnRteActivate->Connect(
463  wxEVT_LEFT_DOWN,
464  wxMouseEventHandler(RouteManagerDialog::OnRteBtnLeftDown), NULL, this);
465 
466  btnRteZoomto = new wxButton(winr, -1, _("&Center View"));
467  bsRouteButtonsInner->Add(btnRteZoomto, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
468  btnRteZoomto->Connect(
469  wxEVT_COMMAND_BUTTON_CLICKED,
470  wxCommandEventHandler(RouteManagerDialog::OnRteZoomtoClick), NULL, this);
471  btnRteZoomto->Connect(
472  wxEVT_LEFT_DOWN,
473  wxMouseEventHandler(RouteManagerDialog::OnRteBtnLeftDown), NULL, this);
474 
475  btnRteReverse = new wxButton(winr, -1, _("&Reverse"));
476  bsRouteButtonsInner->Add(btnRteReverse, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
477  btnRteReverse->Connect(
478  wxEVT_COMMAND_BUTTON_CLICKED,
479  wxCommandEventHandler(RouteManagerDialog::OnRteReverseClick), NULL, this);
480 
481  btnRteDelete = new wxButton(winr, -1, _("&Delete"));
482  bsRouteButtonsInner->Add(btnRteDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
483  btnRteDelete->Connect(
484  wxEVT_COMMAND_BUTTON_CLICKED,
485  wxCommandEventHandler(RouteManagerDialog::OnRteDeleteClick), NULL, this);
486 
487  wxString reseq_label(_("&Resequence Waypoints"));
488  wxString export_label(_("&Export selected..."));
489  wxString send_to_gps_label(_("&Send to GPS..."));
490  wxString send_to_peer_label(_("Send to &Peer..."));
491 
492 #ifdef __ANDROID__
493  reseq_label = wxString(_("Resequence"));
494  export_label = wxString(_("Export"));
495  send_to_gps_label = wxString(_("Send to GPS"));
496  send_to_peer_label = wxString(_("Send to Peer"));
497 #endif
498 
499  btnRteExport = new wxButton(winr, -1, export_label);
500  bsRouteButtonsInner->Add(btnRteExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
501  btnRteExport->Connect(
502  wxEVT_COMMAND_BUTTON_CLICKED,
503  wxCommandEventHandler(RouteManagerDialog::OnRteExportClick), NULL, this);
504 
505 
506  btnRteResequence = new wxButton(winr, -1, reseq_label);
507  bsRouteButtonsInner->Add(btnRteResequence, 0, wxALL | wxEXPAND,
508  DIALOG_MARGIN);
509  btnRteResequence->Connect(
510  wxEVT_COMMAND_BUTTON_CLICKED,
511  wxCommandEventHandler(RouteManagerDialog::OnRteResequenceClick), NULL,
512  this);
513 
514  btnRteSendToPeer = new wxButton(winr, -1, send_to_peer_label);
515  bsRouteButtonsInner->Add(btnRteSendToPeer, 0, wxALL | wxEXPAND,
516  DIALOG_MARGIN);
517  btnRteSendToPeer->Connect(
518  wxEVT_COMMAND_BUTTON_CLICKED,
519  wxCommandEventHandler(RouteManagerDialog::OnRteSendToPeerClick), NULL,
520  this);
521 
522  btnRteSendToGPS = new wxButton(winr, -1, send_to_gps_label);
523  bsRouteButtonsInner->Add(btnRteSendToGPS, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
524  btnRteSendToGPS->Connect(
525  wxEVT_COMMAND_BUTTON_CLICKED,
526  wxCommandEventHandler(RouteManagerDialog::OnRteSendToGPSClick), NULL,
527  this);
528 
529  bsRouteButtonsInner->AddSpacer(10);
530 
531  btnRteDeleteAll = new wxButton(winr, -1, _("&Delete All"));
532  bsRouteButtonsInner->Add(btnRteDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
533  btnRteDeleteAll->Connect(
534  wxEVT_COMMAND_BUTTON_CLICKED,
535  wxCommandEventHandler(RouteManagerDialog::OnRteDeleteAllClick), NULL,
536  this);
537 
538  // Create "Tracks" panel
539  m_pPanelTrk = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition,
540  wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
541  wxBoxSizer *sbsTracks = new wxBoxSizer(wxHORIZONTAL);
542  m_pPanelTrk->SetSizer(sbsTracks);
543  m_pNotebook->AddPage(m_pPanelTrk, _("Tracks"));
544 
545  wxBoxSizer *bSizerTrkContents;
546  bSizerTrkContents = new wxBoxSizer(wxVERTICAL);
547 
548  wxFlexGridSizer *fgSizerFilterTrk;
549  fgSizerFilterTrk = new wxFlexGridSizer(0, 2, 0, 0);
550  fgSizerFilterTrk->AddGrowableCol(1);
551  fgSizerFilterTrk->SetFlexibleDirection(wxBOTH);
552  fgSizerFilterTrk->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
553 
554  m_stFilterTrk = new wxStaticText(m_pPanelTrk, wxID_ANY, _("Filter"),
555  wxDefaultPosition, wxDefaultSize, 0);
556  m_stFilterTrk->Wrap(-1);
557  fgSizerFilterTrk->Add(m_stFilterTrk, 0, wxALL, 5);
558 
559  m_tFilterTrk = new wxTextCtrl(m_pPanelTrk, wxID_ANY, wxEmptyString,
560  wxDefaultPosition, wxDefaultSize, 0);
561  fgSizerFilterTrk->Add(m_tFilterTrk, 1, wxALL | wxEXPAND, 5);
562 
563  bSizerTrkContents->Add(fgSizerFilterTrk, 0, wxEXPAND, 5);
564  m_tFilterTrk->Connect(
565  wxEVT_COMMAND_TEXT_UPDATED,
566  wxCommandEventHandler(RouteManagerDialog::OnFilterChanged), NULL, this);
567 
568  m_cbShowAllTrk = new wxCheckBox(m_pPanelTrk, wxID_ANY, _("Show all tracks"));
569  bSizerTrkContents->Add(m_cbShowAllTrk, 0, wxEXPAND | wxLEFT, 5);
570  m_cbShowAllTrk->Connect(
571  wxEVT_COMMAND_CHECKBOX_CLICKED,
572  wxCommandEventHandler(RouteManagerDialog::OnShowAllTrkCBClicked), NULL,
573  this);
574 
575  m_pTrkListCtrl =
576  new wxListCtrl(m_pPanelTrk, -1, wxDefaultPosition, wxDefaultSize,
577  wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES |
578  wxBORDER_SUNKEN /*|wxLC_VRULES*/);
579 
580 #ifdef __ANDROID__
581  m_pTrkListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
582 #endif
583 
584  m_pTrkListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED,
585  wxListEventHandler(RouteManagerDialog::OnTrkSelected),
586  NULL, this);
587  m_pTrkListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_DESELECTED,
588  wxListEventHandler(RouteManagerDialog::OnTrkSelected),
589  NULL, this);
590  m_pTrkListCtrl->Connect(
591  wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
592  wxListEventHandler(RouteManagerDialog::OnTrkDefaultAction), NULL, this);
593  m_pTrkListCtrl->Connect(
594  wxEVT_LEFT_DOWN,
595  wxMouseEventHandler(RouteManagerDialog::OnTrkToggleVisibility), NULL,
596  this);
597  m_pTrkListCtrl->Connect(
598  wxEVT_COMMAND_LIST_COL_CLICK,
599  wxListEventHandler(RouteManagerDialog::OnTrkColumnClicked), NULL, this);
600  m_pTrkListCtrl->Connect(
601  wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK,
602  wxListEventHandler(RouteManagerDialog::OnTrkRightClick), NULL, this);
603  this->Connect(wxEVT_COMMAND_MENU_SELECTED,
604  wxCommandEventHandler(RouteManagerDialog::OnTrkMenuSelected),
605  NULL, this);
606 
607  bSizerTrkContents->Add(m_pTrkListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
608  sbsTracks->Add(bSizerTrkContents, 1, wxEXPAND, 5);
609 
610  m_pTrkListCtrl->InsertColumn(colTRKVISIBLE, _("Show"), wxLIST_FORMAT_LEFT,
611  4 * char_width);
612  m_pTrkListCtrl->InsertColumn(colTRKNAME, _("Track Name"), wxLIST_FORMAT_LEFT,
613  20 * char_width);
614  m_pTrkListCtrl->InsertColumn(colTRKDATE, _("Start Date"), wxLIST_FORMAT_LEFT,
615  20 * char_width);
616  m_pTrkListCtrl->InsertColumn(colTRKLENGTH, _("Length"), wxLIST_FORMAT_LEFT,
617  5 * char_width);
618 
619  wxBoxSizer *bsTrkButtons = new wxBoxSizer(wxVERTICAL);
620  sbsTracks->Add(bsTrkButtons, 0, wxEXPAND);
621 
622  wxScrolledWindow *wint = new wxScrolledWindow(
623  m_pPanelTrk, wxID_ANY, wxDefaultPosition, wxDefaultSize,
624  wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL);
625  wint->SetScrollRate(0, 5);
626 
627  bsTrkButtons->Add(wint, 1, wxALL | wxEXPAND, DIALOG_MARGIN);
628 
629  wxBoxSizer *bsTrkButtonsInner = new wxBoxSizer(wxVERTICAL);
630  wint->SetSizer(bsTrkButtonsInner);
631 
632  btnTrkNew = new wxButton(wint, -1, _("&Start Track"));
633  bsTrkButtonsInner->Add(btnTrkNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
634  btnTrkNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
635  wxCommandEventHandler(RouteManagerDialog::OnTrkNewClick),
636  NULL, this);
637 
638  btnTrkProperties = new wxButton(wint, -1, _("&Properties"));
639  bsTrkButtonsInner->Add(btnTrkProperties, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
640  btnTrkProperties->Connect(
641  wxEVT_COMMAND_BUTTON_CLICKED,
642  wxCommandEventHandler(RouteManagerDialog::OnTrkPropertiesClick), NULL,
643  this);
644 
645  btnTrkDelete = new wxButton(wint, -1, _("&Delete"));
646  bsTrkButtonsInner->Add(btnTrkDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
647  btnTrkDelete->Connect(
648  wxEVT_COMMAND_BUTTON_CLICKED,
649  wxCommandEventHandler(RouteManagerDialog::OnTrkDeleteClick), NULL, this);
650 
651  btnTrkExport = new wxButton(wint, -1, _("&Export selected..."));
652  bsTrkButtonsInner->Add(btnTrkExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
653  btnTrkExport->Connect(
654  wxEVT_COMMAND_BUTTON_CLICKED,
655  wxCommandEventHandler(RouteManagerDialog::OnTrkExportClick), NULL, this);
656 
657  btnTrkRouteFromTrack = new wxButton(wint, -1, _("Route from Track"));
658  bsTrkButtonsInner->Add(btnTrkRouteFromTrack, 0, wxALL | wxEXPAND,
659  DIALOG_MARGIN);
660  btnTrkRouteFromTrack->Connect(
661  wxEVT_COMMAND_BUTTON_CLICKED,
662  wxCommandEventHandler(RouteManagerDialog::OnTrkRouteFromTrackClick), NULL,
663  this);
664 
665  btnTrkSendToPeer = new wxButton(wint, -1, _("Send to &Peer"));
666  bsTrkButtonsInner->Add(btnTrkSendToPeer, 0, wxALL | wxEXPAND,
667  DIALOG_MARGIN);
668  btnTrkSendToPeer->Connect(
669  wxEVT_COMMAND_BUTTON_CLICKED,
670  wxCommandEventHandler(RouteManagerDialog::OnTrkSendToPeerClick), NULL,
671  this);
672 
673  bsTrkButtonsInner->AddSpacer(10);
674 
675  btnTrkDeleteAll = new wxButton(wint, -1, _("&Delete All"));
676  bsTrkButtonsInner->Add(btnTrkDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
677  btnTrkDeleteAll->Connect(
678  wxEVT_COMMAND_BUTTON_CLICKED,
679  wxCommandEventHandler(RouteManagerDialog::OnTrkDeleteAllClick), NULL,
680  this);
681 
682  // Create "Marks" panel
683  m_pPanelWpt = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition,
684  wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
685  wxBoxSizer *sbsWpts = new wxBoxSizer(wxHORIZONTAL);
686  m_pPanelWpt->SetSizer(sbsWpts);
687  m_pNotebook->AddPage(m_pPanelWpt, _("Marks"));
688 
689  wxBoxSizer *bSizerWptContents;
690  bSizerWptContents = new wxBoxSizer(wxVERTICAL);
691 
692  wxFlexGridSizer *fgSizerFilterWpt;
693  fgSizerFilterWpt = new wxFlexGridSizer(0, 2, 0, 0);
694  fgSizerFilterWpt->AddGrowableCol(1);
695  fgSizerFilterWpt->SetFlexibleDirection(wxBOTH);
696  fgSizerFilterWpt->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
697 
698  m_stFilterWpt = new wxStaticText(m_pPanelWpt, wxID_ANY, _("Filter"),
699  wxDefaultPosition, wxDefaultSize, 0);
700  m_stFilterWpt->Wrap(-1);
701  fgSizerFilterWpt->Add(m_stFilterWpt, 0, wxALL, 5);
702 
703  m_tFilterWpt = new wxTextCtrl(m_pPanelWpt, wxID_ANY, wxEmptyString,
704  wxDefaultPosition, wxDefaultSize, 0);
705  fgSizerFilterWpt->Add(m_tFilterWpt, 1, wxALL | wxEXPAND, 5);
706 
707  bSizerWptContents->Add(fgSizerFilterWpt, 0, wxEXPAND, 5);
708  m_tFilterWpt->Connect(
709  wxEVT_COMMAND_TEXT_UPDATED,
710  wxCommandEventHandler(RouteManagerDialog::OnFilterChanged), NULL, this);
711 
712  m_cbShowAllWP =
713  new wxCheckBox(m_pPanelWpt, wxID_ANY, _("Show all marks"));
714  bSizerWptContents->Add(m_cbShowAllWP, 0, wxEXPAND | wxLEFT, 5);
715  m_cbShowAllWP->Connect(
716  wxEVT_COMMAND_CHECKBOX_CLICKED,
717  wxCommandEventHandler(RouteManagerDialog::OnShowAllWpCBClicked), NULL,
718  this);
719 
720  m_pWptListCtrl =
721  new wxListCtrl(m_pPanelWpt, -1, wxDefaultPosition, wxDefaultSize,
722  wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES |
723  wxBORDER_SUNKEN /*|wxLC_VRULES*/);
724 #ifdef __ANDROID__
725  m_pWptListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
726 #endif
727 
728  m_pWptListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED,
729  wxListEventHandler(RouteManagerDialog::OnWptSelected),
730  NULL, this);
731  m_pWptListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_DESELECTED,
732  wxListEventHandler(RouteManagerDialog::OnWptSelected),
733  NULL, this);
734  m_pWptListCtrl->Connect(
735  wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
736  wxListEventHandler(RouteManagerDialog::OnWptDefaultAction), NULL, this);
737  m_pWptListCtrl->Connect(
738  wxEVT_LEFT_DOWN,
739  wxMouseEventHandler(RouteManagerDialog::OnWptToggleVisibility), NULL,
740  this);
741  m_pWptListCtrl->Connect(
742  wxEVT_COMMAND_LIST_COL_CLICK,
743  wxListEventHandler(RouteManagerDialog::OnWptColumnClicked), NULL, this);
744  bSizerWptContents->Add(m_pWptListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
745  sbsWpts->Add(bSizerWptContents, 1, wxEXPAND, 5);
746 
747  m_pWptListCtrl->InsertColumn(colWPTICON, _("Icon"), wxLIST_FORMAT_LEFT,
748  4 * char_width);
749  m_pWptListCtrl->InsertColumn(colWPTSCALE, _("Scale"), wxLIST_FORMAT_LEFT,
750  8 * char_width);
751  m_pWptListCtrl->InsertColumn(colWPTNAME, _("Mark Name"),
752  wxLIST_FORMAT_LEFT, 15 * char_width);
753  m_pWptListCtrl->InsertColumn(colWPTDIST, _("Distance from own ship"),
754  wxLIST_FORMAT_LEFT, 14 * char_width);
755 
756  wxBoxSizer *bsWptButtons = new wxBoxSizer(wxVERTICAL);
757  sbsWpts->Add(bsWptButtons, 0, wxEXPAND);
758 
759  wxScrolledWindow *winw = new wxScrolledWindow(
760  m_pPanelWpt, wxID_ANY, wxDefaultPosition, wxDefaultSize,
761  wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL);
762  winw->SetScrollRate(0, 5);
763 
764  bsWptButtons->Add(winw, 1, wxALL | wxEXPAND, DIALOG_MARGIN);
765 
766  wxBoxSizer *bsWptButtonsInner = new wxBoxSizer(wxVERTICAL);
767  winw->SetSizer(bsWptButtonsInner);
768 
769  btnWptNew = new wxButton(winw, -1, _("&New"));
770  bsWptButtonsInner->Add(btnWptNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
771  btnWptNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
772  wxCommandEventHandler(RouteManagerDialog::OnWptNewClick),
773  NULL, this);
774 
775  btnWptProperties = new wxButton(winw, -1, _("&Properties"));
776  bsWptButtonsInner->Add(btnWptProperties, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
777  btnWptProperties->Connect(
778  wxEVT_COMMAND_BUTTON_CLICKED,
779  wxCommandEventHandler(RouteManagerDialog::OnWptPropertiesClick), NULL,
780  this);
781 
782  btnWptZoomto = new wxButton(winw, -1, _("&Center View"));
783  bsWptButtonsInner->Add(btnWptZoomto, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
784  btnWptZoomto->Connect(
785  wxEVT_COMMAND_BUTTON_CLICKED,
786  wxCommandEventHandler(RouteManagerDialog::OnWptZoomtoClick), NULL, this);
787 
788  btnWptDelete = new wxButton(winw, -1, _("&Delete"));
789  bsWptButtonsInner->Add(btnWptDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
790  btnWptDelete->Connect(
791  wxEVT_COMMAND_BUTTON_CLICKED,
792  wxCommandEventHandler(RouteManagerDialog::OnWptDeleteClick), NULL, this);
793 
794  btnWptGoTo = new wxButton(winw, -1, _("&Go To"));
795  bsWptButtonsInner->Add(btnWptGoTo, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
796  btnWptGoTo->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
797  wxCommandEventHandler(RouteManagerDialog::OnWptGoToClick),
798  NULL, this);
799 
800  btnWptExport = new wxButton(winw, -1, _("&Export selected..."));
801  bsWptButtonsInner->Add(btnWptExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
802  btnWptExport->Connect(
803  wxEVT_COMMAND_BUTTON_CLICKED,
804  wxCommandEventHandler(RouteManagerDialog::OnWptExportClick), NULL, this);
805 
806  btnWptSendToGPS = new wxButton(winw, -1, _("&Send to GPS"));
807  bsWptButtonsInner->Add(btnWptSendToGPS, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
808  btnWptSendToGPS->Connect(
809  wxEVT_COMMAND_BUTTON_CLICKED,
810  wxCommandEventHandler(RouteManagerDialog::OnWptSendToGPSClick), NULL,
811  this);
812 
813  btnWptSendToPeer = new wxButton(winw, -1, _("Send to &Peer"));
814  bsWptButtonsInner->Add(btnWptSendToPeer, 0, wxALL | wxEXPAND,
815  DIALOG_MARGIN);
816  btnWptSendToPeer->Connect(
817  wxEVT_COMMAND_BUTTON_CLICKED,
818  wxCommandEventHandler(RouteManagerDialog::OnWptSendToPeerClick), NULL,
819  this);
820 
821  bsWptButtonsInner->AddSpacer(10);
822 
823  btnWptDeleteAll = new wxButton(winw, -1, _("Delete All"));
824  bsWptButtonsInner->Add(btnWptDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
825  btnWptDeleteAll->Connect(
826  wxEVT_COMMAND_BUTTON_CLICKED,
827  wxCommandEventHandler(RouteManagerDialog::OnWptDeleteAllClick), NULL,
828  this);
829 
830  wxBoxSizer *itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
831  itemBoxSizer1->Add(itemBoxSizer5, 0, wxALL | wxEXPAND);
832 
833  wxBoxSizer *itemBoxSizer6 = new wxBoxSizer(wxHORIZONTAL);
834  itemBoxSizer5->Add(itemBoxSizer6, 1, wxALL | wxEXPAND);
835 
836  btnImport = new wxButton(this, -1, _("I&mport GPX..."));
837  itemBoxSizer6->Add(btnImport, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN);
838  btnImport->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
839  wxCommandEventHandler(RouteManagerDialog::OnImportClick),
840  NULL, this);
841  /*
842  * btnExport = new wxButton( this, -1, _("E&xport All...") );
843  * itemBoxSizer6->Add( btnExport, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN );
844  * btnExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
845  * wxCommandEventHandler(RouteManagerDialog::OnExportClick), NULL,
846  * this );
847  */
848  btnExportViz = new wxButton(this, -1, _("Export All Visible..."));
849  itemBoxSizer6->Add(btnExportViz, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN);
850  btnExportViz->Connect(
851  wxEVT_COMMAND_BUTTON_CLICKED,
852  wxCommandEventHandler(RouteManagerDialog::OnExportVizClick), NULL, this);
853 
854  // Dialog OK button
855  wxSize sz = ::wxGetDisplaySize();
856  if (sz.y < sz.x) { // landscape
857  itemBoxSizer6->Add(0, 0, 1, wxEXPAND, 5); // Spacer
858  itemBoxSizer6->Add(new wxButton(this, wxID_OK), 0, wxALL, DIALOG_MARGIN);
859  }
860  else {
861  wxStaticLine* staticLine121 =
862  new wxStaticLine(this, wxID_ANY, wxDefaultPosition,
863  wxDefaultSize, wxLI_HORIZONTAL);
864  itemBoxSizer1->Add(staticLine121, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
865 
866  wxBoxSizer *itemBoxSizer7 = new wxBoxSizer(wxHORIZONTAL);
867  itemBoxSizer1->Add(itemBoxSizer7, 0, wxEXPAND);
868 
869  wxBoxSizer *itemBoxSizer7a = new wxBoxSizer(wxHORIZONTAL);
870  itemBoxSizer7->Add(itemBoxSizer7a, 1, wxEXPAND);
871 
872  itemBoxSizer7a->AddStretchSpacer();
873  itemBoxSizer7a->Add(new wxButton(this, wxID_OK), 0, wxRIGHT | wxALIGN_RIGHT, DIALOG_MARGIN *4);
874  }
875 
876  // Create "Layers" panel
877  m_pPanelLay = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition,
878  wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
879  wxBoxSizer *sbsLayers = new wxBoxSizer(wxHORIZONTAL);
880  m_pPanelLay->SetSizer(sbsLayers);
881  m_pNotebook->AddPage(m_pPanelLay, _("Layers"));
882 
883  wxBoxSizer *bSizerLayContents;
884  bSizerLayContents = new wxBoxSizer(wxVERTICAL);
885 
886  wxFlexGridSizer *fgSizerFilterLay;
887  fgSizerFilterLay = new wxFlexGridSizer(0, 2, 0, 0);
888  fgSizerFilterLay->AddGrowableCol(1);
889  fgSizerFilterLay->SetFlexibleDirection(wxBOTH);
890  fgSizerFilterLay->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
891 
892  m_stFilterLay = new wxStaticText(m_pPanelLay, wxID_ANY, _("Filter"),
893  wxDefaultPosition, wxDefaultSize, 0);
894  m_stFilterLay->Wrap(-1);
895  fgSizerFilterLay->Add(m_stFilterLay, 0, wxALL, 5);
896 
897  m_tFilterLay = new wxTextCtrl(m_pPanelLay, wxID_ANY, wxEmptyString,
898  wxDefaultPosition, wxDefaultSize, 0);
899  fgSizerFilterLay->Add(m_tFilterLay, 1, wxALL | wxEXPAND, 5);
900 
901  bSizerLayContents->Add(fgSizerFilterLay, 0, wxEXPAND, 5);
902  m_tFilterLay->Connect(
903  wxEVT_COMMAND_TEXT_UPDATED,
904  wxCommandEventHandler(RouteManagerDialog::OnFilterChanged), NULL, this);
905 
906  m_cbShowAllLay = new wxCheckBox(m_pPanelLay, wxID_ANY, _("Show all layers"));
907  bSizerLayContents->Add(m_cbShowAllLay, 0, wxEXPAND | wxLEFT, 5);
908  m_cbShowAllLay->Connect(
909  wxEVT_COMMAND_CHECKBOX_CLICKED,
910  wxCommandEventHandler(RouteManagerDialog::OnShowAllLayCBClicked), NULL,
911  this);
912 
913  m_pLayListCtrl =
914  new wxListCtrl(m_pPanelLay, -1, wxDefaultPosition, wxDefaultSize,
915  wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING |
916  wxLC_HRULES | wxBORDER_SUNKEN /*|wxLC_VRULES*/);
917 #ifdef __ANDROID__
918  m_pLayListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
919 #endif
920 
921  m_pLayListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED,
922  wxListEventHandler(RouteManagerDialog::OnLaySelected),
923  NULL, this);
924  m_pLayListCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_DESELECTED,
925  wxListEventHandler(RouteManagerDialog::OnLaySelected),
926  NULL, this);
927  m_pLayListCtrl->Connect(
928  wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
929  wxListEventHandler(RouteManagerDialog::OnLayDefaultAction), NULL, this);
930  m_pLayListCtrl->Connect(
931  wxEVT_LEFT_DOWN,
932  wxMouseEventHandler(RouteManagerDialog::OnLayToggleVisibility), NULL,
933  this);
934  m_pLayListCtrl->Connect(
935  wxEVT_COMMAND_LIST_COL_CLICK,
936  wxListEventHandler(RouteManagerDialog::OnLayColumnClicked), NULL, this);
937  bSizerLayContents->Add(m_pLayListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
938  sbsLayers->Add(bSizerLayContents, 1, wxEXPAND, 5);
939 
940  m_pLayListCtrl->InsertColumn(colLAYVISIBLE, _T(""), wxLIST_FORMAT_LEFT,
941  4 * char_width);
942  m_pLayListCtrl->InsertColumn(colLAYNAME, _("Layer Name"), wxLIST_FORMAT_LEFT,
943  14 * char_width);
944  m_pLayListCtrl->InsertColumn(colLAYITEMS, _("No. of items"),
945  wxLIST_FORMAT_LEFT, 10 * char_width);
946  m_pLayListCtrl->InsertColumn(colLAYPERSIST, _("Layer type"),
947  wxLIST_FORMAT_LEFT, 10 * char_width);
948 
949  wxBoxSizer *bsLayButtons = new wxBoxSizer(wxVERTICAL);
950  sbsLayers->Add(bsLayButtons, 0, wxEXPAND);
951 
952  wxScrolledWindow *winl = new wxScrolledWindow(
953  m_pPanelLay, wxID_ANY, wxDefaultPosition, wxDefaultSize,
954  wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL);
955  winl->SetScrollRate(0, 5);
956 
957  bsLayButtons->Add(winl, 1, wxALL | wxEXPAND, DIALOG_MARGIN);
958 
959  wxBoxSizer *bsLayButtonsInner = new wxBoxSizer(wxVERTICAL);
960  winl->SetSizer(bsLayButtonsInner);
961 
962  btnLayNew = new wxButton(winl, -1, _("Create Temporary layer"));
963  bsLayButtonsInner->Add(btnLayNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
964  btnLayNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
965  wxCommandEventHandler(RouteManagerDialog::OnLayNewClick),
966  NULL, this);
967 
968  btnPerLayNew = new wxButton(winl, -1, _("Create Persistent layer"));
969  bsLayButtonsInner->Add(btnPerLayNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
970  btnPerLayNew->Connect(
971  wxEVT_COMMAND_BUTTON_CLICKED,
972  wxCommandEventHandler(RouteManagerDialog::OnPerLayNewClick), NULL, this);
973 
974  btnLayDelete = new wxButton(winl, -1, _("&Delete"));
975  bsLayButtonsInner->Add(btnLayDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
976  btnLayDelete->Connect(
977  wxEVT_COMMAND_BUTTON_CLICKED,
978  wxCommandEventHandler(RouteManagerDialog::OnLayDeleteClick), NULL, this);
979 
980  cbLayToggleChart = new wxCheckBox(winl, -1, _("Show on chart"));
981  bsLayButtonsInner->Add(cbLayToggleChart, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
982  cbLayToggleChart->Connect(
983  wxEVT_COMMAND_CHECKBOX_CLICKED,
984  wxCommandEventHandler(RouteManagerDialog::OnLayToggleChartClick), NULL,
985  this);
986 
987  cbLayToggleNames =
988  new wxCheckBox(winl, -1, _("Show WPT names"), wxDefaultPosition,
989  wxDefaultSize, wxCHK_3STATE);
990 
991  bsLayButtonsInner->Add(cbLayToggleNames, 0, wxALL | wxEXPAND, DIALOG_MARGIN);
992  cbLayToggleNames->Connect(
993  wxEVT_COMMAND_CHECKBOX_CLICKED,
994  wxCommandEventHandler(RouteManagerDialog::OnLayToggleNamesClick), NULL,
995  this);
996 
997  cbLayToggleListing = new wxCheckBox(winl, -1, _("List contents"));
998  bsLayButtonsInner->Add(cbLayToggleListing, 0, wxALL | wxEXPAND,
999  DIALOG_MARGIN);
1000  cbLayToggleListing->Connect(
1001  wxEVT_COMMAND_CHECKBOX_CLICKED,
1002  wxCommandEventHandler(RouteManagerDialog::OnLayToggleListingClick), NULL,
1003  this);
1004 
1005  RecalculateSize();
1006 
1007  int imageRefSize = m_charWidth * 2; // g_Platform->GetDisplayDPmm() * 4;
1008  wxImageList *imglist = new wxImageList(imageRefSize, imageRefSize, true, 1);
1009 
1010  // Load eye icons
1011  wxString UserIconPath = g_Platform->GetSharedDataDir() + _T("uidata") +
1012  wxFileName::GetPathSeparator();
1013  wxImage iconSVG =
1014  LoadSVG(UserIconPath + _T("eye.svg"), imageRefSize, imageRefSize)
1015  .ConvertToImage();
1016  if (iconSVG.IsOk()) {
1017  iconSVG.Resize(wxSize(imageRefSize, imageRefSize),
1018  wxPoint(0, 0)); // Avoid wxImageList size asserts
1019  imglist->Add(wxBitmap(iconSVG));
1020  }
1021 
1022  iconSVG = LoadSVG(UserIconPath + _T("eyex.svg"), imageRefSize, imageRefSize)
1023  .ConvertToImage();
1024  if (iconSVG.IsOk()) {
1025  iconSVG.Resize(wxSize(imageRefSize, imageRefSize), wxPoint(0, 0));
1026  imglist->Add(wxBitmap(iconSVG));
1027  }
1028 
1029  iconSVG =
1030  LoadSVG(UserIconPath + _T("eyeGray.svg"), imageRefSize, imageRefSize)
1031  .ConvertToImage();
1032  if (iconSVG.IsOk()) {
1033  iconSVG.Resize(wxSize(imageRefSize, imageRefSize), wxPoint(0, 0));
1034  imglist->Add(wxBitmap(iconSVG));
1035  }
1036 
1037  m_pRouteListCtrl->AssignImageList(imglist, wxIMAGE_LIST_SMALL);
1038 
1039 #ifdef __ANDROID__
1040  m_pRouteListCtrl->GetHandle()->setIconSize(QSize(imageRefSize, imageRefSize));
1041 #endif
1042 
1043  // Assign will handle destroy, Set will not. It's OK, that's what we want
1044  m_pTrkListCtrl->SetImageList(imglist, wxIMAGE_LIST_SMALL);
1045  m_pWptListCtrl->SetImageList(
1046  pWayPointMan->Getpmarkicon_image_list(m_listIconSize),
1047  wxIMAGE_LIST_SMALL);
1048  m_pLayListCtrl->SetImageList(imglist, wxIMAGE_LIST_SMALL);
1049 
1050  SetColorScheme();
1051 
1052  UpdateLists();
1053 
1054  // This should work under Linux :-(
1055  // m_pNotebook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
1056  // wxNotebookEventHandler(RouteManagerDialog::OnTabSwitch), NULL, this);
1057 
1058  m_bNeedConfigFlush = false;
1059 }
1060 
1061 RouteManagerDialog::~RouteManagerDialog() {
1062  delete m_pRouteListCtrl;
1063  delete m_pTrkListCtrl;
1064  delete m_pWptListCtrl;
1065  delete m_pLayListCtrl;
1066 
1067  delete btnRteDelete;
1068  delete btnRteResequence;
1069  delete btnRteExport;
1070  delete btnRteZoomto;
1071  delete btnRteProperties;
1072  delete btnRteActivate;
1073  delete btnRteReverse;
1074  delete btnRteSendToGPS;
1075  delete btnRteDeleteAll;
1076  delete btnTrkNew;
1077  delete btnTrkProperties;
1078  delete btnTrkDelete;
1079  delete btnTrkExport;
1080  delete btnTrkRouteFromTrack;
1081  delete btnTrkDeleteAll;
1082  delete btnWptNew;
1083  delete btnWptProperties;
1084  delete btnWptZoomto;
1085  delete btnWptDelete;
1086  delete btnWptGoTo;
1087  delete btnWptExport;
1088  delete btnWptSendToGPS;
1089  delete btnWptDeleteAll;
1090  delete btnLayNew;
1091  // delete btnLayProperties;
1092  delete cbLayToggleChart;
1093  delete cbLayToggleListing;
1094  delete cbLayToggleNames;
1095  delete btnLayDelete;
1096  delete btnImport;
1097  delete btnExport;
1098  delete btnExportViz;
1099  btnImport = NULL;
1100  btnExport = NULL;
1101  btnExportViz = NULL;
1102 
1103  delete m_pNotebook;
1104  instanceFlag = false;
1105 }
1106 
1107 void RouteManagerDialog::RecalculateSize() {
1108  // All of this dialog layout is expandable, so we need to set a specific size
1109  // target for the onscreen display. The size will then be adjusted so that it
1110  // fits within the parent's client area, with some padding
1111 
1112  // Get a text height metric for reference
1113  int char_width, char_height;
1114  GetTextExtent(_T("W"), &char_width, &char_height);
1115 
1116  wxSize sz;
1117  sz.x = 60 * char_width;
1118  sz.y = 30 * char_height;
1119 
1120  wxSize dsize = GetParent()->GetClientSize();
1121  sz.y = wxMin(sz.y, dsize.y);
1122  sz.x = wxMin(sz.x, dsize.x);
1123  SetClientSize(sz);
1124 
1125  wxSize fsize = GetSize();
1126  fsize.y = wxMin(fsize.y, dsize.y);
1127  fsize.x = wxMin(fsize.x, dsize.x);
1128  SetSize(fsize);
1129 
1130  CentreOnParent();
1131 }
1132 
1133 void RouteManagerDialog::OnClose(wxCloseEvent &event) {
1134 #ifdef __WXGTK__
1135  gFrame->Raise();
1136 #endif
1137  Hide();
1138  // pRouteManagerDialog = NULL;
1139 }
1140 
1141 void RouteManagerDialog::OnOK(wxCommandEvent &event) {
1142 #ifdef __WXGTK__
1143  gFrame->Raise();
1144 #endif
1145  Hide();
1146 }
1147 
1148 void RouteManagerDialog::SetColorScheme() { DimeControl(this); }
1149 
1150 void RouteManagerDialog::OnShowAllRteCBClicked(wxCommandEvent &event) {
1151  bool viz = m_cbShowAllRte->GetValue();
1152  long item = -1;
1153  for (;;) {
1154  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1155  wxLIST_STATE_DONTCARE);
1156  if (item == -1) break;
1157 
1158  Route *pR = (Route *)m_pRouteListCtrl->GetItemData(item);
1159 
1160  pR->SetVisible(viz, viz);
1161  pR->SetSharedWPViz(viz);
1162 
1163  m_pRouteListCtrl->SetItemImage(item, !viz); // visible
1164 
1165  pConfig->UpdateRoute(pR);
1166  }
1167 
1168  UpdateWptListCtrlViz();
1169 
1170  gFrame->RefreshAllCanvas();
1171 }
1172 
1173 void RouteManagerDialog::OnShowAllWpCBClicked(wxCommandEvent &event) {
1174  bool viz = m_cbShowAllWP->GetValue();
1175  long item = -1;
1176  for (;;) {
1177  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1178  wxLIST_STATE_DONTCARE);
1179  if (item == -1) break;
1180 
1181  RoutePoint *pRP = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
1182 
1183  if (!pRP->IsSharedInVisibleRoute()) {
1184  pRP->SetVisible(viz);
1185  } else
1186  pRP->SetVisible(true);
1187 
1188  m_pWptListCtrl->SetItemImage(item, RoutePointGui(*pRP).GetIconImageIndex());
1189  pConfig->UpdateWayPoint(pRP);
1190  }
1191 
1192  gFrame->RefreshAllCanvas();
1193 }
1194 
1195 void RouteManagerDialog::OnShowAllTrkCBClicked(wxCommandEvent &event) {
1196  bool viz = m_cbShowAllTrk->GetValue();
1197  long item = -1;
1198  for (;;) {
1199  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1200  wxLIST_STATE_DONTCARE);
1201  if (item == -1) break;
1202 
1203  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
1204 
1205  track->SetVisible(viz);
1206  m_pTrkListCtrl->SetItemImage(item, track->IsVisible() ? 0 : 1);
1207  }
1208 
1209  gFrame->RefreshAllCanvas();
1210 }
1211 
1212 void RouteManagerDialog::OnShowAllLayCBClicked(wxCommandEvent &event) {
1213  bool viz = m_cbShowAllLay->GetValue();
1214  long item = -1;
1215  for (;;) {
1216  item = m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1217  wxLIST_STATE_DONTCARE);
1218  if (item == -1) break;
1219 
1220  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
1221 
1222  layer->SetVisibleOnChart(viz);
1223  m_pLayListCtrl->SetItemImage(item, layer->IsVisibleOnChart() ? 0 : 1);
1224 
1225  ToggleLayerContentsOnChart(layer);
1226  }
1227 
1228  gFrame->RefreshAllCanvas();
1229 }
1230 
1231 void RouteManagerDialog::UpdateRouteListCtrl() {
1232  // if an item was selected, make it selected again if it still exist
1233  long item = -1;
1234  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1235  wxLIST_STATE_SELECTED);
1236  wxUIntPtr selected_id = wxUIntPtr(0);
1237  if (item != -1) selected_id = m_pRouteListCtrl->GetItemData(item);
1238 
1239  // Delete existing items
1240  m_pRouteListCtrl->DeleteAllItems();
1241 
1242  // then add routes to the listctrl
1243  RouteList::iterator it;
1244  int index = 0;
1245  int list_index = 0;
1246  bool bpartialViz = false;
1247 
1248  for (it = (*pRouteList).begin(); it != (*pRouteList).end(); ++it, ++index) {
1249  if (!(*it)->IsListed()) continue;
1250 
1251  if (!(*it)->GetName().Upper().Contains(m_tFilterRte->GetValue().Upper())) {
1252  continue;
1253  }
1254 
1255  wxListItem li;
1256  li.SetId(list_index);
1257  li.SetImage((*it)->IsVisible() ? 0 : 1);
1258  li.SetData(*it);
1259  li.SetText(_T(""));
1260  li.SetAlign(wxLIST_FORMAT_LEFT);
1261 
1262  if ((*it)->m_bRtIsActive) {
1263  wxFont font = *wxNORMAL_FONT;
1264  font.SetWeight(wxFONTWEIGHT_BOLD);
1265  li.SetFont(font);
1266  }
1267 
1268  long idx = m_pRouteListCtrl->InsertItem(li);
1269 
1270  wxString name = (*it)->m_RouteNameString;
1271  if (name.IsEmpty()) name = _("(Unnamed Route)");
1272  m_pRouteListCtrl->SetItem(idx, rmROUTENAME, name);
1273 
1274  wxString startend = (*it)->m_RouteStartString;
1275  if (!(*it)->m_RouteEndString.IsEmpty())
1276  startend.append(_(" - ") + (*it)->m_RouteEndString);
1277  m_pRouteListCtrl->SetItem(idx, rmROUTEDESC, startend);
1278 
1279  wxListItem lic;
1280  lic.SetId(list_index);
1281  lic.SetColumn(1);
1282  lic.SetAlign(wxLIST_FORMAT_LEFT);
1283  m_pRouteListCtrl->SetItem(lic);
1284 
1285  lic.SetColumn(2);
1286  lic.SetAlign(wxLIST_FORMAT_LEFT);
1287  m_pRouteListCtrl->SetItem(lic);
1288 
1289  // Keep track if any are invisible
1290  if (!(*it)->IsVisible()) bpartialViz = true;
1291 
1292  list_index++;
1293  }
1294 
1295  m_pRouteListCtrl->SortItems(SortRoutesOnName, (wxIntPtr)NULL);
1296 
1297  m_pRouteListCtrl->SetColumnWidth(0, 4 * m_charWidth);
1298 
1299  // restore selection if possible
1300  // NOTE this will select a different item, if one is deleted
1301  // (the next route will get that index).
1302  if (selected_id != wxUIntPtr(0)) {
1303  item = m_pRouteListCtrl->FindItem(-1, selected_id);
1304  m_pRouteListCtrl->SetItemState(
1305  item, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1306  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1307  }
1308 
1309  if ((m_lastRteItem >= 0) && (m_pRouteListCtrl->GetItemCount()))
1310  m_pRouteListCtrl->EnsureVisible(m_lastRteItem);
1311  UpdateRteButtons();
1312 
1313  // If any route is invisible, then "show all" cb must be clear.
1314  m_cbShowAllRte->SetValue(!bpartialViz);
1315 }
1316 
1317 void RouteManagerDialog::UpdateRteButtons() {
1318  // enable/disable buttons
1319  long selected_index_index =
1320  m_pRouteListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1321  bool enable1 = m_pRouteListCtrl->GetSelectedItemCount() == 1;
1322  bool enablemultiple = m_pRouteListCtrl->GetSelectedItemCount() >= 1;
1323 
1324  m_lastRteItem = selected_index_index;
1325 
1326  btnRteDelete->Enable(m_pRouteListCtrl->GetSelectedItemCount() > 0);
1327  btnRteZoomto->Enable(enable1);
1328  btnRteProperties->Enable(enable1);
1329  btnRteReverse->Enable(enable1);
1330  btnRteExport->Enable(enablemultiple);
1331  btnRteResequence->Enable(enable1);
1332  btnRteSendToGPS->Enable(enable1);
1333  btnRteDeleteAll->Enable(m_pRouteListCtrl->GetItemCount() > 0);
1334  btnRteSendToPeer->Enable(enablemultiple);
1335 
1336  // set activate button text
1337  Route *route = NULL;
1338  if (enable1)
1339  route = (Route *)m_pRouteListCtrl->GetItemData(selected_index_index);
1340 
1341  if (!g_pRouteMan->IsAnyRouteActive()) {
1342  btnRteActivate->Enable(enable1);
1343  if (enable1) btnRteActivate->SetLabel(_("Activate"));
1344 
1345  } else {
1346  if (enable1) {
1347  if (route && route->m_bRtIsActive) {
1348  btnRteActivate->Enable(enable1);
1349  btnRteActivate->SetLabel(_("Deactivate"));
1350  } else
1351  btnRteActivate->Enable(false);
1352  } else
1353  btnRteActivate->Enable(false);
1354  }
1355 }
1356 
1357 void RouteManagerDialog::MakeAllRoutesInvisible() {
1358  RouteList::iterator it;
1359  long index = 0;
1360  for (it = (*pRouteList).begin(); it != (*pRouteList).end(); ++it, ++index) {
1361  if ((*it)->IsVisible()) { // avoid config updating as much as possible!
1362  (*it)->SetVisible(false);
1363  m_pRouteListCtrl->SetItemImage(m_pRouteListCtrl->FindItem(-1, index),
1364  1); // Likely not same order :0
1365  pConfig->UpdateRoute(*it); // auch, flushes config to disk. FIXME
1366  }
1367  }
1368 }
1369 
1370 void RouteManagerDialog::ZoomtoRoute(Route *route) {
1371  // Calculate bbox center
1372  LLBBox RBBox = route->GetBBox();
1373  double clat = (RBBox.GetMinLat() + RBBox.GetMaxLat()) / 2;
1374  double clon = (RBBox.GetMinLon() + RBBox.GetMaxLon()) / 2;
1375 
1376  // Calculate ppm
1377  double rw, rh, ppm; // route width, height, final ppm scale to use
1378  int ww, wh; // chart window width, height
1379  // route bbox width in nm
1380  DistanceBearingMercator(RBBox.GetMinLat(), RBBox.GetMinLon(),
1381  RBBox.GetMinLat(), RBBox.GetMaxLon(), NULL, &rw);
1382  // route bbox height in nm
1383  DistanceBearingMercator(RBBox.GetMinLat(), RBBox.GetMinLon(),
1384  RBBox.GetMaxLat(), RBBox.GetMinLon(), NULL, &rh);
1385 
1386  if (gFrame->GetFocusCanvas()) {
1387  gFrame->GetFocusCanvas()->GetSize(&ww, &wh);
1388  ppm = wxMin(ww / (rw * 1852), wh / (rh * 1852)) * (100 - fabs(clat)) / 90;
1389  ppm = wxMin(ppm, 1.0);
1390 
1391  gFrame->JumpToPosition(gFrame->GetFocusCanvas(), clat, clon, ppm);
1392  }
1393 
1394  m_bNeedConfigFlush = true;
1395 }
1396 
1397 // BEGIN Event handlers
1398 void RouteManagerDialog::OnRteDeleteClick(wxCommandEvent &event) {
1399  RouteList list;
1400 
1401  int answer = OCPNMessageBox(
1402  this, _("Are you sure you want to delete the selected object(s)"),
1403  wxString(_("OpenCPN Alert")), wxYES_NO);
1404  if (answer != wxID_YES) return;
1405 
1406  bool busy = false;
1407  if (m_pRouteListCtrl->GetSelectedItemCount()) {
1408  ::wxBeginBusyCursor();
1409  gFrame->CancelAllMouseRoute();
1410  m_bNeedConfigFlush = true;
1411  busy = true;
1412  }
1413 
1414  long item = -1;
1415  for (;;) {
1416  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1417  wxLIST_STATE_SELECTED);
1418  if (item == -1) break;
1419 
1420  Route *proute_to_delete = (Route *)m_pRouteListCtrl->GetItemData(item);
1421 
1422  if (proute_to_delete) list.Append(proute_to_delete);
1423  }
1424 
1425  if (busy) {
1426  for (unsigned int i = 0; i < list.GetCount(); i++) {
1427  Route *route = list.Item(i)->GetData();
1428  if (route) {
1429  pConfig->DeleteConfigRoute(route);
1430  g_pRouteMan->DeleteRoute(route, NavObjectChanges::getInstance());
1431  }
1432  }
1433 
1434  m_lastRteItem = -1;
1435  UpdateRouteListCtrl();
1436  UpdateTrkListCtrl();
1437 
1438  gFrame->InvalidateAllCanvasUndo();
1439  gFrame->RefreshAllCanvas();
1440  ::wxEndBusyCursor();
1441  }
1442 }
1443 
1444 void RouteManagerDialog::OnRteDeleteAllClick(wxCommandEvent &event) {
1445  int dialog_ret =
1446  OCPNMessageBox(this, _("Are you sure you want to delete <ALL> routes?"),
1447  wxString(_("OpenCPN Alert")), wxYES_NO);
1448 
1449  if (dialog_ret == wxID_YES) {
1450  if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1451 
1452  gFrame->CancelAllMouseRoute();
1453 
1454  g_pRouteMan->DeleteAllRoutes(NavObjectChanges::getInstance());
1455  // TODO Seth
1456  // m_pSelectedRoute = NULL;
1457  // m_pFoundRoutePoint = NULL;
1458  // m_pFoundRoutePointSecond = NULL;
1459 
1460  m_lastRteItem = -1;
1461  UpdateRouteListCtrl();
1462 
1463  // Also need to update the track list control, since routes and tracks
1464  // share a common global list (pRouteList)
1465  UpdateTrkListCtrl();
1466 
1467  if (pRoutePropDialog) pRoutePropDialog->Hide();
1468  gFrame->InvalidateAllCanvasUndo();
1469  gFrame->RefreshAllCanvas();
1470 
1471  m_bNeedConfigFlush = true;
1472  }
1473 }
1474 
1475 void RouteManagerDialog::OnRtePropertiesClick(wxCommandEvent &event) {
1476  // Show routeproperties dialog for selected route
1477  long item = -1;
1478  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1479  wxLIST_STATE_SELECTED);
1480  if (item == -1) return;
1481 
1482  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1483 
1484  if (!route) return;
1485 
1486  pRoutePropDialog = RoutePropDlgImpl::getInstance(GetParent());
1487 
1488  pRoutePropDialog->SetRouteAndUpdate(route);
1489 
1490  if (!pRoutePropDialog->IsShown()) pRoutePropDialog->Show();
1491 
1492  pRoutePropDialog->Raise();
1493 
1494  m_bNeedConfigFlush = true;
1495 }
1496 
1497 void RouteManagerDialog::OnRteZoomtoClick(wxCommandEvent &event) {
1498  // Zoom into the bounding box of the selected route
1499  long item = -1;
1500  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1501  wxLIST_STATE_SELECTED);
1502  if (item == -1) return;
1503 
1504  // optionally make this route exclusively visible
1505  if (m_bCtrlDown) MakeAllRoutesInvisible();
1506 
1507  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1508 
1509  if (!route) return;
1510 
1511  // Ensure route is visible
1512  if (!route->IsVisible()) {
1513  route->SetVisible(true);
1514  m_pRouteListCtrl->SetItemImage(item, route->IsVisible() ? 0 : 1);
1515  pConfig->UpdateRoute(route);
1516  }
1517 
1518  ZoomtoRoute(route);
1519 }
1520 
1521 void RouteManagerDialog::OnRteReverseClick(wxCommandEvent &event) {
1522  // Reverse selected route
1523  long item = -1;
1524  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1525  wxLIST_STATE_SELECTED);
1526  if (item == -1) return;
1527 
1528  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1529 
1530  if (!route) return;
1531  if (route->m_bIsInLayer) return;
1532 
1533  int ask_return = OCPNMessageBox(this, g_pRouteMan->GetRouteReverseMessage(),
1534  _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1535  if (ask_return != wxID_CANCEL) {
1536  bool rename = (ask_return == wxID_YES);
1537 
1538  pSelect->DeleteAllSelectableRouteSegments(route);
1539  route->Reverse(rename);
1540  pSelect->AddAllSelectableRouteSegments(route);
1541 
1542  // update column 2 - create a UpdateRouteItem(index) instead?
1543  wxString startend = route->m_RouteStartString;
1544  if (!route->m_RouteEndString.IsEmpty())
1545  startend.append(_(" - ") + route->m_RouteEndString);
1546  m_pRouteListCtrl->SetItem(item, 2, startend);
1547 
1548  pConfig->UpdateRoute(route);
1549  gFrame->RefreshAllCanvas();
1550  }
1551 
1552  m_bNeedConfigFlush = true;
1553 }
1554 
1555 void RouteManagerDialog::OnRteExportClick(wxCommandEvent &event) {
1556  RouteList list;
1557 
1558  wxString suggested_name = _T("routes");
1559 
1560  long item = -1;
1561  for (;;) {
1562  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1563  wxLIST_STATE_SELECTED);
1564  if (item == -1) break;
1565 
1566  Route *proute_to_export = (Route *)m_pRouteListCtrl->GetItemData(item);
1567 
1568  if (proute_to_export) {
1569  list.Append(proute_to_export);
1570  if (proute_to_export->m_RouteNameString != wxEmptyString)
1571  suggested_name = proute_to_export->m_RouteNameString;
1572  }
1573  }
1574 
1575  ExportGPXRoutes(this, &list, suggested_name);
1576 }
1577 
1578 void RouteManagerDialog::OnRteResequenceClick(wxCommandEvent &event) {
1579  long item = -1;
1580  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1581  wxLIST_STATE_SELECTED);
1582  if (item == -1) return;
1583 
1584  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1585 
1586  if (!route) return;
1587  if (route->m_bIsInLayer) return;
1588  route->RenameRoutePoints();
1589 }
1590 
1591 void RouteManagerDialog::OnRteSendToPeerClick(wxCommandEvent &event) {
1592  std::vector<Route*> list;
1593  long item = -1;
1594  for (;;) {
1595  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1596  wxLIST_STATE_SELECTED);
1597  if (item == -1) break;
1598 
1599  Route *proute = (Route *)m_pRouteListCtrl->GetItemData(item);
1600 
1601  if (proute) {
1602  list.push_back(proute);
1603  }
1604  }
1605  if (!list.empty()) {
1606  SendToPeerDlg dlg;
1607  for (auto r : list) {
1608  dlg.SetRoute(r);
1609  }
1610 
1611  // Perform initial scan, if necessary
1612 
1613  // Check for stale cache...
1614  MdnsCache::GetInstance().Validate();
1615  if (MdnsCache::GetInstance().GetCache().empty())
1616  dlg.SetScanOnCreate(true);
1617 
1618  dlg.SetScanTime(5); // seconds
1619  dlg.Create(NULL, -1, _("Send Route(s) to OpenCPN Peer") + _T( "..." ), _T(""));
1620  dlg.ShowModal();
1621  }
1622 }
1623 
1624 void RouteManagerDialog::OnWptSendToPeerClick(wxCommandEvent &event) {
1625  std::vector<RoutePoint*> list;
1626  long item = -1;
1627  for (;;) {
1628  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1629  wxLIST_STATE_SELECTED);
1630  if (item == -1) break;
1631 
1632  RoutePoint *proutep = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
1633 
1634  if (proutep) {
1635  list.push_back(proutep);
1636  }
1637  }
1638  if (!list.empty()) {
1639  SendToPeerDlg dlg;
1640  for (auto r : list) {
1641  dlg.SetWaypoint(r);
1642  }
1643 
1644  // Perform initial scan, if necessary
1645 
1646  // Check for stale cache...
1647  MdnsCache::GetInstance().Validate();
1648  if (MdnsCache::GetInstance().GetCache().empty())
1649  dlg.SetScanOnCreate(true);
1650 
1651  dlg.SetScanTime(5); // seconds
1652  dlg.Create(NULL, -1, _("Send Waypoint(s) to OpenCPN Peer") + _T( "..." ), _T(""));
1653  dlg.ShowModal();
1654  }
1655 }
1656 
1657 void RouteManagerDialog::OnTrkSendToPeerClick(wxCommandEvent &event) {
1658  std::vector<Track*> list;
1659  long item = -1;
1660  for (;;) {
1661  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1662  wxLIST_STATE_SELECTED);
1663  if (item == -1) break;
1664 
1665  Track *ptrk = (Track *)m_pTrkListCtrl->GetItemData(item);
1666 
1667  if (ptrk) {
1668  list.push_back(ptrk);
1669  }
1670  }
1671  if (!list.empty()) {
1672  SendToPeerDlg dlg;
1673  for (auto r : list) {
1674  dlg.SetTrack(r);
1675  }
1676 
1677  // Perform initial scan, if necessary
1678 
1679  // Check for stale cache...
1680  MdnsCache::GetInstance().Validate();
1681  if (MdnsCache::GetInstance().GetCache().empty())
1682  dlg.SetScanOnCreate(true);
1683 
1684  dlg.SetScanTime(5); // seconds
1685  dlg.Create(NULL, -1, _("Send Track(s) to OpenCPN Peer") + _T( "..." ), _T(""));
1686  dlg.ShowModal();
1687  }
1688 }
1689 
1690 void RouteManagerDialog::OnRteActivateClick(wxCommandEvent &event) {
1691  // Activate the selected route, unless it already is
1692  long item = -1;
1693  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1694  wxLIST_STATE_SELECTED);
1695  if (item == -1) return;
1696 
1697  if (m_bCtrlDown) MakeAllRoutesInvisible();
1698 
1699  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1700 
1701  if (!route) return;
1702 
1703  if (!route->m_bRtIsActive) {
1704  if (!route->IsVisible()) {
1705  route->SetVisible(true);
1706  m_pRouteListCtrl->SetItemImage(item, 0, 0);
1707  }
1708 
1709  ZoomtoRoute(route);
1710 
1711  RoutePoint *best_point =
1712  g_pRouteMan->FindBestActivatePoint(route, gLat, gLon, gCog, gSog);
1713  g_pRouteMan->ActivateRoute(route, best_point);
1714  // g_pRouteMan->ActivateRoute(route);
1715  } else
1716  g_pRouteMan->DeactivateRoute();
1717 
1718  UpdateRouteListCtrl();
1719 
1720  pConfig->UpdateRoute(route);
1721 
1722  gFrame->RefreshAllCanvas();
1723 
1724  // btnRteActivate->SetLabel(route->m_bRtIsActive ? _("Deactivate") :
1725  // _("Activate"));
1726 
1727  m_bNeedConfigFlush = true;
1728 }
1729 
1730 void RouteManagerDialog::OnRteToggleVisibility(wxMouseEvent &event) {
1731  wxPoint pos = event.GetPosition();
1732  int flags = 0;
1733  long clicked_index = m_pRouteListCtrl->HitTest(pos, flags);
1734 
1735  // Clicking Visibility column?
1736  if (clicked_index > -1 &&
1737  event.GetX() < m_pRouteListCtrl->GetColumnWidth(rmVISIBLE)) {
1738  // Process the clicked item
1739  Route *route = (Route *)m_pRouteListCtrl->GetItemData(clicked_index);
1740 
1741  route->SetVisible(!route->IsVisible());
1742 
1743  m_pRouteListCtrl->SetItemImage(clicked_index, route->IsVisible() ? 0 : 1);
1744 
1745  ::wxBeginBusyCursor();
1746 
1747  pConfig->UpdateRoute(route);
1748  gFrame->RefreshAllCanvas();
1749 
1750  // We need to update the waypoint list control since the visibility of
1751  // shared waypoints might have changed.
1752  if (g_pRouteMan->DoesRouteContainSharedPoints(route))
1753  UpdateWptListCtrlViz();
1754 
1755  // Manage "show all" checkbox
1756  bool viz = true;
1757  long item = -1;
1758  for (;;) {
1759  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1760  wxLIST_STATE_DONTCARE);
1761  if (item == -1) break;
1762 
1763  Route *pR = (Route *)m_pRouteListCtrl->GetItemData(item);
1764 
1765  if (!pR->IsVisible()) {
1766  viz = false;
1767  break;
1768  }
1769  }
1770  m_cbShowAllRte->SetValue(viz);
1771 
1772  ::wxEndBusyCursor();
1773  }
1774 
1775  // Allow wx to process...
1776  event.Skip();
1777 }
1778 
1779 void RouteManagerDialog::OnRteBtnLeftDown(wxMouseEvent &event) {
1780  m_bCtrlDown = event.ControlDown();
1781  event.Skip();
1782 }
1783 
1784 void RouteManagerDialog::OnRteSelected(wxListEvent &event) {
1785  long clicked_index = event.m_itemIndex;
1786  // Process the clicked item
1787  Route *route = (Route *)m_pRouteListCtrl->GetItemData(clicked_index);
1788  // route->SetVisible(!route->IsVisible());
1789  m_pRouteListCtrl->SetItemImage(clicked_index, route->IsVisible() ? 0 : 1);
1790  // pConfig->UpdateRoute(route);
1791 
1792  gFrame->RefreshAllCanvas();
1793 
1794  UpdateRteButtons();
1795 }
1796 
1797 void RouteManagerDialog::OnRteColumnClicked(wxListEvent &event) {
1798  if (event.m_col == 1) {
1799  sort_route_name_dir++;
1800 
1801  m_pRouteListCtrl->SortItems(SortRoutesOnName, (wxIntPtr)NULL);
1802  } else if (event.m_col == 2) {
1803  sort_route_to_dir++;
1804  m_pRouteListCtrl->SortItems(SortRoutesOnTo, (wxIntPtr)NULL);
1805  }
1806 }
1807 
1808 void RouteManagerDialog::OnRteSendToGPSClick(wxCommandEvent &event) {
1809  long item = -1;
1810  item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1811  wxLIST_STATE_SELECTED);
1812  if (item == -1) return;
1813 
1814  Route *route = (Route *)m_pRouteListCtrl->GetItemData(item);
1815 
1816  if (!route) return;
1817 
1818  SendToGpsDlg *pdlg = new SendToGpsDlg();
1819  pdlg->SetRoute(route);
1820 
1821  wxFont fo = GetOCPNGUIScaledFont(_T("Dialog"));
1822  pdlg->SetFont(fo);
1823 
1824  wxString source;
1825  pdlg->Create(NULL, -1, _("Send to GPS") + _T( "..." ), source);
1826 
1827 #ifdef __WXOSX__
1828  HideWithEffect(wxSHOW_EFFECT_BLEND);
1829 #endif
1830 
1831  pdlg->ShowModal();
1832 
1833 #ifdef __WXOSX__
1834  ShowWithEffect(wxSHOW_EFFECT_BLEND);
1835 #endif
1836 
1837  pdlg->Destroy();
1838 }
1839 
1840 void RouteManagerDialog::OnRteDefaultAction(wxListEvent &event) {
1841  wxCommandEvent evt;
1842  OnRtePropertiesClick(evt);
1843 }
1844 
1845 void RouteManagerDialog::OnTrkDefaultAction(wxListEvent &event) {
1846  wxCommandEvent evt;
1847  OnTrkPropertiesClick(evt);
1848 }
1849 
1850 void RouteManagerDialog::OnTrkRightClick(wxListEvent &event) {
1851  wxMenu menu;
1852  wxMenuItem *mergeItem = menu.Append(TRACK_MERGE, _("&Merge Selected Tracks"));
1853  mergeItem->Enable(m_pTrkListCtrl->GetSelectedItemCount() > 1);
1854  wxMenuItem *cleanItem = menu.Append(TRACK_CLEAN, _("Reduce Data..."));
1855  cleanItem->Enable(m_pTrkListCtrl->GetSelectedItemCount() == 1);
1856  wxMenuItem *copyItem = menu.Append(TRACK_COPY_TEXT, _("&Copy as text"));
1857  copyItem->Enable(m_pTrkListCtrl->GetSelectedItemCount() > 0);
1858  PopupMenu(&menu);
1859 }
1860 
1861 static bool CompareTracks(Track *track1, Track *track2) {
1862  TrackPoint *start1 = track1->GetPoint(0);
1863  TrackPoint *start2 = track2->GetPoint(0);
1864  return start1->GetCreateTime() < start2->GetCreateTime();
1865 }
1866 
1867 void RouteManagerDialog::OnTrkMenuSelected(wxCommandEvent &event) {
1868  int item = -1;
1869 
1870  switch (event.GetId()) {
1871  case TRACK_CLEAN: {
1872  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1873  wxLIST_STATE_SELECTED);
1874  if (item == -1) break;
1875  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
1876  if (track->IsRunning()) {
1877  wxBell();
1878  break;
1879  }
1880 
1881  const wxString choices[] = {_T("5.0"), _T("10.0"), _T("20.0"), _T("50.0"),
1882  _T("100.0")};
1883 
1884  wxSingleChoiceDialog precisionDlg(this,
1885  _("Select the maximum error allowed "
1886  "(in meters)\nafter data reduction:"),
1887  _("Reduce Data Precision"), 5, choices);
1888 #ifdef __WXOSX__
1889  precisionDlg.ShowWindowModal();
1890  while (precisionDlg.IsShown()) {
1891  wxMilliSleep(10);
1892  wxYield();
1893  }
1894  int result = precisionDlg.GetReturnCode();
1895 #else
1896  int result = precisionDlg.ShowModal();
1897 #endif
1898  if (result == wxID_CANCEL) break;
1899  double precision = 5.0;
1900  switch (precisionDlg.GetSelection()) {
1901  case 0:
1902  precision = 5.0;
1903  break;
1904  case 1:
1905  precision = 10.0;
1906  break;
1907  case 2:
1908  precision = 20.0;
1909  break;
1910  case 3:
1911  precision = 50.0;
1912  break;
1913  case 4:
1914  precision = 100.0;
1915  break;
1916  }
1917 
1918  int pointsBefore = track->GetnPoints();
1919 
1920  int reduction = track->Simplify(precision);
1921  gFrame->Refresh(false);
1922 
1923  reduction = 100 * reduction / pointsBefore;
1924  wxString msg = wxString::Format(
1925  _("The amount of data used by the track\n was reduced by %d%%."),
1926  reduction);
1927  OCPNMessageBox(this, msg, _("OpenCPN info"), wxICON_INFORMATION | wxOK);
1928 
1929  UpdateTrkListCtrl();
1930  UpdateRouteListCtrl();
1931 
1932  break;
1933  }
1934 
1935  case TRACK_COPY_TEXT: {
1936  wxString csvString;
1937  while (1) {
1938  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1939  wxLIST_STATE_SELECTED);
1940  if (item == -1) break;
1941  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
1942  csvString << track->GetName() << _T("\t")
1943  << wxString::Format(_T("%.1f"), track->Length()) << _T("\t")
1944  << _T("\n");
1945  }
1946 
1947  if (wxTheClipboard->Open()) {
1948  wxTextDataObject *data = new wxTextDataObject;
1949  data->SetText(csvString);
1950  wxTheClipboard->SetData(data);
1951  wxTheClipboard->Close();
1952  }
1953 
1954  break;
1955  }
1956 
1957  case TRACK_MERGE: {
1958  Track *targetTrack = NULL;
1959  TrackPoint *tPoint;
1960  TrackPoint *newPoint;
1961  TrackPoint *lastPoint;
1962  std::vector<Track *> mergeList;
1963  std::vector<Track *> deleteList;
1964  bool runningSkipped = false;
1965 
1966  ::wxBeginBusyCursor();
1967 
1968  while (1) {
1969  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
1970  wxLIST_STATE_SELECTED);
1971  if (item == -1) break;
1972  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
1973  mergeList.push_back(track);
1974  }
1975 
1976  std::sort(mergeList.begin(), mergeList.end(), CompareTracks);
1977 
1978  targetTrack = mergeList[0];
1979  lastPoint = targetTrack->GetLastPoint();
1980 
1981  for (auto const &mergeTrack : mergeList) {
1982  if (mergeTrack == *mergeList.begin()) continue;
1983 
1984  if (mergeTrack->IsRunning()) {
1985  runningSkipped = true;
1986  continue;
1987  }
1988 
1989  for (int i = 0; i < mergeTrack->GetnPoints(); i++) {
1990  tPoint = mergeTrack->GetPoint(i);
1991  newPoint = new TrackPoint(tPoint->m_lat, tPoint->m_lon,
1992  tPoint->GetCreateTime());
1993 
1994  targetTrack->AddPoint(newPoint);
1995 
1996  pSelect->AddSelectableTrackSegment(lastPoint->m_lat, lastPoint->m_lon,
1997  newPoint->m_lat, newPoint->m_lon,
1998  lastPoint, newPoint, targetTrack);
1999 
2000  lastPoint = newPoint;
2001  }
2002  deleteList.push_back(mergeTrack);
2003  }
2004 
2005  for (auto const &deleteTrack : deleteList) {
2006  g_pAIS->DeletePersistentTrack(deleteTrack);
2007  pConfig->DeleteConfigTrack(deleteTrack);
2008  RoutemanGui(*g_pRouteMan).DeleteTrack(deleteTrack);
2009  }
2010 
2011  mergeList.clear();
2012  deleteList.clear();
2013 
2014  ::wxEndBusyCursor();
2015 
2016  UpdateTrkListCtrl();
2017  UpdateRouteListCtrl();
2018  gFrame->RefreshAllCanvas();
2019 
2020  if (runningSkipped) {
2021  wxMessageDialog skipWarning(
2022  this,
2023  _("The currently running Track was not merged.\nYou can merge it "
2024  "later when it is completed."),
2025  _T("Warning"), wxCANCEL | wxICON_WARNING);
2026  skipWarning.ShowModal();
2027  }
2028 
2029  break;
2030  }
2031  }
2032 }
2033 
2034 void RouteManagerDialog::UpdateTrkListCtrl() {
2035  // if an item was selected, make it selected again if it still exist
2036  long item = -1;
2037  item =
2038  m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2039 
2040  wxUIntPtr selected_id = wxUIntPtr(0);
2041  if (item != -1) selected_id = m_pTrkListCtrl->GetItemData(item);
2042 
2043  // Delete existing items
2044  m_pTrkListCtrl->DeleteAllItems();
2045 
2046  // then add tracks to the listctrl
2047  std::vector<Track*>::iterator it;
2048  int index = 0;
2049  int list_index = 0;
2050  bool bpartialViz = false;
2051 
2052  for (Track *trk : g_TrackList) {
2053  if (!trk->IsVisible()) bpartialViz = true;
2054 
2055  if (!trk->IsListed()) continue;
2056 
2057  if (!trk->GetName(true).Upper().Contains(
2058  m_tFilterTrk->GetValue().Upper())) {
2059  continue;
2060  }
2061 
2062  wxListItem li;
2063  li.SetId(list_index);
2064  li.SetImage(trk->IsVisible() ? 0 : 1);
2065  li.SetData(trk);
2066  li.SetText(_T(""));
2067 
2068  if (g_pActiveTrack == trk) {
2069  wxFont font = *wxNORMAL_FONT;
2070  font.SetWeight(wxFONTWEIGHT_BOLD);
2071  li.SetFont(font);
2072  }
2073  long idx = m_pTrkListCtrl->InsertItem(li);
2074 
2075  m_pTrkListCtrl->SetItem(idx, colTRKNAME, trk->GetName(true));
2076  m_pTrkListCtrl->SetItem(idx, colTRKDATE, trk->GetDate(true));
2077 
2078  wxString len;
2079  len.Printf(wxT("%5.2f"), trk->Length());
2080  m_pTrkListCtrl->SetItem(idx, colTRKLENGTH, len);
2081 
2082  wxListItem lic;
2083  lic.SetId(list_index);
2084  lic.SetColumn(1);
2085  lic.SetAlign(wxLIST_FORMAT_LEFT);
2086  m_pTrkListCtrl->SetItem(lic);
2087 
2088  lic.SetColumn(2);
2089  lic.SetAlign(wxLIST_FORMAT_LEFT);
2090  m_pTrkListCtrl->SetItem(lic);
2091 
2092  list_index++;
2093  }
2094 
2095  switch (sort_track_key) {
2096  case SORT_ON_DISTANCE:
2097  m_pTrkListCtrl->SortItems(SortTracksOnDistance, (wxIntPtr)NULL);
2098  break;
2099  case SORT_ON_DATE:
2100  m_pTrkListCtrl->SortItems(SortTracksOnDate, (wxIntPtr)NULL);
2101  break;
2102  case SORT_ON_NAME:
2103  default:
2104  m_pTrkListCtrl->SortItems(SortTracksOnName, (wxIntPtr)NULL);
2105  break;
2106  }
2107 
2108  m_pTrkListCtrl->SetColumnWidth(0, 4 * m_charWidth);
2109 
2110  // restore selection if possible
2111  // NOTE this will select a different item, if one is deleted
2112  // (the next route will get that index).
2113  if (selected_id != wxUIntPtr(0)) {
2114  item = m_pTrkListCtrl->FindItem(-1, selected_id);
2115  m_pTrkListCtrl->SetItemState(item,
2116  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
2117  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
2118  }
2119 
2120  if ((m_lastTrkItem >= 0) && (m_pTrkListCtrl->GetItemCount()))
2121  m_pTrkListCtrl->EnsureVisible(m_lastTrkItem);
2122 
2123  m_cbShowAllTrk->SetValue(!bpartialViz);
2124  UpdateTrkButtons();
2125 }
2126 
2127 void RouteManagerDialog::OnTrkSelected(wxListEvent &event) {
2128  UpdateTrkButtons();
2129 }
2130 
2131 void RouteManagerDialog::OnTrkColumnClicked(wxListEvent &event) {
2132  if (event.m_col == 1) {
2133  sort_track_key = SORT_ON_NAME;
2134  sort_track_name_dir++;
2135  m_pTrkListCtrl->SortItems(SortTracksOnName, (wxIntPtr)NULL);
2136  } else if (event.m_col == 2) {
2137  sort_track_key = SORT_ON_DISTANCE;
2138  sort_track_len_dir++;
2139  m_pTrkListCtrl->SortItems(SortTracksOnDistance, (wxIntPtr)NULL);
2140  } else if (event.m_col == 3) {
2141  sort_track_key = SORT_ON_DATE;
2142  sort_track_date_dir++;
2143  m_pTrkListCtrl->SortItems(SortTracksOnDate, (wxIntPtr)NULL);
2144  }
2145 }
2146 
2147 void RouteManagerDialog::UpdateTrkButtons() {
2148  long item = -1;
2149  item =
2150  m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2151  int items = m_pTrkListCtrl->GetSelectedItemCount();
2152 
2153  m_lastTrkItem = item;
2154 
2155  btnTrkProperties->Enable(items == 1);
2156  btnTrkDelete->Enable(items >= 1);
2157  btnTrkExport->Enable(items >= 1);
2158  btnTrkRouteFromTrack->Enable(items == 1);
2159  btnTrkDeleteAll->Enable(m_pTrkListCtrl->GetItemCount() > 0);
2160  btnTrkSendToPeer->Enable(items >= 1);
2161 }
2162 
2163 void RouteManagerDialog::OnTrkToggleVisibility(wxMouseEvent &event) {
2164  wxPoint pos = event.GetPosition();
2165  int flags = 0;
2166  long clicked_index = m_pTrkListCtrl->HitTest(pos, flags);
2167 
2168  // Clicking Visibility column?
2169  if (clicked_index > -1 &&
2170  event.GetX() < m_pTrkListCtrl->GetColumnWidth(colTRKVISIBLE)) {
2171  // Process the clicked item
2172  Track *track = (Track *)m_pTrkListCtrl->GetItemData(clicked_index);
2173  if (track) {
2174  track->SetVisible(!track->IsVisible());
2175  m_pTrkListCtrl->SetItemImage(clicked_index, track->IsVisible() ? 0 : 1);
2176  }
2177 
2178  // Manage "show all" checkbox
2179  bool viz = true;
2180  long item = -1;
2181  for (;;) {
2182  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2183  wxLIST_STATE_DONTCARE);
2184  if (item == -1) break;
2185 
2186  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
2187 
2188  if (!track->IsVisible()) {
2189  viz = false;
2190  break;
2191  }
2192  }
2193  m_cbShowAllTrk->SetValue(viz);
2194 
2195  gFrame->RefreshAllCanvas();
2196  }
2197 
2198  // Allow wx to process...
2199  event.Skip();
2200 }
2201 
2202 void RouteManagerDialog::OnTrkNewClick(wxCommandEvent &event) {
2203  gFrame->TrackOff();
2204  if (pConfig && pConfig->IsChangesFileDirty()) {
2205  pConfig->UpdateNavObj(true);
2206  }
2207 
2208  gFrame->TrackOn();
2209 
2210  UpdateTrkListCtrl();
2211 }
2212 
2213 void RouteManagerDialog::OnTrkPropertiesClick(wxCommandEvent &event) {
2214  // Show trackproperties dialog for selected track
2215  long item = -1;
2216  item =
2217  m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2218  if (item == -1) return;
2219 
2220  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
2221 
2222  if (!track) return;
2223 
2224  pTrackPropDialog = TrackPropDlg::getInstance(GetParent());
2225  pTrackPropDialog->SetTrackAndUpdate(track);
2226 
2227  if (!pTrackPropDialog->IsShown()) pTrackPropDialog->Show();
2228  UpdateTrkListCtrl();
2229 
2230  m_bNeedConfigFlush = true;
2231 }
2232 
2233 void RouteManagerDialog::OnTrkDeleteClick(wxCommandEvent &event) {
2234  std::vector<Track*> list;
2235 
2236  int answer = OCPNMessageBox(
2237  this, _("Are you sure you want to delete the selected object(s)"),
2238  wxString(_("OpenCPN Alert")), wxYES_NO);
2239  if (answer != wxID_YES) return;
2240 
2241  bool busy = false;
2242  if (m_pTrkListCtrl->GetSelectedItemCount()) {
2243  ::wxBeginBusyCursor();
2244  m_bNeedConfigFlush = true;
2245  busy = true;
2246  }
2247 
2248  long item = -1;
2249  for (;;) {
2250  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2251  wxLIST_STATE_SELECTED);
2252  if (item == -1) break;
2253 
2254  Track *ptrack_to_delete = (Track *)m_pTrkListCtrl->GetItemData(item);
2255 
2256  if (ptrack_to_delete) list.push_back(ptrack_to_delete);
2257  }
2258 
2259  if (busy) {
2260  for (unsigned int i = 0; i < list.size(); i++) {
2261  Track *track = list.at(i);
2262  if (track) {
2263  g_pAIS->DeletePersistentTrack(track);
2264  pConfig->DeleteConfigTrack(track);
2265  RoutemanGui(*g_pRouteMan).DeleteTrack(track);
2266  }
2267  }
2268 
2269  m_lastTrkItem = -1;
2270  // UpdateRouteListCtrl();
2271  UpdateTrkListCtrl();
2272 
2273  if (pConfig && pConfig->IsChangesFileDirty()) {
2274  pConfig->UpdateNavObj(true);
2275  }
2276 
2277  gFrame->InvalidateAllCanvasUndo();
2278  gFrame->RefreshAllCanvas();
2279  ::wxEndBusyCursor();
2280  }
2281 }
2282 
2283 void RouteManagerDialog::OnTrkExportClick(wxCommandEvent &event) {
2284  std::vector<Track*> list;
2285  wxString suggested_name = _T("tracks");
2286 
2287  long item = -1;
2288  for (;;) {
2289  item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2290  wxLIST_STATE_SELECTED);
2291  if (item == -1) break;
2292 
2293  Track *ptrack_to_export = (Track *)m_pTrkListCtrl->GetItemData(item);
2294 
2295  if (ptrack_to_export) {
2296  list.push_back(ptrack_to_export);
2297  if (ptrack_to_export->GetName() != wxEmptyString)
2298  suggested_name = ptrack_to_export->GetName();
2299  }
2300  }
2301 
2302  ExportGPXTracks(this, &list, suggested_name);
2303 }
2304 
2305 void RouteManagerDialog::TrackToRoute(Track *track) {
2306  if (!track) return;
2307  if (track->m_bIsInLayer) return;
2308 
2309  wxGenericProgressDialog pprog(_("OpenCPN Converting Track to Route...."),
2310  _("Processing Waypoints..."), 101, NULL,
2311  wxPD_AUTO_HIDE | wxPD_SMOOTH |
2312  wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
2313  wxPD_REMAINING_TIME);
2314 
2315  ::wxBeginBusyCursor();
2316 
2317  Route *route = track->RouteFromTrack(&pprog);
2318 
2319  pRouteList->Append(route);
2320 
2321  pprog.Update(101, _("Done."));
2322 
2323  gFrame->RefreshAllCanvas();
2324 
2325  ::wxEndBusyCursor();
2326 }
2327 
2328 void RouteManagerDialog::OnTrkRouteFromTrackClick(wxCommandEvent &event) {
2329  long item = -1;
2330  item =
2331  m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2332  if (item == -1) return;
2333 
2334  Track *track = (Track *)m_pTrkListCtrl->GetItemData(item);
2335 
2336  TrackToRoute(track);
2337 
2338  UpdateRouteListCtrl();
2339 }
2340 
2341 void RouteManagerDialog::OnTrkDeleteAllClick(wxCommandEvent &event) {
2342  int dialog_ret =
2343  OCPNMessageBox(this, _("Are you sure you want to delete <ALL> tracks?"),
2344  wxString(_("OpenCPN Alert")), wxYES_NO);
2345 
2346  if (dialog_ret == wxID_YES) {
2347  RoutemanGui(*g_pRouteMan).DeleteAllTracks();
2348  }
2349 
2350  m_lastTrkItem = -1;
2351  m_lastRteItem = -1;
2352 
2353  UpdateTrkListCtrl();
2354 
2355  // Also need to update the route list control, since routes and tracks
2356  // share a common global list (pRouteList)
2357  UpdateRouteListCtrl();
2358 
2359  if (pRoutePropDialog) pRoutePropDialog->Hide();
2360 
2361  gFrame->RefreshAllCanvas();
2362 
2363  m_bNeedConfigFlush = true;
2364 }
2365 
2366 void RouteManagerDialog::UpdateWptListCtrl(RoutePoint *rp_select,
2367  bool b_retain_sort) {
2368  wxIntPtr selected_id = wxUIntPtr(0);
2369  long item = -1;
2370 
2371  if (NULL == rp_select) {
2372  // if an item was selected, make it selected again if it still exists
2373  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2374  wxLIST_STATE_SELECTED);
2375 
2376  if (item != -1) selected_id = m_pWptListCtrl->GetItemData(item);
2377  }
2378 
2379  // Freshen the image list
2380  m_pWptListCtrl->SetImageList(
2381  pWayPointMan->Getpmarkicon_image_list(m_listIconSize),
2382  wxIMAGE_LIST_SMALL);
2383 
2384  m_pWptListCtrl->DeleteAllItems();
2385 
2386  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
2387 
2388  int index = 0;
2389  bool b_anyHidden = false;
2390  while (node) {
2391  RoutePoint *rp = node->GetData();
2392  if (rp && rp->IsListed()) {
2393  if (rp->m_bIsInRoute && !rp->IsShared()) {
2394  node = node->GetNext();
2395  continue;
2396  }
2397 
2398  if (!rp->GetName().Upper().Contains(m_tFilterWpt->GetValue().Upper())) {
2399  node = node->GetNext();
2400  continue;
2401  }
2402 
2403  wxListItem li;
2404  li.SetId(index);
2405  li.SetImage(RoutePointGui(*rp).GetIconImageIndex());
2406  li.SetData(rp);
2407  li.SetText(_T(""));
2408  long idx = m_pWptListCtrl->InsertItem(li);
2409 
2410  wxString scamin = wxString::Format(_T("%i"), (int)rp->GetScaMin());
2411  if (!rp->GetUseSca()) scamin = _("Always");
2412  if (g_bOverruleScaMin) scamin = _("Overruled");
2413  m_pWptListCtrl->SetItem(idx, colWPTSCALE, scamin);
2414 
2415  wxString name = rp->GetName();
2416  if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
2417  m_pWptListCtrl->SetItem(idx, colWPTNAME, name);
2418 
2419  double dst;
2420  DistanceBearingMercator(rp->m_lat, rp->m_lon, gLat, gLon, NULL, &dst);
2421  wxString dist;
2422  dist.Printf(_T("%5.2f ") + getUsrDistanceUnit(), toUsrDistance(dst));
2423  m_pWptListCtrl->SetItem(idx, colWPTDIST, dist);
2424 
2425  if (rp == rp_select) selected_id = (wxIntPtr)rp_select;
2426 
2427  wxListItem lic;
2428  lic.SetId(index);
2429  lic.SetColumn(1);
2430  lic.SetAlign(wxLIST_FORMAT_LEFT);
2431  m_pWptListCtrl->SetItem(lic);
2432 
2433  lic.SetColumn(2);
2434  lic.SetAlign(wxLIST_FORMAT_LEFT);
2435  m_pWptListCtrl->SetItem(lic);
2436 
2437  if (!rp->IsVisible()) b_anyHidden = true;
2438 
2439  index++;
2440  }
2441 
2442  node = node->GetNext();
2443  }
2444 
2445  if (!b_retain_sort) {
2446  m_pWptListCtrl->SortItems(SortWaypointsOnName,
2447  reinterpret_cast<wxIntPtr>(m_pWptListCtrl));
2448  sort_wp_key = SORT_ON_NAME;
2449  } else {
2450  switch (sort_wp_key) {
2451  case SORT_ON_NAME:
2452  m_pWptListCtrl->SortItems(SortWaypointsOnName,
2453  reinterpret_cast<wxIntPtr>(m_pWptListCtrl));
2454  break;
2455  case SORT_ON_DISTANCE:
2456  m_pWptListCtrl->SortItems(SortWaypointsOnDistance,
2457  reinterpret_cast<wxIntPtr>(m_pWptListCtrl));
2458  break;
2459  }
2460  }
2461 
2462  if (selected_id != wxUIntPtr(0)) {
2463  item = m_pWptListCtrl->FindItem(-1, selected_id);
2464  m_pWptListCtrl->SetItemState(item,
2465  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
2466  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
2467  }
2468 
2469  if ((m_lastWptItem >= 0) && (m_pWptListCtrl->GetItemCount()))
2470  m_pWptListCtrl->EnsureVisible(m_lastWptItem);
2471 
2472  if (pWayPointMan->Getpmarkicon_image_list(m_listIconSize)->GetImageCount()) {
2473  int iwidth, iheight;
2474  pWayPointMan->Getpmarkicon_image_list(m_listIconSize)
2475  ->GetSize(0, iwidth, iheight);
2476 
2477  m_pWptListCtrl->SetColumnWidth(0, wxMax(iwidth + 4, 4 * m_charWidth));
2478  }
2479 
2480  UpdateWptButtons();
2481 
2482  m_cbShowAllWP->SetValue(!b_anyHidden);
2483 }
2484 
2485 void RouteManagerDialog::UpdateWptListCtrlViz() {
2486  long item = -1;
2487  for (;;) {
2488  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2489  wxLIST_STATE_DONTCARE);
2490  if (item == -1) break;
2491 
2492  RoutePoint *pRP = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2493  int imageIndex = RoutePointGui(*pRP).GetIconImageIndex();
2494 
2495  m_pWptListCtrl->SetItemImage(item, imageIndex);
2496  }
2497 }
2498 
2499 void RouteManagerDialog::OnWptDefaultAction(wxListEvent &event) {
2500  wxCommandEvent evt;
2501  OnWptPropertiesClick(evt);
2502 }
2503 
2504 void RouteManagerDialog::OnWptSelected(wxListEvent &event) {
2505  UpdateWptButtons();
2506 }
2507 
2508 void RouteManagerDialog::OnWptColumnClicked(wxListEvent &event) {
2509  if (event.m_col == NAME_COLUMN) {
2510  sort_wp_name_dir++;
2511  m_pWptListCtrl->SortItems(SortWaypointsOnName,
2512  reinterpret_cast<wxIntPtr>(m_pWptListCtrl));
2513  sort_wp_key = SORT_ON_NAME;
2514  } else {
2515  if (event.m_col == DISTANCE_COLUMN) {
2516  sort_wp_len_dir++;
2517  m_pWptListCtrl->SortItems(SortWaypointsOnDistance,
2518  reinterpret_cast<wxIntPtr>(m_pWptListCtrl));
2519  sort_wp_key = SORT_ON_DISTANCE;
2520  }
2521  }
2522  UpdateWptListCtrl();
2523 }
2524 
2525 void RouteManagerDialog::UpdateWptButtons() {
2526  long item = -1;
2527  item =
2528  m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2529  bool enable1 = (m_pWptListCtrl->GetSelectedItemCount() == 1);
2530  bool enablemultiple = (m_pWptListCtrl->GetSelectedItemCount() >= 1);
2531 
2532  if (enable1)
2533  m_lastWptItem = item;
2534  else
2535  m_lastWptItem = -1;
2536 
2537  // Check selection to see if it is in a layer
2538  // If so, disable the "delete" button
2539  bool b_delete_enable = true;
2540  item = -1;
2541  for (;;) {
2542  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2543  wxLIST_STATE_SELECTED);
2544  if (item == -1) break;
2545 
2546  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2547 
2548  if (wp && wp->m_bIsInLayer) {
2549  b_delete_enable = false;
2550  break;
2551  }
2552  }
2553 
2554  btnWptProperties->Enable(enablemultiple);
2555  btnWptZoomto->Enable(enable1);
2556  btnWptDeleteAll->Enable(m_pWptListCtrl->GetItemCount() > 0);
2557  btnWptDelete->Enable(b_delete_enable && enablemultiple);
2558  btnWptGoTo->Enable(enable1);
2559  btnWptExport->Enable(enablemultiple);
2560  btnWptSendToGPS->Enable(enable1);
2561  btnWptSendToPeer->Enable(enablemultiple);
2562 }
2563 
2564 void RouteManagerDialog::OnWptToggleVisibility(wxMouseEvent &event) {
2565  wxPoint pos = event.GetPosition();
2566  int flags = 0;
2567  long clicked_index = m_pWptListCtrl->HitTest(pos, flags);
2568 
2569  // Clicking Visibility column?
2570  if (clicked_index > -1 &&
2571  event.GetX() < m_pWptListCtrl->GetColumnWidth(colTRKVISIBLE)) {
2572  // Process the clicked item
2573  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(clicked_index);
2574 
2575  if (!wp->IsSharedInVisibleRoute()) {
2576  wp->SetVisible(!wp->IsVisible());
2577  m_pWptListCtrl->SetItemImage(clicked_index, RoutePointGui(*wp).GetIconImageIndex());
2578 
2579  pConfig->UpdateWayPoint(wp);
2580  }
2581 
2582  // Manage "show all" checkbox
2583  bool viz = true;
2584  long item = -1;
2585  for (;;) {
2586  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2587  wxLIST_STATE_DONTCARE);
2588  if (item == -1) break;
2589 
2590  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2591 
2592  if (!wp->IsVisible()) {
2593  viz = false;
2594  break;
2595  }
2596  }
2597  m_cbShowAllWP->SetValue(viz);
2598 
2599  gFrame->RefreshAllCanvas();
2600  } else // clicked on ScaMin column??
2601  if (clicked_index > -1 &&
2602  event.GetX() > m_pWptListCtrl->GetColumnWidth(colTRKVISIBLE) &&
2603  event.GetX() < (m_pWptListCtrl->GetColumnWidth(colTRKVISIBLE) +
2604  m_pWptListCtrl->GetColumnWidth(colWPTSCALE)) &&
2605  !g_bOverruleScaMin) {
2606  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(clicked_index);
2607  wp->SetUseSca(!wp->GetUseSca());
2608  pConfig->UpdateWayPoint(wp);
2609  gFrame->RefreshAllCanvas();
2610  wxString scamin = wxString::Format(_T("%i"), (int)wp->GetScaMin());
2611  if (!wp->GetUseSca()) scamin = _("Always");
2612  m_pWptListCtrl->SetItem(clicked_index, colWPTSCALE, scamin);
2613  }
2614 
2615  // Allow wx to process...
2616  event.Skip();
2617 }
2618 
2619 void RouteManagerDialog::OnWptNewClick(wxCommandEvent &event) {
2620  RoutePoint *pWP = new RoutePoint(gLat, gLon, g_default_wp_icon, wxEmptyString,
2621  wxEmptyString);
2622  pWP->m_bIsolatedMark = true; // This is an isolated mark
2623  pSelect->AddSelectableRoutePoint(gLat, gLon, pWP);
2624  pConfig->AddNewWayPoint(pWP, -1); // use auto next num
2625  gFrame->RefreshAllCanvas();
2626 
2627  // g_pMarkInfoDialog = MarkInfoImpl::getInstance( GetParent() );
2628  if (!g_pMarkInfoDialog) // There is one global instance of the MarkProp
2629  // Dialog
2630  g_pMarkInfoDialog = new MarkInfoDlg(GetParent());
2631 
2632  WptShowPropertiesDialog(std::vector<RoutePoint*> {pWP}, GetParent());
2633 }
2634 
2635 void RouteManagerDialog::OnWptPropertiesClick(wxCommandEvent &event) {
2636  std::vector<RoutePoint *> wptlist;
2637  long item = wxNOT_FOUND;
2638  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2639  while (item != wxNOT_FOUND)
2640  {
2641  auto wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2642  if (wp) {
2643  wptlist.push_back(wp);
2644  }
2645  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2646  }
2647 
2648  if (wptlist.size() == 0) return;
2649 
2650  WptShowPropertiesDialog(wptlist, GetParent());
2651 
2652  UpdateWptListCtrl();
2653  m_bNeedConfigFlush = true;
2654 }
2655 
2656 void RouteManagerDialog::WptShowPropertiesDialog(std::vector<RoutePoint *> wptlist,
2657  wxWindow *parent) {
2658  if (!g_pMarkInfoDialog) // There is one global instance of the MarkProp
2659  // Dialog
2660  g_pMarkInfoDialog = new MarkInfoDlg(parent);
2661 
2662  g_pMarkInfoDialog->SetRoutePoints(wptlist);
2663  g_pMarkInfoDialog->UpdateProperties();
2664 
2665  wxString base_title = _("Mark Properties");
2666  if (wptlist[0]->m_bIsInRoute)
2667  base_title = _("Waypoint Properties");
2668 
2669  if (wptlist[0]->m_bIsInLayer) {
2670  wxString caption(wxString::Format(_T("%s, %s: %s"),
2671  base_title, _("Layer"),
2672  GetLayerName(wptlist[0]->m_LayerID)));
2673  g_pMarkInfoDialog->SetDialogTitle(caption);
2674  } else {
2675  if (wptlist.size() > 1)
2676  g_pMarkInfoDialog->SetDialogTitle(base_title + wxString::Format(_(" (%lu points)"), wptlist.size()));
2677  else
2678  g_pMarkInfoDialog->SetDialogTitle(base_title);
2679  }
2680 
2681  if (!g_pMarkInfoDialog->IsShown()) g_pMarkInfoDialog->Show();
2682  g_pMarkInfoDialog->Raise();
2683 }
2684 
2685 void RouteManagerDialog::OnWptZoomtoClick(wxCommandEvent &event) {
2686  long item = -1;
2687  item =
2688  m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2689  if (item == -1) return;
2690 
2691  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2692 
2693  if (!wp) return;
2694 
2695  if (gFrame->GetFocusCanvas()) {
2696  gFrame->JumpToPosition(gFrame->GetFocusCanvas(), wp->m_lat, wp->m_lon,
2697  gFrame->GetFocusCanvas()->GetVPScale());
2698  }
2699 }
2700 
2701 void RouteManagerDialog::OnWptDeleteClick(wxCommandEvent &event) {
2702  RoutePointList list;
2703 
2704  int answer = OCPNMessageBox(
2705  this, _("Are you sure you want to delete the selected object(s)"),
2706  wxString(_("OpenCPN Alert")), wxYES_NO);
2707  if (answer != wxID_YES) return;
2708 
2709  bool busy = false;
2710  if (m_pWptListCtrl->GetSelectedItemCount()) {
2711  ::wxBeginBusyCursor();
2712  m_bNeedConfigFlush = true;
2713  busy = true;
2714  }
2715 
2716  long item = -1;
2717  long item_last_selected = -1;
2718  for (;;) {
2719  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2720  wxLIST_STATE_SELECTED);
2721  if (item == -1) break;
2722 
2723  item_last_selected = item;
2724  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2725 
2726  if (wp && !wp->m_bIsInLayer) list.Append(wp);
2727  }
2728 
2729  if (busy) {
2730  for (unsigned int i = 0; i < list.GetCount(); i++) {
2731  RoutePoint *wp = list.Item(i)->GetData();
2732  if (wp) {
2733  if (wp->m_bIsInRoute) {
2734  if (wxID_YES ==
2735  OCPNMessageBox(this,
2736  _("The waypoint you want to delete is used in a "
2737  "route, do you really want to delete it?"),
2738  _("OpenCPN Alert"), wxYES_NO))
2739  pWayPointMan->DestroyWaypoint(wp);
2740  } else
2741  pWayPointMan->DestroyWaypoint(wp);
2742  }
2743  }
2744 
2745  long item_next =
2746  m_pWptListCtrl->GetNextItem(item_last_selected); // next in list
2747  RoutePoint *wp_next = NULL;
2748  if (item_next > -1)
2749  wp_next = (RoutePoint *)m_pWptListCtrl->GetItemData(item_next);
2750 
2751  m_lastWptItem = item_next;
2752 
2753  UpdateRouteListCtrl();
2754  UpdateTrkListCtrl();
2755  UpdateWptListCtrl(wp_next, true);
2756 
2757  if (g_pMarkInfoDialog) {
2758  g_pMarkInfoDialog->ClearData();
2759  }
2760 
2761  gFrame->InvalidateAllCanvasUndo();
2762  gFrame->RefreshAllCanvas();
2763  ::wxEndBusyCursor();
2764  }
2765 }
2766 
2767 void RouteManagerDialog::OnWptGoToClick(wxCommandEvent &event) {
2768  long item = -1;
2769  item =
2770  m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2771  if (item == -1) return;
2772 
2773  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2774 
2775  if (!wp) return;
2776 
2777  RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
2778  wxEmptyString, wxEmptyString);
2779  pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
2780 
2781  Route *temp_route = new Route();
2782  pRouteList->Append(temp_route);
2783 
2784  temp_route->AddPoint(pWP_src);
2785  temp_route->AddPoint(wp);
2786 
2787  pSelect->AddSelectableRouteSegment(gLat, gLon, wp->m_lat, wp->m_lon, pWP_src,
2788  wp, temp_route);
2789 
2790  wxString name = wp->GetName();
2791  if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
2792  wxString rteName = _("Go to ");
2793  rteName.Append(name);
2794  temp_route->m_RouteNameString = rteName;
2795  temp_route->m_RouteStartString = _("Here");
2796 
2797  temp_route->m_RouteEndString = name;
2798  temp_route->m_bDeleteOnArrival = true;
2799 
2800  if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
2801 
2802  g_pRouteMan->ActivateRoute(temp_route, wp);
2803 
2804  UpdateRouteListCtrl();
2805 }
2806 
2807 void RouteManagerDialog::OnWptExportClick(wxCommandEvent &event) {
2808  RoutePointList list;
2809 
2810  wxString suggested_name = _T("waypoints");
2811 
2812  long item = -1;
2813  for (;;) {
2814  item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2815  wxLIST_STATE_SELECTED);
2816  if (item == -1) break;
2817 
2818  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2819 
2820  if (wp && !wp->m_bIsInLayer) {
2821  list.Append(wp);
2822  if (wp->GetName() != wxEmptyString) suggested_name = wp->GetName();
2823  }
2824  }
2825 
2826  ExportGPXWaypoints(this, &list, suggested_name);
2827 }
2828 
2829 void RouteManagerDialog::OnWptSendToGPSClick(wxCommandEvent &event) {
2830  long item = -1;
2831  item =
2832  m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2833  if (item == -1) return;
2834 
2835  RoutePoint *wp = (RoutePoint *)m_pWptListCtrl->GetItemData(item);
2836 
2837  if (!wp) return;
2838 
2839  SendToGpsDlg *pdlg = new SendToGpsDlg();
2840  pdlg->SetWaypoint(wp);
2841 
2842  wxString source;
2843  pdlg->Create(NULL, -1, _("Send to GPS") + _T( "..." ), source);
2844 
2845 #ifdef __WXOSX__
2846  HideWithEffect(wxSHOW_EFFECT_BLEND);
2847 #endif
2848  pdlg->ShowModal();
2849 #ifdef __WXOSX__
2850  ShowWithEffect(wxSHOW_EFFECT_BLEND);
2851 #endif
2852 
2853  delete pdlg;
2854 }
2855 
2856 void RouteManagerDialog::OnWptDeleteAllClick(wxCommandEvent &event) {
2857  wxString prompt;
2858  int buttons, type;
2859  if (!pWayPointMan->SharedWptsExist()) {
2860  prompt = _("Are you sure you want to delete <ALL> waypoints?");
2861  buttons = wxYES_NO;
2862  type = 1;
2863  } else {
2864  prompt =
2865  _("There are some waypoints used in routes or anchor alarms.\n Do you "
2866  "want to delete them as well?\n This will change the routes and "
2867  "disable the anchor alarms.\n Answering No keeps the waypoints used "
2868  "in routes or alarms.");
2869  buttons = wxYES_NO | wxCANCEL;
2870  type = 2;
2871  }
2872  int answer =
2873  OCPNMessageBox(this, prompt, wxString(_("OpenCPN Alert")), buttons);
2874  if (answer == wxID_YES) pWayPointMan->DeleteAllWaypoints(true);
2875  if (answer == wxID_NO && type == 2)
2876  pWayPointMan->DeleteAllWaypoints(false); // only delete unused waypoints
2877 
2878  if (g_pMarkInfoDialog) {
2879  g_pMarkInfoDialog->ClearData();
2880  }
2881 
2882  m_lastWptItem = -1;
2883  UpdateRouteListCtrl();
2884  UpdateWptListCtrl();
2885  gFrame->InvalidateAllCanvasUndo();
2886  gFrame->RefreshAllCanvas();
2887 }
2888 
2889 void RouteManagerDialog::OnLaySelected(wxListEvent &event) {
2890  UpdateLayButtons();
2891 }
2892 
2893 void RouteManagerDialog::OnLayColumnClicked(wxListEvent &event) {
2894  if (event.m_col == 1) {
2895  sort_layer_name_dir++;
2896  m_pLayListCtrl->SortItems(SortLayersOnName, (wxIntPtr)NULL);
2897  } else if (event.m_col == 2) {
2898  sort_layer_len_dir++;
2899  m_pLayListCtrl->SortItems(SortLayersOnSize, (wxIntPtr)NULL);
2900  }
2901 }
2902 
2903 void RouteManagerDialog::UpdateLayButtons() {
2904  long item = -1;
2905  item =
2906  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2907  bool enable = (item != -1);
2908 
2909  // btnLayProperties->Enable(false);
2910  btnLayDelete->Enable(enable);
2911  cbLayToggleChart->Enable(enable);
2912  cbLayToggleListing->Enable(enable);
2913  cbLayToggleNames->Enable(enable);
2914 
2915  if (item >= 0) {
2916  cbLayToggleChart->SetValue(
2917  ((Layer *)m_pLayListCtrl->GetItemData(item))->IsVisibleOnChart());
2918 
2919  cbLayToggleNames->Set3StateValue(
2920  ((Layer *)m_pLayListCtrl->GetItemData(item))->HasVisibleNames());
2921 
2922  cbLayToggleListing->SetValue(
2923  ((Layer *)m_pLayListCtrl->GetItemData(item))->IsVisibleOnListing());
2924 
2925  } else {
2926  cbLayToggleChart->SetValue(true);
2927  cbLayToggleNames->Set3StateValue(wxCHK_UNDETERMINED);
2928  cbLayToggleListing->SetValue(true);
2929  }
2930 }
2931 
2932 void RouteManagerDialog::OnLayToggleVisibility(wxMouseEvent &event) {
2933  wxPoint pos = event.GetPosition();
2934  int flags = 0;
2935  long clicked_index = m_pLayListCtrl->HitTest(pos, flags);
2936 
2937  // Clicking Visibility column?
2938  if (clicked_index > -1 &&
2939  event.GetX() < m_pLayListCtrl->GetColumnWidth(colLAYVISIBLE)) {
2940  // Process the clicked item
2941  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(clicked_index);
2942 
2943  layer->SetVisibleOnChart(!layer->IsVisibleOnChart());
2944  m_pLayListCtrl->SetItemImage(clicked_index,
2945  layer->IsVisibleOnChart() ? 0 : 1);
2946 
2947  // Manage "show all" checkbox
2948  bool viz = true;
2949  long item = -1;
2950  for (;;) {
2951  item = m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
2952  wxLIST_STATE_DONTCARE);
2953  if (item == -1) break;
2954 
2955  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
2956 
2957  if (!layer->IsVisibleOnChart()) {
2958  viz = false;
2959  break;
2960  }
2961  }
2962  m_cbShowAllLay->SetValue(viz);
2963 
2964  ToggleLayerContentsOnChart(layer);
2965  }
2966 
2967  // Allow wx to process...
2968  event.Skip();
2969 }
2970 
2971 void RouteManagerDialog::UpdateLists() {
2972  UpdateRouteListCtrl();
2973  UpdateTrkListCtrl();
2974  UpdateWptListCtrl();
2975  UpdateLayListCtrl();
2976 }
2977 
2978 void RouteManagerDialog::OnLayNewClick(wxCommandEvent &event) {
2979  AddNewLayer(false); // Temporary layer
2980 }
2981 
2982 void RouteManagerDialog::OnPerLayNewClick(wxCommandEvent &event) {
2983  AddNewLayer(true); // Persistent layer
2984 }
2985 
2986 void RouteManagerDialog::AddNewLayer(bool isPersistent) {
2987  bool show_flag = g_bShowLayers;
2988  g_bShowLayers = true;
2989 
2990  UI_ImportGPX(this, true, _T(""), true, isPersistent);
2991 
2992  g_bShowLayers = show_flag;
2993  UpdateLists();
2994  gFrame->RefreshAllCanvas();
2995 }
2996 
2997 void RouteManagerDialog::OnLayPropertiesClick(wxCommandEvent &event) {
2998  // Show layer properties dialog for selected layer - todo
2999  long item = -1;
3000  item =
3001  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3002  if (item == -1) return;
3003 }
3004 
3005 void RouteManagerDialog::OnLayDeleteClick(wxCommandEvent &event) {
3006  long item = -1;
3007  item =
3008  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3009  if (item == -1) return;
3010 
3011  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
3012 
3013  if (!layer) return;
3014  // Check if this file is a persistent layer.
3015  // If added in this session the listctrl file path is origin dir and not yet
3016  // /layers
3017  bool ispers = false;
3018  wxString destf, f, name, ext;
3019  f = layer->m_LayerFileName;
3020  wxFileName::SplitPath(f, NULL, NULL, &name, &ext);
3021  destf = g_Platform->GetPrivateDataDir();
3022  appendOSDirSlash(&destf);
3023  destf.Append(_T("layers"));
3024  appendOSDirSlash(&destf);
3025  destf << name << _T(".") << ext;
3026 
3027  wxString prompt = _(
3028  "Are you sure you want to delete this layer and <ALL> of its contents?");
3029  if (wxFileExists(destf)) {
3030  prompt.Append(_T("\n"));
3031  prompt.Append(
3032  _("The file will also be deleted from OpenCPN's layer directory."));
3033  prompt.Append(_T("\n (") + destf + _T(")" ));
3034  ispers = true;
3035  }
3036  int answer =
3037  OCPNMessageBox(this, prompt, wxString(_("OpenCPN Alert")), wxYES_NO);
3038  if (answer == wxID_NO) return;
3039 
3040  // Delete a persistent layer file if present
3041  if (ispers) {
3042  wxString remMSG;
3043  if (wxRemoveFile(destf))
3044  remMSG.sprintf(_T("Layer file: %s is deleted"), destf);
3045  else
3046  remMSG.sprintf(_T("Error deleting Layer file: %s"), destf);
3047 
3048  wxLogMessage(remMSG);
3049  }
3050 
3051  // Process Tracks and Routes in this layer
3052  wxRouteListNode *node1 = pRouteList->GetFirst();
3053  while (node1) {
3054  Route *pRoute = node1->GetData();
3055  wxRouteListNode *next_node = node1->GetNext();
3056  if (pRoute->m_bIsInLayer && (pRoute->m_LayerID == layer->m_LayerID)) {
3057  pRoute->m_bIsInLayer = false;
3058  pRoute->m_LayerID = 0;
3059  g_pRouteMan->DeleteRoute(pRoute, NavObjectChanges::getInstance());
3060  }
3061  node1 = next_node;
3062  }
3063 
3064  for (Track *pTrack : g_TrackList) {
3065  if (pTrack->m_bIsInLayer && (pTrack->m_LayerID == layer->m_LayerID)) {
3066  pTrack->m_bIsInLayer = false;
3067  pTrack->m_LayerID = 0;
3068  RoutemanGui(*g_pRouteMan).DeleteTrack(pTrack);
3069  }
3070  }
3071 
3072  // Process waypoints in this layer
3073  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3074  wxRoutePointListNode *node3;
3075 
3076  while (node) {
3077  node3 = node->GetNext();
3078  RoutePoint *rp = node->GetData();
3079  if (rp && (rp->m_LayerID == layer->m_LayerID)) {
3080  rp->m_bIsInLayer = false;
3081  rp->m_LayerID = 0;
3082  pWayPointMan->DestroyWaypoint(
3083  rp, false); // no need to update the change set on layer ops
3084  }
3085 
3086  node = node3;
3087  node3 = NULL;
3088  }
3089 
3090  if (g_pMarkInfoDialog) {
3091  g_pMarkInfoDialog->ClearData();
3092  }
3093 
3094  pLayerList->DeleteObject(layer);
3095 
3096  UpdateLists();
3097 
3098  gFrame->RefreshAllCanvas();
3099 
3100  m_bNeedConfigFlush = false;
3101 }
3102 
3103 void RouteManagerDialog::OnLayToggleChartClick(wxCommandEvent &event) {
3104  // Toggle visibility on chart for selected layer
3105  long item = -1;
3106  item =
3107  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3108  if (item == -1) return;
3109 
3110  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
3111 
3112  if (!layer) return;
3113 
3114  layer->SetVisibleOnChart(!layer->IsVisibleOnChart());
3115  m_pLayListCtrl->SetItemImage(item, layer->IsVisibleOnChart() ? 0 : 1);
3116 
3117  ToggleLayerContentsOnChart(layer);
3118 }
3119 
3120 void RouteManagerDialog::ToggleLayerContentsOnChart(Layer *layer) {
3121  // Process Tracks and Routes in this layer
3122  wxRouteListNode *node1 = pRouteList->GetFirst();
3123  while (node1) {
3124  Route *pRoute = node1->GetData();
3125  if (pRoute->m_bIsInLayer && (pRoute->m_LayerID == layer->m_LayerID)) {
3126  pRoute->SetVisible(layer->IsVisibleOnChart());
3127  }
3128  node1 = node1->GetNext();
3129  }
3130 
3131  for (Track* pTrack : g_TrackList) {
3132  if (pTrack->m_bIsInLayer && (pTrack->m_LayerID == layer->m_LayerID))
3133  pTrack->SetVisible(layer->IsVisibleOnChart());
3134  }
3135 
3136  // Process waypoints in this layer
3137  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3138 
3139  while (node) {
3140  RoutePoint *rp = node->GetData();
3141  if (rp && (rp->m_LayerID == layer->m_LayerID)) {
3142  rp->SetVisible(layer->IsVisibleOnChart());
3143  }
3144 
3145  node = node->GetNext();
3146  }
3147  UpdateLists();
3148 
3149  UpdateLayButtons();
3150 
3151  gFrame->RefreshAllCanvas();
3152 }
3153 
3154 void RouteManagerDialog::OnLayToggleNamesClick(wxCommandEvent &event) {
3155  // Toggle WPT names visibility on chart for selected layer
3156  long item = -1;
3157  item =
3158  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3159  if (item == -1) return;
3160 
3161  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
3162 
3163  if (!layer) return;
3164 
3165  layer->SetVisibleNames(cbLayToggleNames->Get3StateValue());
3166 
3167  ToggleLayerContentsNames(layer);
3168 }
3169 
3170 void RouteManagerDialog::ToggleLayerContentsNames(Layer *layer) {
3171  // Process Tracks and Routes in this layer
3172  wxRouteListNode *node1 = pRouteList->GetFirst();
3173  while (node1) {
3174  Route *pRoute = node1->GetData();
3175  if (pRoute->m_bIsInLayer && (pRoute->m_LayerID == layer->m_LayerID)) {
3176  wxRoutePointListNode *node = pRoute->pRoutePointList->GetFirst();
3177  RoutePoint *prp1 = node->GetData();
3178  while (node) {
3179  if (layer->HasVisibleNames() == wxCHK_UNDETERMINED) {
3180  prp1->m_bShowName = prp1->m_bShowNameData;
3181  } else {
3182  prp1->m_bShowName = (layer->HasVisibleNames() == wxCHK_CHECKED);
3183  }
3184  node = node->GetNext();
3185  }
3186  }
3187  node1 = node1->GetNext();
3188  }
3189 
3190  // Process waypoints in this layer
3191  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3192 
3193  while (node) {
3194  RoutePoint *rp = node->GetData();
3195  if (rp && (rp->m_LayerID == layer->m_LayerID)) {
3196  rp->SetNameShown(layer->HasVisibleNames() == wxCHK_CHECKED ||
3197  (rp->m_bShowNameData &&
3198  layer->HasVisibleNames() == wxCHK_UNDETERMINED));
3199  }
3200 
3201  node = node->GetNext();
3202  }
3203 
3204  UpdateLayButtons();
3205 
3206  gFrame->RefreshAllCanvas();
3207 }
3208 
3209 void RouteManagerDialog::OnLayToggleListingClick(wxCommandEvent &event) {
3210  // Toggle visibility on listing for selected layer
3211  long item = -1;
3212  item =
3213  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3214  if (item == -1) return;
3215 
3216  Layer *layer = (Layer *)m_pLayListCtrl->GetItemData(item);
3217 
3218  if (!layer) return;
3219 
3220  layer->SetVisibleOnListing(!layer->IsVisibleOnListing());
3221 
3222  ToggleLayerContentsOnListing(layer);
3223 }
3224 
3225 void RouteManagerDialog::ToggleLayerContentsOnListing(Layer *layer) {
3226  ::wxBeginBusyCursor();
3227 
3228  // Process Tracks and Routes in this layer
3229  wxRouteListNode *node1 = pRouteList->GetFirst();
3230  while (node1) {
3231  Route *pRoute = node1->GetData();
3232  if (pRoute->m_bIsInLayer && (pRoute->m_LayerID == layer->m_LayerID)) {
3233  pRoute->SetListed(layer->IsVisibleOnListing());
3234  }
3235  node1 = node1->GetNext();
3236  }
3237 
3238  for (Track *pTrack : g_TrackList) {
3239  if (pTrack->m_bIsInLayer && (pTrack->m_LayerID == layer->m_LayerID))
3240  pTrack->SetListed(layer->IsVisibleOnListing());
3241  }
3242 
3243  // Process waypoints in this layer
3244  // n.b. If the waypoint belongs to a track, and is not shared, then do not
3245  // list it. This is a performance optimization, allowing large track support.
3246 
3247  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3248 
3249  while (node) {
3250  RoutePoint *rp = node->GetData();
3251  if (rp && rp->m_bIsolatedMark && (rp->m_LayerID == layer->m_LayerID)) {
3252  rp->SetListed(layer->IsVisibleOnListing());
3253  }
3254 
3255  node = node->GetNext();
3256  }
3257 
3258  UpdateLists();
3259 
3260  ::wxEndBusyCursor();
3261 
3262  gFrame->RefreshAllCanvas();
3263 }
3264 
3265 void RouteManagerDialog::OnLayDefaultAction(wxListEvent &event) {
3266  wxCommandEvent evt;
3267  OnLayPropertiesClick(evt);
3268 }
3269 
3270 void RouteManagerDialog::UpdateLayListCtrl() {
3271  // if an item was selected, make it selected again if it still exist
3272  long item = -1;
3273  item =
3274  m_pLayListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
3275 
3276  wxUIntPtr selected_id = wxUIntPtr(0);
3277  if (item != -1) selected_id = m_pLayListCtrl->GetItemData(item);
3278 
3279  // Delete existing items
3280  m_pLayListCtrl->DeleteAllItems();
3281 
3282  // then add routes to the listctrl
3283  LayerList::iterator it;
3284  int index = 0;
3285  bool b_anyHidden = false;
3286  for (it = (*pLayerList).begin(); it != (*pLayerList).end(); ++it, ++index) {
3287  Layer *lay = (Layer *)(*it);
3288 
3289  if (!lay->m_LayerName.Upper().Contains(m_tFilterLay->GetValue().Upper())) {
3290  continue;
3291  }
3292 
3293  wxListItem li;
3294  li.SetId(index);
3295  li.SetImage(lay->IsVisibleOnChart() ? 0 : 1);
3296  li.SetData(lay);
3297  li.SetText(_T(""));
3298 
3299  long idx = m_pLayListCtrl->InsertItem(li);
3300 
3301  wxString name = lay->m_LayerName;
3302  if (name.IsEmpty()) {
3303  // RoutePoint *rp = trk->GetPoint(1);
3304  // if (rp)
3305  // name = rp->m_CreateTime.FormatISODate() + _T(" ") +
3306  // rp->m_CreateTime.FormatISOTime(); //name =
3307  // rp->m_CreateTime.Format();
3308  // else
3309  name = _("(Unnamed Layer)");
3310  }
3311  m_pLayListCtrl->SetItem(idx, colLAYNAME, name);
3312 
3313  wxString len;
3314  len.Printf(wxT("%d"), (int)lay->m_NoOfItems);
3315  m_pLayListCtrl->SetItem(idx, colLAYITEMS, len);
3316  m_pLayListCtrl->SetItem(idx, colLAYPERSIST, lay->m_LayerType);
3317 
3318  wxListItem lic;
3319  lic.SetId(index);
3320  lic.SetColumn(1);
3321  lic.SetAlign(wxLIST_FORMAT_LEFT);
3322  m_pLayListCtrl->SetItem(lic);
3323 
3324  lic.SetColumn(2);
3325  lic.SetAlign(wxLIST_FORMAT_LEFT);
3326  m_pLayListCtrl->SetItem(lic);
3327 
3328  if (!lay->IsVisibleOnChart()) b_anyHidden = true;
3329  }
3330 
3331  m_pLayListCtrl->SortItems(SortLayersOnName,
3332  reinterpret_cast<wxIntPtr>(m_pLayListCtrl));
3333  m_pLayListCtrl->SetColumnWidth(0, 4 * m_charWidth);
3334 
3335  // restore selection if possible
3336  // NOTE this will select a different item, if one is deleted
3337  // (the next route will get that index).
3338  if (selected_id != wxUIntPtr(0)) {
3339  item = m_pLayListCtrl->FindItem(-1, selected_id);
3340  m_pLayListCtrl->SetItemState(item,
3341  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
3342  wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
3343  }
3344  UpdateLayButtons();
3345 
3346  m_cbShowAllLay->SetValue(!b_anyHidden);
3347 }
3348 
3349 void RouteManagerDialog::OnImportClick(wxCommandEvent &event) {
3350  // Import routes
3351  // FIXME there is no way to instruct this function about what to import.
3352  // Suggest to add that!
3353 
3354  UI_ImportGPX(this);
3355 
3356  UpdateLists();
3357 
3358  gFrame->RefreshAllCanvas();
3359 }
3360 void RouteManagerDialog::OnExportClick(wxCommandEvent &event) {
3361  ExportGPX(this);
3362 }
3363 
3364 void RouteManagerDialog::OnExportVizClick(wxCommandEvent &event) {
3365  ExportGPX(this, true, true); // only visible objects, layers included
3366 }
3367 
3368 void RouteManagerDialog::OnFilterChanged(wxCommandEvent &event) {
3369  if (event.GetEventObject() == m_tFilterWpt) {
3370  UpdateWptListCtrl(NULL, true);
3371  } else if (event.GetEventObject() == m_tFilterRte) {
3372  UpdateRouteListCtrl();
3373  } else if (event.GetEventObject() == m_tFilterTrk) {
3374  UpdateTrkListCtrl();
3375  } else if (event.GetEventObject() == m_tFilterLay) {
3376  UpdateLayListCtrl();
3377  }
3378 }
3379 
3380 // END Event handlers
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
Definition: Layer.h:32
Class MarkInfoDef.
Definition: MarkInfo.h:203
void Validate()
Check that all entries are accessible, remove stale ones.
Definition: mdns_cache.cpp:71
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition: observable.h:227
Definition: route.h:75
EventVar on_routes_update
Notified when list of routes is updated (no data in event)
Definition: routeman.h:196
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
Definition: routeman.cpp:751
Route "Send to GPS..." Dialog Definition.
Definition: SendToGpsDlg.h:51
Route "Send to Peer..." Dialog Definition.
Definition: SendToPeerDlg.h:71
Class TrackPropDlg.
Definition: TrackPropDlg.h:93
Definition: track.h:78