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