OpenCPN Partial API docs
Loading...
Searching...
No Matches
RoutePropDlgImpl.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2013 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 **************************************************************************/
23
24#include <wx/clipbrd.h>
25
26#include "RoutePropDlgImpl.h"
27#include "navutil.h"
28#include "georef.h"
29#include "MarkInfo.h"
30#include "own_ship.h"
31#include "routeman.h"
32#include "routemanagerdialog.h"
33#include "routeprintout.h"
34#include "chcanv.h"
35#include "navutil_base.h"
36#include "tcmgr.h"
37#include "ocpn_plugin.h"
38#include "gui_lib.h"
39
40#define ID_RCLK_MENU_COPY_TEXT 7013
41#define ID_RCLK_MENU_EDIT_WP 7014
42#define ID_RCLK_MENU_DELETE 7015
43#define ID_RCLK_MENU_MOVEUP_WP 7026
44#define ID_RCLK_MENU_MOVEDOWN_WP 7027
45
46#define COLUMN_PLANNED_SPEED 9
47#define COLUMN_ETD 13
48
49extern wxString GetLayerName(int id);
50
51extern WayPointman* pWayPointMan;
52extern Routeman* g_pRouteMan;
53extern MyConfig* pConfig;
54extern ColorScheme global_color_scheme;
55extern RouteList* pRouteList;
56extern Select* pSelect;
57extern MyFrame* gFrame;
58extern RouteManagerDialog* pRouteManagerDialog;
59extern TCMgr* ptcmgr;
60extern bool g_btouch;
61
62int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
63
64// Sunrise/twilight calculation for route properties.
65// limitations: latitude below 60, year between 2000 and 2100
66// riset is +1 for rise -1 for set
67// adapted by author's permission from QBASIC source as published at
68// http://www.stargazing.net/kepler
69
70#ifndef PI
71#define PI (4. * atan(1.0))
72#endif
73#define TPI (2. * PI)
74#define DEGS (180. / PI)
75#define RADS (PI / 180.)
76
77#define MOTWILIGHT \
78 1 // in some languages there may be a distinction between morning/evening
79#define SUNRISE 2
80#define DAY 3
81#define SUNSET 4
82#define EVTWILIGHT 5
83#define NIGHT 6
84
85static wxString GetDaylightString(int index) {
86 switch (index) {
87 case 0:
88 return _T(" - ");
89 case 1:
90 return _("MoTwilight");
91 case 2:
92 return _("Sunrise");
93 case 3:
94 return _("Daytime");
95 case 4:
96 return _("Sunset");
97 case 5:
98 return _("EvTwilight");
99 case 6:
100 return _("Nighttime");
101
102 default:
103 return _T("");
104 }
105}
106
107static double sign(double x) {
108 if (x < 0.)
109 return -1.;
110 else
111 return 1.;
112}
113
114static double FNipart(double x) { return (sign(x) * (int)(fabs(x))); }
115
116static double FNday(int y, int m, int d, int h) {
117 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
118 return ((double)fd - 730531.5 + h / 24.);
119}
120
121static double FNrange(double x) {
122 double b = x / TPI;
123 double a = TPI * (b - FNipart(b));
124 if (a < 0.) a = TPI + a;
125 return (a);
126}
127
128static double getDaylightEvent(double glat, double glong, int riset,
129 double altitude, int y, int m, int d) {
130 double day = FNday(y, m, d, 0);
131 double days, correction;
132 double utold = PI;
133 double utnew = 0.;
134 double sinalt =
135 sin(altitude * RADS); // go for the sunrise/sunset altitude first
136 double sinphi = sin(glat * RADS);
137 double cosphi = cos(glat * RADS);
138 double g = glong * RADS;
139 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
140 int limit = 12;
141 while ((fabs(utold - utnew) > .001)) {
142 if (limit-- <= 0) return (-1.);
143 days = day + utnew / TPI;
144 t = days / 36525.;
145 // get arguments of Sun's orbit
146 L = FNrange(4.8949504201433 + 628.331969753199 * t);
147 G = FNrange(6.2400408 + 628.3019501 * t);
148 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
149 lambda = L + ec;
150 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
151 obl = .409093 - .0002269 * t;
152 delta = asin(sin(obl) * sin(lambda));
153 GHA = utold - PI + E;
154 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
155 if (cosc > 1.)
156 correction = 0.;
157 else if (cosc < -1.)
158 correction = PI;
159 else
160 correction = acos(cosc);
161 double tmp = utnew;
162 utnew = FNrange(utold - (GHA + g + riset * correction));
163 utold = tmp;
164 }
165 return (utnew * DEGS / 15.); // returns decimal hours UTC
166}
167
168static double getLMT(double ut, double lon) {
169 double t = ut + lon / 15.;
170 if (t >= 0.)
171 if (t <= 24.)
172 return (t);
173 else
174 return (t - 24.);
175 else
176 return (t + 24.);
177}
178
179static int getDaylightStatus(double lat, double lon, wxDateTime utcDateTime) {
180 if (fabs(lat) > 60.) return (0);
181 int y = utcDateTime.GetYear();
182 int m = utcDateTime.GetMonth() + 1; // wxBug? months seem to run 0..11 ?
183 int d = utcDateTime.GetDay();
184 int h = utcDateTime.GetHour();
185 int n = utcDateTime.GetMinute();
186 int s = utcDateTime.GetSecond();
187 if (y < 2000 || y > 2100) return (0);
188
189 double ut = (double)h + (double)n / 60. + (double)s / 3600.;
190 double lt = getLMT(ut, lon);
191 double rsalt = -0.833;
192 double twalt = -12.;
193
194 if (lt <= 12.) {
195 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
196 if (sunrise < 0.)
197 return (0);
198 else
199 sunrise = getLMT(sunrise, lon);
200
201 if (fabs(lt - sunrise) < 0.15) return (SUNRISE);
202 if (lt > sunrise) return (DAY);
203 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
204 if (twilight < 0.)
205 return (0);
206 else
207 twilight = getLMT(twilight, lon);
208 if (lt > twilight)
209 return (MOTWILIGHT);
210 else
211 return (NIGHT);
212 } else {
213 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
214 if (sunset < 0.)
215 return (0);
216 else
217 sunset = getLMT(sunset, lon);
218 if (fabs(lt - sunset) < 0.15) return (SUNSET);
219 if (lt < sunset) return (DAY);
220 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
221 if (twilight < 0.)
222 return (0);
223 else
224 twilight = getLMT(twilight, lon);
225 if (lt < twilight)
226 return (EVTWILIGHT);
227 else
228 return (NIGHT);
229 }
230}
231
232RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID id,
233 const wxString& title, const wxPoint& pos,
234 const wxSize& size, long style)
235 : RoutePropDlg(parent, id, title, pos, size, style) {
236 m_pRoute = NULL;
237
238 SetColorScheme(global_color_scheme);
239
240 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
241 g_route_prop_sx < wxGetDisplaySize().x &&
242 g_route_prop_sy < wxGetDisplaySize().y) {
243 SetSize(g_route_prop_sx, g_route_prop_sy);
244 }
245
246 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
247 g_route_prop_x < wxGetDisplaySize().x &&
248 g_route_prop_y < wxGetDisplaySize().y) {
249 SetPosition(wxPoint(10, 10));
250 }
251 RecalculateSize();
252
253 Connect(wxEVT_COMMAND_MENU_SELECTED,
254 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
255 NULL, this);
256
257#ifdef __WXOSX__
258 Connect(wxEVT_ACTIVATE,
259 wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
260 NULL, this);
261#endif
262}
263
264RoutePropDlgImpl::~RoutePropDlgImpl() {
265 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
266 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
267 NULL, this);
268 instanceFlag = false;
269}
270
271bool RoutePropDlgImpl::instanceFlag = false;
272bool RoutePropDlgImpl::getInstanceFlag() {
273 return RoutePropDlgImpl::instanceFlag;
274}
275
276RoutePropDlgImpl* RoutePropDlgImpl::single = NULL;
277RoutePropDlgImpl* RoutePropDlgImpl::getInstance(wxWindow* parent) {
278 if (!instanceFlag) {
279 single = new RoutePropDlgImpl(parent);
280 instanceFlag = true;
281 }
282 return single;
283}
284
285void RoutePropDlgImpl::OnActivate(wxActivateEvent& event){
286 wxFrame* pWin = wxDynamicCast(event.GetEventObject(), wxFrame);
287 long int style = pWin->GetWindowStyle();
288 if (event.GetActive())
289 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
290 else
291 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
292}
293
294void RoutePropDlgImpl::RecalculateSize(void) {
295 wxSize esize;
296 esize.x = GetCharWidth() * 110;
297 esize.y = GetCharHeight() * 40;
298
299 wxSize dsize = GetParent()->GetSize(); // GetClientSize();
300 esize.y = wxMin(esize.y, dsize.y - 0 /*(2 * GetCharHeight())*/);
301 esize.x = wxMin(esize.x, dsize.x - 0 /*(2 * GetCharHeight())*/);
302 SetSize(esize);
303
304 wxSize fsize = GetSize();
305 wxSize canvas_size = GetParent()->GetSize();
306 wxPoint screen_pos = GetParent()->GetScreenPosition();
307 int xp = (canvas_size.x - fsize.x) / 2;
308 int yp = (canvas_size.y - fsize.y) / 2;
309 Move(screen_pos.x + xp, screen_pos.y + yp);
310}
311
312void RoutePropDlgImpl::UpdatePoints() {
313 if (!m_pRoute) return;
314 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
315 int selected_row = m_dvlcWaypoints->GetSelectedRow();
316 m_dvlcWaypoints->DeleteAllItems();
317
318 wxVector<wxVariant> data;
319
320 m_pRoute->UpdateSegmentDistances(
321 m_pRoute->m_PlannedSpeed); // to fix ETA properties
322 m_tcDistance->SetValue(
323 wxString::Format(wxT("%5.1f ") + getUsrDistanceUnit(),
324 toUsrDistance(m_pRoute->m_route_length)));
325 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->m_route_time)));
326 // Iterate on Route Points, inserting blank fields starting with index 0
327 wxRoutePointListNode* pnode = m_pRoute->pRoutePointList->GetFirst();
328 int in = 0;
329 wxString slen, eta, ete;
330 double bearing, distance, speed;
331 double totalDistance = 0;
332 wxDateTime eta_dt = wxInvalidDateTime;
333 while (pnode) {
334 speed = pnode->GetData()->GetPlannedSpeed();
335 if (speed < .1) {
336 speed = m_pRoute->m_PlannedSpeed;
337 }
338 if (in == 0) {
339 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
340 pnode->GetData()->GetLongitude(), gLat, gLon,
341 &bearing, &distance);
342 if (m_pRoute->m_PlannedDeparture.IsValid()) {
343 eta = wxString::Format(
344 "Start: %s", toUsrDateTime(m_pRoute->m_PlannedDeparture,
345 m_tz_selection, pnode->GetData()->m_lon)
346 .Format(ETA_FORMAT_STR)
347 .c_str());
348 eta.Append(wxString::Format(
349 _T(" (%s)"),
350 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
351 pnode->GetData()->m_lon,
352 m_pRoute->m_PlannedDeparture))
353 .c_str()));
354 eta_dt = m_pRoute->m_PlannedDeparture;
355 } else {
356 eta = _("N/A");
357 }
358 if (speed > .1) {
359 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
360 } else {
361 ete = _("N/A");
362 }
363 } else {
364 distance = pnode->GetData()->GetDistance();
365 bearing = pnode->GetData()->GetCourse();
366 if (pnode->GetData()->GetETA().IsValid()) {
367 eta = toUsrDateTime(pnode->GetData()->GetETA(), m_tz_selection,
368 pnode->GetData()->m_lon)
369 .Format(ETA_FORMAT_STR);
370 eta.Append(wxString::Format(
371 _T(" (%s)"),
372 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
373 pnode->GetData()->m_lon,
374 pnode->GetData()->GetETA()))
375 .c_str()));
376 eta_dt = pnode->GetData()->GetETA();
377 } else {
378 eta = wxEmptyString;
379 }
380 ete = pnode->GetData()->GetETE();
381 totalDistance += distance;
382 }
383 wxString name = pnode->GetData()->GetName();
384 double lat = pnode->GetData()->GetLatitude();
385 double lon = pnode->GetData()->GetLongitude();
386 wxString tide_station = pnode->GetData()->m_TideStation;
387 wxString desc = pnode->GetData()->GetDescription();
388 wxString etd;
389 if (pnode->GetData()->GetManualETD().IsValid()) {
390 // GetManualETD() returns time in UTC, always. So use it as such.
391 etd = toUsrDateTime(pnode->GetData()->GetManualETD(),
392 0 /*m_tz_selection*/, pnode->GetData()->m_lon)
393 .Format(ETA_FORMAT_STR);
394 if (pnode->GetData()->GetManualETD().IsValid() &&
395 pnode->GetData()->GetETA().IsValid() &&
396 pnode->GetData()->GetManualETD() < pnode->GetData()->GetETA()) {
397 etd.Prepend(
398 _T("!! ")); // Manually entered ETD is before we arrive here!
399 }
400 } else {
401 etd = wxEmptyString;
402 }
403 pnode = pnode->GetNext();
404 wxString crs;
405 if (pnode) {
406 crs = formatAngle(pnode->GetData()->GetCourse());
407 } else {
408 crs = _("Arrived");
409 }
410
411 if (in == 0)
412 data.push_back(wxVariant("---"));
413 else {
414 std::ostringstream stm;
415 stm << in;
416 data.push_back(wxVariant(stm.str()));
417 }
418
419 wxString schar = wxEmptyString;
420#ifdef __OCPN__ANDROID__
421 schar = wxString(" ");
422#endif
423 data.push_back(wxVariant(name + schar)); // To
424 slen.Printf(wxT("%5.1f ") + getUsrDistanceUnit(), toUsrDistance(distance));
425 data.push_back(wxVariant(schar + slen + schar)); // Distance
426 data.push_back(wxVariant(schar + formatAngle(bearing))); // Bearing
427 slen.Printf(wxT("%5.1f ") + getUsrDistanceUnit(),
428 toUsrDistance(totalDistance));
429 data.push_back(wxVariant(schar + slen + schar)); // Total Distance
430 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar)); // Lat
431 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar)); // Lon
432 data.push_back(wxVariant(schar + ete + schar)); // ETE
433 data.push_back(schar + eta + schar); // ETA
434 data.push_back(
435 wxVariant(wxString::FromDouble(toUsrSpeed(speed)))); // Speed
436 data.push_back(wxVariant(
437 MakeTideInfo(tide_station, lat, lon, eta_dt))); // Next Tide event
438 data.push_back(wxVariant(desc)); // Description
439 data.push_back(wxVariant(crs));
440 data.push_back(wxVariant(etd));
441 data.push_back(wxVariant(
442 wxEmptyString)); // Empty column to fill the remaining space (Usually
443 // gets squeezed to zero, even if not empty)
444 m_dvlcWaypoints->AppendItem(data);
445 data.clear();
446 in++;
447 }
448 if (selected_row > 0) {
449 m_dvlcWaypoints->SelectRow(selected_row);
450 m_dvlcWaypoints->EnsureVisible(selection);
451 }
452}
453
454wxDateTime RoutePropDlgImpl::toUsrDateTime(const wxDateTime ts,
455 const int format, const double lon) {
456 if (!ts.IsValid()) {
457 return ts;
458 }
459 wxDateTime dt;
460 switch (m_tz_selection) {
461 case 2: // LMT@Location
462 if (std::isnan(lon)) {
463 dt = wxInvalidDateTime;
464 } else {
465 dt =
466 ts.Add(wxTimeSpan(wxTimeSpan(0, 0, wxLongLong(lon * 3600. / 15.))));
467 }
468 break;
469 case 1: // Local@PC
470 dt = ts.FromUTC();
471 break;
472 case 0: // UTC
473 dt = ts;
474 break;
475 }
476 return dt;
477}
478
479wxDateTime RoutePropDlgImpl::fromUsrDateTime(const wxDateTime ts,
480 const int format,
481 const double lon) {
482 if (!ts.IsValid()) {
483 return ts;
484 }
485 wxDateTime dt;
486 switch (m_tz_selection) {
487 case 2: // LMT@Location
488 if (std::isnan(lon)) {
489 dt = wxInvalidDateTime;
490 } else {
491 dt = ts.Subtract(wxTimeSpan(0, 0, wxLongLong(lon * 3600. / 15.)));
492 }
493 break;
494 case 1: // Local@PC
495 dt = ts.ToUTC();
496 break;
497 case 0: // UTC
498 dt = ts;
499 break;
500 }
501 return dt;
502}
503
504void RoutePropDlgImpl::SetRouteAndUpdate(Route* pR, bool only_points) {
505 if (NULL == pR) return;
506
507 if (m_pRoute &&
508 m_pRoute != pR) // We had unsaved changes, but now display another route
509 ResetChanges();
510
511 m_OrigRoute.m_PlannedDeparture = pR->m_PlannedDeparture;
512 m_OrigRoute.m_PlannedSpeed = pR->m_PlannedSpeed;
513
514 wxString title =
515 pR->GetName() == wxEmptyString ? _("Route Properties") : pR->GetName();
516 if (!pR->m_bIsInLayer)
517 SetTitle(title);
518 else {
519 wxString caption(wxString::Format(_T("%s, %s: %s"), title, _("Layer"),
520 GetLayerName(pR->m_LayerID)));
521 SetTitle(caption);
522 }
523
524 // Fetch any config file values
525 if (!only_points) {
526 if (!pR->m_PlannedDeparture.IsValid())
527 pR->m_PlannedDeparture = wxDateTime::Now().ToUTC();
528
529 m_tz_selection = 1; // Local PC time by default
530 if (pR != m_pRoute) {
531 if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_UTC)
532 m_tz_selection = 0;
533 else if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_LOCAL)
534 m_tz_selection = 2;
535 m_pEnroutePoint = NULL;
536 m_bStartNow = false;
537 }
538
539 m_pRoute = pR;
540
541 m_tcPlanSpeed->SetValue(
542 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
543
544 if (m_scrolledWindowLinks) {
545 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
546 for (unsigned int i = 0; i < kids.GetCount(); i++) {
547 wxWindowListNode* node = kids.Item(i);
548 wxWindow* win = node->GetData();
549 if (win->IsKindOf(CLASSINFO(wxHyperlinkCtrl))) {
550 ((wxHyperlinkCtrl*)win)
551 ->Disconnect(
552 wxEVT_COMMAND_HYPERLINK,
553 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
554 ((wxHyperlinkCtrl*)win)
555 ->Disconnect(
556 wxEVT_RIGHT_DOWN,
557 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
558 win->Destroy();
559 }
560 }
561 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
562 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
563 if (NbrOfLinks > 0) {
564 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
565 while (linknode) {
566 Hyperlink* link = linknode->GetData();
567 wxString Link = link->Link;
568 wxString Descr = link->DescrText;
569
570 wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
571 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
572 wxDefaultSize, wxHL_DEFAULT_STYLE);
573 ctrl->Connect(
574 wxEVT_COMMAND_HYPERLINK,
575 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
576 this);
577 if (!m_pRoute->m_bIsInLayer) {
578 ctrl->Connect(
579 wxEVT_RIGHT_DOWN,
580 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
581 NULL, this);
582 }
583 bSizerLinks->Add(ctrl, 0, wxALL, 5);
584
585 linknode = linknode->GetNext();
586 }
587 }
588 m_scrolledWindowLinks->InvalidateBestSize();
589 m_scrolledWindowLinks->Layout();
590 bSizerLinks->Layout();
591 }
592
593 m_choiceTimezone->SetSelection(m_tz_selection);
594
595 // Reorganize dialog for route or track display
596 m_tcName->SetValue(m_pRoute->m_RouteNameString);
597 m_tcFrom->SetValue(m_pRoute->m_RouteStartString);
598 m_tcTo->SetValue(m_pRoute->m_RouteEndString);
599 m_tcDescription->SetValue(m_pRoute->m_RouteDescription);
600
601 m_tcName->SetFocus();
602 if (m_pRoute->m_PlannedDeparture.IsValid() &&
603 m_pRoute->m_PlannedDeparture.GetValue() > 0) {
604 m_dpDepartureDate->SetValue(
605 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
606 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
607 .GetDateOnly());
608 m_tpDepartureTime->SetValue(toUsrDateTime(
609 m_pRoute->m_PlannedDeparture, m_tz_selection,
610 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
611 } else {
612 m_dpDepartureDate->SetValue(
613 toUsrDateTime(wxDateTime::Now(), m_tz_selection,
614 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
615 .GetDateOnly());
616 m_tpDepartureTime->SetValue(toUsrDateTime(
617 wxDateTime::Now(), m_tz_selection,
618 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
619 }
620 }
621
622 m_btnSplit->Enable(false);
623 if (!m_pRoute) return;
624
625 if (m_pRoute->m_Colour == wxEmptyString) {
626 m_choiceColor->Select(0);
627 } else {
628 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
629 i++) {
630 if (m_pRoute->m_Colour == ::GpxxColorNames[i]) {
631 m_choiceColor->Select(i + 1);
632 break;
633 }
634 }
635 }
636
637 for (unsigned int i = 0; i < sizeof(::StyleValues) / sizeof(int); i++) {
638 if (m_pRoute->m_style == ::StyleValues[i]) {
639 m_choiceStyle->Select(i);
640 break;
641 }
642 }
643
644 for (unsigned int i = 0; i < sizeof(::WidthValues) / sizeof(int); i++) {
645 if (m_pRoute->m_width == ::WidthValues[i]) {
646 m_choiceWidth->Select(i);
647 break;
648 }
649 }
650
651 UpdatePoints();
652
653 m_btnExtend->Enable(IsThisRouteExtendable());
654}
655
656void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
657 if (!m_pRoute) return;
658 m_pRoute->SetDepartureDate(GetDepartureTS());
659 UpdatePoints();
660 event.Skip();
661}
662
663void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
664 if (!m_pRoute) return;
665 m_pRoute->SetDepartureDate(GetDepartureTS());
666 UpdatePoints();
667 event.Skip();
668}
669
670void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
671 m_tz_selection = m_choiceTimezone->GetSelection();
672 m_dpDepartureDate->SetValue(
673 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
674 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
675 .GetDateOnly());
676 m_tpDepartureTime->SetValue(
677 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
678 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
679 UpdatePoints();
680 event.Skip();
681}
682
683void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
684 if (!m_pRoute) return;
685 double spd;
686 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
687 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
688 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
689 UpdatePoints();
690 }
691 } else {
692 m_tcPlanSpeed->SetValue(
693 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
694 }
695}
696
697void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
698 if (!m_pRoute) return;
699 double spd;
700 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
701 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
702 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
703 UpdatePoints();
704 }
705 } else {
706 m_tcPlanSpeed->SetValue(
707 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
708 }
709 event.Skip();
710}
711
712static int ev_col;
713void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
714 wxDataViewEvent& event) {
715 // There is a bug in wxWidgets, the EDITING_DONE event does not contain the
716 // new value, so we must save the data and do the work later in the value
717 // changed event.
718 ev_col = event.GetColumn();
719}
720
721void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
722 wxDataViewEvent& event) {
723#if wxCHECK_VERSION(3, 1, 2)
724 // wx 3.0.x crashes in the bellow code
725 if (!m_pRoute) return;
726 wxDataViewModel* const model = event.GetModel();
727 wxVariant value;
728 model->GetValue(value, event.GetItem(), ev_col);
729 RoutePoint* p = m_pRoute->GetPoint(
730 static_cast<int>(reinterpret_cast<long long>(event.GetItem().GetID())));
731 if (ev_col == COLUMN_PLANNED_SPEED) {
732 double spd;
733 if (!value.GetString().ToDouble(&spd)) {
734 spd = 0.0;
735 }
736 p->SetPlannedSpeed(fromUsrSpeed(spd));
737 } else if (ev_col == COLUMN_ETD) {
738 wxString::const_iterator end;
739 wxDateTime etd;
740
741 wxString ts = value.GetString();
742 if (ts.StartsWith("!")) {
743 ts.Replace("!", wxEmptyString, true);
744 }
745 ts.Trim(true);
746 ts.Trim(false);
747
748 if (!ts.IsEmpty()) {
749 if (!etd.ParseDateTime(ts, &end)) {
750 p->SetETD(wxInvalidDateTime);
751 } else {
752 p->SetETD(
753 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
754 }
755 } else {
756 p->SetETD(wxInvalidDateTime);
757 }
758 }
759 UpdatePoints();
760#endif
761}
762
763void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
764 wxDataViewEvent& event) {
765 long selected_row = m_dvlcWaypoints->GetSelectedRow();
766 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
767 m_btnSplit->Enable(true);
768 } else {
769 m_btnSplit->Enable(false);
770 }
771 if (IsThisRouteExtendable()) {
772 m_btnExtend->Enable(true);
773 } else {
774 m_btnExtend->Enable(false);
775 }
776 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
777 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
778 if (prp) {
779 gFrame->JumpToPosition(gFrame->GetPrimaryCanvas(), prp->m_lat, prp->m_lon,
780 gFrame->GetPrimaryCanvas()->GetVPScale());
781#ifdef __WXMSW__
782 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
783#endif
784 }
785 }
786}
787
788wxDateTime RoutePropDlgImpl::GetDepartureTS() {
789 wxDateTime dt = m_dpDepartureDate->GetValue();
790 dt.SetHour(m_tpDepartureTime->GetValue().GetHour());
791 dt.SetMinute(m_tpDepartureTime->GetValue().GetMinute());
792 dt.SetSecond(m_tpDepartureTime->GetValue().GetSecond());
793 return fromUsrDateTime(
794 dt, m_tz_selection,
795 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon);
796 ;
797}
798
799void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
800 wxString tab("\t", wxConvUTF8);
801 wxString eol("\n", wxConvUTF8);
802 wxString csvString;
803
804 csvString << this->GetTitle() << eol << _("Name") << tab
805 << m_pRoute->m_RouteNameString << eol << _("Depart From") << tab
806 << m_pRoute->m_RouteStartString << eol << _("Destination") << tab
807 << m_pRoute->m_RouteEndString << eol << _("Total distance") << tab
808 << m_tcDistance->GetValue() << eol << _("Speed (Kts)") << tab
809 << m_tcPlanSpeed->GetValue() << eol
810 << _("Departure Time") + _T(" (") + _T(ETA_FORMAT_STR) + _T(")")
811 << tab << GetDepartureTS().Format(ETA_FORMAT_STR) << eol
812 << _("Time enroute") << tab << m_tcEnroute->GetValue() << eol
813 << eol;
814
815 int noCols;
816 int noRows;
817 noCols = m_dvlcWaypoints->GetColumnCount();
818 noRows = m_dvlcWaypoints->GetItemCount();
819 wxListItem item;
820 item.SetMask(wxLIST_MASK_TEXT);
821
822 for (int i = 0; i < noCols; i++) {
823 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
824 csvString << col->GetTitle() << tab;
825 }
826 csvString << eol;
827
828 wxVariant value;
829 for (int j = 0; j < noRows; j++) {
830 for (int i = 0; i < noCols; i++) {
831 m_dvlcWaypoints->GetValue(value, j, i);
832 csvString << value.MakeString() << tab;
833 }
834 csvString << eol;
835 }
836
837 if (wxTheClipboard->Open()) {
838 wxTextDataObject* data = new wxTextDataObject;
839 data->SetText(csvString);
840 wxTheClipboard->SetData(data);
841 wxTheClipboard->Close();
842 }
843}
844
845void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
846 bool moveup = false;
847 switch (event.GetId()) {
848 case ID_RCLK_MENU_COPY_TEXT: {
849 OnRoutepropCopyTxtClick(event);
850 break;
851 }
852 case ID_RCLK_MENU_MOVEUP_WP: {
853 moveup = true;
854 }
855 case ID_RCLK_MENU_MOVEDOWN_WP: {
856 wxString mess =
857 moveup ? _("Are you sure you want to move Up this waypoint?")
858 : _("Are you sure you want to move Down this waypoint?");
859 int dlg_return =
860 OCPNMessageBox(this, mess, _("OpenCPN Move Waypoint"),
861 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
862
863 if (dlg_return == wxID_YES) {
864 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
865 RoutePoint* pRP = m_pRoute->GetPoint(
866 static_cast<int>(reinterpret_cast<long long>(selection.GetID())));
867 int nRP = m_pRoute->pRoutePointList->IndexOf(pRP) + (moveup ? -1 : 1);
868
869 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
870 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
871
872 m_pRoute->pRoutePointList->DeleteObject(pRP);
873 m_pRoute->pRoutePointList->Insert(nRP, pRP);
874
875 pSelect->AddAllSelectableRouteSegments(m_pRoute);
876 pSelect->AddAllSelectableRoutePoints(m_pRoute);
877
878 pConfig->UpdateRoute(m_pRoute);
879
880 m_pRoute->FinalizeForRendering();
881 m_pRoute->UpdateSegmentDistances();
882 ;
883
884 gFrame->InvalidateAllGL();
885
886 m_dvlcWaypoints->SelectRow(nRP);
887
888 SetRouteAndUpdate(m_pRoute, true);
889 }
890 break;
891 }
892 case ID_RCLK_MENU_DELETE: {
893 int dlg_return = OCPNMessageBox(
894 this, _("Are you sure you want to remove this waypoint?"),
895 _("OpenCPN Remove Waypoint"),
896 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
897
898 if (dlg_return == wxID_YES) {
899 int sel = m_dvlcWaypoints->GetSelectedRow();
900 m_dvlcWaypoints->SelectRow(sel);
901
902 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
903 RoutePoint* pRP = m_pRoute->GetPoint(
904 static_cast<int>(reinterpret_cast<long long>(selection.GetID())));
905
906 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
907 gFrame->InvalidateAllGL();
908 UpdatePoints();
909 }
910 break;
911 }
912 case ID_RCLK_MENU_EDIT_WP: {
913 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
914 RoutePoint* pRP = m_pRoute->GetPoint(
915 static_cast<int>(reinterpret_cast<long long>(selection.GetID())));
916
917 RouteManagerDialog::WptShowPropertiesDialog(pRP, this);
918 break;
919 }
920 }
921}
922
923void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
924 wxDataViewEvent& event) {
925 wxMenu menu;
926 if (!m_pRoute->m_bIsInLayer) {
927 wxMenuItem* editItem = new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
928 _("Waypoint Properties") + _T("..."));
929 wxMenuItem* moveUpItem =
930 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _("Move Up"));
931 wxMenuItem* moveDownItem =
932 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _("Move Down"));
933 wxMenuItem* delItem =
934 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _("Remove Selected"));
935#ifdef __OCPN__ANDROID__
936 wxFont* pf = OCPNGetFont(_T("Menu"), 0);
937 editItem->SetFont(*pf);
938 moveUpItem->SetFont(*pf);
939 moveDownItem->SetFont(*pf);
940 delItem->SetFont(*pf);
941#endif
942#if defined(__WXMSW__)
943 wxFont* pf = GetOCPNScaledFont(_T("Menu"));
944 editItem->SetFont(*pf);
945 moveUpItem->SetFont(*pf);
946 moveDownItem->SetFont(*pf);
947 delItem->SetFont(*pf);
948#endif
949
950 menu.Append(editItem);
951 if (g_btouch) menu.AppendSeparator();
952 menu.Append(moveUpItem);
953 if (g_btouch) menu.AppendSeparator();
954 menu.Append(moveDownItem);
955 if (g_btouch) menu.AppendSeparator();
956 menu.Append(delItem);
957
958 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
959 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
960 m_dvlcWaypoints->GetItemCount() > 2);
961 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
962 m_dvlcWaypoints->GetSelectedRow() <
963 m_dvlcWaypoints->GetItemCount() - 1 &&
964 m_dvlcWaypoints->GetItemCount() > 2);
965 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
966 m_dvlcWaypoints->GetItemCount() > 2);
967 }
968#ifndef __WXQT__
969 wxMenuItem* copyItem =
970 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _("&Copy all as text"));
971
972#if defined(__WXMSW__)
973 wxFont* qFont = GetOCPNScaledFont(_T("Menu"));
974 copyItem->SetFont(*qFont);
975#endif
976
977 if (g_btouch) menu.AppendSeparator();
978 menu.Append(copyItem);
979#endif
980
981 PopupMenu(&menu);
982}
983
984void RoutePropDlgImpl::ResetChanges() {
985 if (!m_pRoute) return;
986 m_pRoute->m_PlannedSpeed = m_OrigRoute.m_PlannedSpeed;
987 m_pRoute->m_PlannedDeparture = m_OrigRoute.m_PlannedDeparture;
988 m_pRoute = NULL;
989}
990
991void RoutePropDlgImpl::SaveChanges() {
992 if (m_pRoute && !m_pRoute->m_bIsInLayer) {
993 // Get User input Text Fields
994 m_pRoute->m_RouteNameString = m_tcName->GetValue();
995 m_pRoute->m_RouteStartString = m_tcFrom->GetValue();
996 m_pRoute->m_RouteEndString = m_tcTo->GetValue();
997 m_pRoute->m_RouteDescription = m_tcDescription->GetValue();
998 if (m_choiceColor->GetSelection() == 0) {
999 m_pRoute->m_Colour = wxEmptyString;
1000 } else {
1001 m_pRoute->m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
1002 }
1003 m_pRoute->m_style =
1004 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
1005 m_pRoute->m_width = ::WidthValues[m_choiceWidth->GetSelection()];
1006 switch (m_tz_selection) {
1007 case 1:
1008 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_PC;
1009 break;
1010 case 2:
1011 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_LOCAL;
1012 break;
1013 default:
1014 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_UTC;
1015 }
1016
1017 pConfig->UpdateRoute(m_pRoute);
1018 pConfig->UpdateSettings();
1019 m_pRoute = NULL;
1020 }
1021}
1022
1023void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(this); }
1024
1025void RoutePropDlgImpl::SaveGeometry() {
1026 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1027 GetPosition(&g_route_prop_x, &g_route_prop_y);
1028}
1029
1030void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1031 SaveChanges();
1032 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1033 pRouteManagerDialog->UpdateRouteListCtrl();
1034 }
1035 Hide();
1036 SaveGeometry();
1037}
1038
1039void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1040 m_btnSplit->Enable(false);
1041
1042 if (m_pRoute->m_bIsInLayer) return;
1043
1044 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1045 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1046 m_pHead = new Route();
1047 m_pTail = new Route();
1048 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _("_A"));
1049 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _("_B"),
1050 true);
1051 pRouteList->Append(m_pHead);
1052 pConfig->AddNewRoute(m_pHead);
1053
1054 pRouteList->Append(m_pTail);
1055 pConfig->AddNewRoute(m_pTail);
1056
1057 pConfig->DeleteConfigRoute(m_pRoute);
1058
1059 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1060 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1061 g_pRouteMan->DeleteRoute(m_pRoute, NavObjectChanges::getInstance());
1062 pSelect->AddAllSelectableRouteSegments(m_pTail);
1063 pSelect->AddAllSelectableRoutePoints(m_pTail);
1064 pSelect->AddAllSelectableRouteSegments(m_pHead);
1065 pSelect->AddAllSelectableRoutePoints(m_pHead);
1066
1067 SetRouteAndUpdate(m_pTail);
1068 UpdatePoints();
1069
1070 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1071 pRouteManagerDialog->UpdateRouteListCtrl();
1072 }
1073}
1074
1075void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1076 RoutePrintSelection* dlg = new RoutePrintSelection(this, m_pRoute);
1077 DimeControl(dlg);
1078 dlg->ShowWindowModalThenDo([this, dlg](int retcode) {
1079 if (retcode == wxID_OK) {
1080 }
1081 });
1082}
1083
1084void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1085 m_btnExtend->Enable(false);
1086
1087 if (IsThisRouteExtendable()) {
1088 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1089 int to = m_pExtendRoute->GetnPoints();
1090 if (fm <= to) {
1091 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1092 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _("_plus"));
1093 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1094 SetRouteAndUpdate(m_pRoute);
1095 UpdatePoints();
1096 }
1097 }
1098 m_btnExtend->Enable(true);
1099}
1100
1101bool RoutePropDlgImpl::IsThisRouteExtendable() {
1102 m_pExtendRoute = NULL;
1103 m_pExtendPoint = NULL;
1104 if (m_pRoute->m_bRtIsActive || m_pRoute->m_bIsInLayer) return false;
1105
1106 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1107 wxArrayPtrVoid* pEditRouteArray;
1108
1109 pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(pLastPoint);
1110 // remove invisible & own routes from choices
1111 int i;
1112 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1113 Route* p = (Route*)pEditRouteArray->Item(i - 1);
1114 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1115 pEditRouteArray->RemoveAt(i - 1);
1116 }
1117 if (pEditRouteArray->GetCount() == 1) {
1118 m_pExtendPoint = pLastPoint;
1119 } else {
1120 if (pEditRouteArray->GetCount() == 0) {
1121 int nearby_radius_meters =
1122 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1123 double rlat = pLastPoint->m_lat;
1124 double rlon = pLastPoint->m_lon;
1125
1126 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1127 rlat, rlon, nearby_radius_meters, pLastPoint->m_GUID);
1128 if (m_pExtendPoint) {
1129 wxArrayPtrVoid* pCloseWPRouteArray =
1130 g_pRouteMan->GetRouteArrayContaining(m_pExtendPoint);
1131 if (pCloseWPRouteArray) {
1132 pEditRouteArray = pCloseWPRouteArray;
1133
1134 // remove invisible & own routes from choices
1135 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1136 Route* p = (Route*)pEditRouteArray->Item(i - 1);
1137 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1138 pEditRouteArray->RemoveAt(i - 1);
1139 }
1140 }
1141 }
1142 }
1143 }
1144 if (pEditRouteArray->GetCount() == 1) {
1145 Route* p = (Route*)pEditRouteArray->Item(0);
1146 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1147 int to = p->GetnPoints();
1148 if (fm <= to) {
1149 m_pExtendRoute = p;
1150 delete pEditRouteArray;
1151 return true;
1152 }
1153 }
1154 delete pEditRouteArray;
1155
1156 return false;
1157}
1158
1159wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName, double lat,
1160 double lon, wxDateTime utcTime) {
1161 if (stationName.Find("lind") != wxNOT_FOUND) int yyp = 4;
1162
1163 if (stationName.IsEmpty()) {
1164 return wxEmptyString;
1165 }
1166 if (!utcTime.IsValid()) {
1167 return _("Invalid date/time!");
1168 }
1169 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1170 if (stationID == 0) {
1171 return _("Unknown station!");
1172 }
1173 time_t dtmtt = utcTime.FromUTC().GetTicks();
1174 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1175
1176 wxDateTime dtm;
1177 dtm.Set(dtmtt).MakeUTC();
1178
1179 wxString tide_form = wxEmptyString;
1180
1181 if (ev == 1) {
1182 tide_form.Append(_T("LW: "));
1183 } else if (ev == 2) {
1184 tide_form.Append(_T("HW: "));
1185 } else if (ev == 0) {
1186 tide_form.Append(_("Unavailable: "));
1187 }
1188
1189 int offset =
1190 ptcmgr->GetStationTimeOffset((IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1191
1192 tide_form.Append(
1193 toUsrDateTime(dtm, m_tz_selection, lon).Format(ETA_FORMAT_STR));
1194 dtm.Add(wxTimeSpan(0, offset, 0));
1195 tide_form.Append(wxString::Format(_T(" (") + _("Local") + _T(": %s) @ %s"),
1196 dtm.Format(ETA_FORMAT_STR),
1197 stationName.c_str()));
1198
1199 return tide_form;
1200}
1201
1202void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1203 wxString findurl = m_pEditedLink->GetURL();
1204 wxString findlabel = m_pEditedLink->GetLabel();
1205
1206 LinkPropImpl* LinkPropDlg = new LinkPropImpl(this);
1207 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1208 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1209 DimeControl(LinkPropDlg);
1210 LinkPropDlg->ShowWindowModalThenDo([this, LinkPropDlg, findurl,
1211 findlabel](int retcode) {
1212 if (retcode == wxID_OK) {
1213 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1214 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1215 // int len = 0;
1216 if (NbrOfLinks > 0) {
1217 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1218 while (linknode) {
1219 Hyperlink* link = linknode->GetData();
1220 wxString Link = link->Link;
1221 wxString Descr = link->DescrText;
1222 if (Link == findurl &&
1223 (Descr == findlabel ||
1224 (Link == findlabel && Descr == wxEmptyString))) {
1225 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1226 link->DescrText =
1227 LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1228 wxHyperlinkCtrl* h =
1229 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1230 findlabel);
1231 if (h) {
1232 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1233 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1234 }
1235 }
1236 linknode = linknode->GetNext();
1237 }
1238 }
1239
1240 m_scrolledWindowLinks->InvalidateBestSize();
1241 m_scrolledWindowLinks->Layout();
1242 bSizerLinks->Layout();
1243 }
1244 });
1245 event.Skip();
1246}
1247
1248void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1249 AddLinkOnButtonClick(event);
1250}
1251
1253 wxHyperlinkListNode* nodeToDelete = NULL;
1254 wxString findurl = m_pEditedLink->GetURL();
1255 wxString findlabel = m_pEditedLink->GetLabel();
1256
1257 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1258 for (unsigned int i = 0; i < kids.GetCount(); i++) {
1259 wxWindowListNode* node = kids.Item(i);
1260 wxWindow* win = node->GetData();
1261
1262 if (win->IsKindOf(CLASSINFO(wxHyperlinkCtrl))) {
1263 ((wxHyperlinkCtrl*)win)
1264 ->Disconnect(
1265 wxEVT_COMMAND_HYPERLINK,
1266 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1267 ((wxHyperlinkCtrl*)win)
1268 ->Disconnect(
1269 wxEVT_RIGHT_DOWN,
1270 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1271 win->Destroy();
1272 }
1273 }
1274
1276 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1277 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1278 // int len = 0;
1279 if (NbrOfLinks > 0) {
1280 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1281 while (linknode) {
1282 Hyperlink* link = linknode->GetData();
1283 wxString Link = link->Link;
1284 wxString Descr = link->DescrText;
1285 if (Link == findurl &&
1286 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1287 nodeToDelete = linknode;
1288 else {
1289 wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
1290 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1291 wxDefaultSize, wxHL_DEFAULT_STYLE);
1292 ctrl->Connect(
1293 wxEVT_COMMAND_HYPERLINK,
1294 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1295 this);
1296 ctrl->Connect(
1297 wxEVT_RIGHT_DOWN,
1298 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1299 this);
1300
1301 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1302 }
1303 linknode = linknode->GetNext();
1304 }
1305 }
1306 if (nodeToDelete) {
1307 hyperlinklist->DeleteNode(nodeToDelete);
1308 }
1309 m_scrolledWindowLinks->InvalidateBestSize();
1310 m_scrolledWindowLinks->Layout();
1311 bSizerLinks->Layout();
1312 event.Skip();
1313}
1314
1315void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1316 LinkPropImpl* LinkPropDlg = new LinkPropImpl(this);
1317 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1318 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1319 DimeControl(LinkPropDlg);
1320 LinkPropDlg->ShowWindowModalThenDo([this, LinkPropDlg](int retcode) {
1321 if (retcode == wxID_OK) {
1322 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1323 if (desc == wxEmptyString)
1324 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1325 wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
1326 m_scrolledWindowLinks, wxID_ANY, desc,
1327 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1328 wxDefaultSize, wxHL_DEFAULT_STYLE);
1329 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1330 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1331 NULL, this);
1332 ctrl->Connect(wxEVT_RIGHT_DOWN,
1333 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1334 NULL, this);
1335
1336 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1337 m_scrolledWindowLinks->InvalidateBestSize();
1338 m_scrolledWindowLinks->Layout();
1339 bSizerLinks->Layout();
1340
1341 Hyperlink* h = new Hyperlink();
1342 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1343 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1344 h->LType = wxEmptyString;
1345 m_pRoute->m_HyperlinkList->Append(h);
1346 }
1347 });
1348}
1349
1350void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1351 if (m_toggleBtnEdit->GetValue()) {
1352 m_stEditEnabled->SetLabel(_("Links are opened for editing."));
1353 } else {
1354 m_stEditEnabled->SetLabel(_("Links are opened in the default browser."));
1355 }
1356 event.Skip();
1357}
1358
1359void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1360 if (m_toggleBtnEdit->GetValue()) {
1361 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1362 ItemEditOnMenuSelection(event);
1363 event.Skip(false);
1364 return;
1365 }
1366 // Windows has trouble handling local file URLs with embedded anchor
1367 // points, e.g file://testfile.html#point1 The trouble is with the
1368 // wxLaunchDefaultBrowser with verb "open" Workaround is to probe the
1369 // registry to get the default browser, and open directly
1370 //
1371 // But, we will do this only if the URL contains the anchor point character
1372 // '#' What a hack......
1373
1374#ifdef __WXMSW__
1375 wxString cc = event.GetURL();
1376 if (cc.Find(_T("#")) != wxNOT_FOUND) {
1377 wxRegKey RegKey(
1378 wxString(_T("HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command")));
1379 if (RegKey.Exists()) {
1380 wxString command_line;
1381 RegKey.QueryValue(wxString(_T("")), command_line);
1382
1383 // Remove "
1384 command_line.Replace(wxString(_T("\"")), wxString(_T("")));
1385
1386 // Strip arguments
1387 int l = command_line.Find(_T(".exe"));
1388 if (wxNOT_FOUND == l) l = command_line.Find(_T(".EXE"));
1389
1390 if (wxNOT_FOUND != l) {
1391 wxString cl = command_line.Mid(0, l + 4);
1392 cl += _T(" ");
1393 cc.Prepend(_T("\""));
1394 cc.Append(_T("\""));
1395 cl += cc;
1396 wxExecute(cl); // Async, so Fire and Forget...
1397 }
1398 }
1399 } else
1400 event.Skip();
1401#else
1402 wxString url = event.GetURL();
1403 url.Replace(_T(" "), _T("%20"));
1404 ::wxLaunchDefaultBrowser(url);
1405#endif
1406}
1407
1408void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1409 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1410 m_scrolledWindowLinks->PopupMenu(
1411 m_menuLink, m_pEditedLink->GetPosition().x + event.GetPosition().x,
1412 m_pEditedLink->GetPosition().y + event.GetPosition().y);
1413}
Definition: IDX_entry.h:41
Class LinkPropImpl.
Definition: LinkPropDlg.h:89
void ItemDeleteOnMenuSelection(wxCommandEvent &event)
Class RoutePropDlg.
Definition: RoutePropDlg.h:53
Definition: route.h:70
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
Definition: routeman.cpp:726
Definition: select.h:51
Definition: tcmgr.h:86