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