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