24 #include <wx/clipbrd.h>
26 #include "model/georef.h"
27 #include "model/own_ship.h"
28 #include "model/routeman.h"
29 #include "model/select.h"
34 #include "model/navutil_base.h"
37 #include "routemanagerdialog.h"
38 #include "routeprintout.h"
39 #include "RoutePropDlgImpl.h"
42 #define ID_RCLK_MENU_COPY_TEXT 7013
43 #define ID_RCLK_MENU_EDIT_WP 7014
44 #define ID_RCLK_MENU_DELETE 7015
45 #define ID_RCLK_MENU_MOVEUP_WP 7026
46 #define ID_RCLK_MENU_MOVEDOWN_WP 7027
48 #define COLUMN_PLANNED_SPEED 9
51 extern wxString GetLayerName(
int id);
55 extern ColorScheme global_color_scheme;
56 extern RouteList* pRouteList;
61 int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
70 #define PI (4. * atan(1.0))
73 #define DEGS (180. / PI)
74 #define RADS (PI / 180.)
84 static wxString GetDaylightString(
int index) {
89 return _(
"MoTwilight");
97 return _(
"EvTwilight");
99 return _(
"Nighttime");
106 static double sign(
double x) {
113 static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
115 static double FNday(
int y,
int m,
int d,
int h) {
116 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
117 return ((
double)fd - 730531.5 + h / 24.);
120 static double FNrange(
double x) {
122 double a = TPI * (b - FNipart(b));
123 if (a < 0.) a = TPI + a;
127 static double getDaylightEvent(
double glat,
double glong,
int riset,
128 double altitude,
int y,
int m,
int d) {
129 double day = FNday(y, m, d, 0);
130 double days, correction;
134 sin(altitude * RADS);
135 double sinphi = sin(glat * RADS);
136 double cosphi = cos(glat * RADS);
137 double g = glong * RADS;
138 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
140 while ((fabs(utold - utnew) > .001)) {
141 if (limit-- <= 0)
return (-1.);
142 days = day + utnew / TPI;
145 L = FNrange(4.8949504201433 + 628.331969753199 * t);
146 G = FNrange(6.2400408 + 628.3019501 * t);
147 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
149 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
150 obl = .409093 - .0002269 * t;
151 delta = asin(sin(obl) * sin(lambda));
152 GHA = utold - PI + E;
153 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
159 correction = acos(cosc);
161 utnew = FNrange(utold - (GHA + g + riset * correction));
164 return (utnew * DEGS / 15.);
167 static double getLMT(
double ut,
double lon) {
168 double t = ut + lon / 15.;
178 static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
179 if (fabs(lat) > 60.)
return (0);
180 int y = utcDateTime.GetYear();
181 int m = utcDateTime.GetMonth() + 1;
182 int d = utcDateTime.GetDay();
183 int h = utcDateTime.GetHour();
184 int n = utcDateTime.GetMinute();
185 int s = utcDateTime.GetSecond();
186 if (y < 2000 || y > 2100)
return (0);
188 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
189 double lt = getLMT(ut, lon);
190 double rsalt = -0.833;
194 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
198 sunrise = getLMT(sunrise, lon);
200 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
201 if (lt > sunrise)
return (DAY);
202 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
206 twilight = getLMT(twilight, lon);
212 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
216 sunset = getLMT(sunset, lon);
217 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
218 if (lt < sunset)
return (DAY);
219 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
223 twilight = getLMT(twilight, lon);
231 RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
232 const wxString& title,
const wxPoint& pos,
233 const wxSize& size,
long style)
237 SetColorScheme(global_color_scheme);
239 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
240 g_route_prop_sx < wxGetDisplaySize().x &&
241 g_route_prop_sy < wxGetDisplaySize().y) {
242 SetSize(g_route_prop_sx, g_route_prop_sy);
245 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
246 g_route_prop_x < wxGetDisplaySize().x &&
247 g_route_prop_y < wxGetDisplaySize().y) {
248 SetPosition(wxPoint(10, 10));
252 Connect(wxEVT_COMMAND_MENU_SELECTED,
253 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
257 Connect(wxEVT_ACTIVATE,
258 wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
263 RoutePropDlgImpl::~RoutePropDlgImpl() {
264 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
265 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
267 instanceFlag =
false;
270 bool RoutePropDlgImpl::instanceFlag =
false;
271 bool RoutePropDlgImpl::getInstanceFlag() {
272 return RoutePropDlgImpl::instanceFlag;
284 void RoutePropDlgImpl::OnActivate(wxActivateEvent& event){
285 wxFrame* pWin = wxDynamicCast(event.GetEventObject(), wxFrame);
286 long int style = pWin->GetWindowStyle();
287 if (event.GetActive())
288 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
290 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
293 void RoutePropDlgImpl::RecalculateSize(
void) {
295 esize.x = GetCharWidth() * 110;
296 esize.y = GetCharHeight() * 40;
298 wxSize dsize = GetParent()->GetSize();
299 esize.y = wxMin(esize.y, dsize.y - 0 );
300 esize.x = wxMin(esize.x, dsize.x - 0 );
303 wxSize fsize = GetSize();
304 wxSize canvas_size = GetParent()->GetSize();
305 wxPoint screen_pos = GetParent()->GetScreenPosition();
306 int xp = (canvas_size.x - fsize.x) / 2;
307 int yp = (canvas_size.y - fsize.y) / 2;
308 Move(screen_pos.x + xp, screen_pos.y + yp);
311 void RoutePropDlgImpl::UpdatePoints() {
312 if (!m_pRoute)
return;
313 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
314 int selected_row = m_dvlcWaypoints->GetSelectedRow();
315 m_dvlcWaypoints->DeleteAllItems();
317 wxVector<wxVariant> data;
319 m_pRoute->UpdateSegmentDistances(
320 m_pRoute->m_PlannedSpeed);
321 m_tcDistance->SetValue(
322 wxString::Format(wxT(
"%5.1f ") + getUsrDistanceUnit(),
323 toUsrDistance(m_pRoute->m_route_length)));
324 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->m_route_time)));
326 wxRoutePointListNode* pnode = m_pRoute->pRoutePointList->GetFirst();
328 wxString slen, eta, ete;
329 double bearing, distance, speed;
330 double totalDistance = 0;
331 wxDateTime eta_dt = wxInvalidDateTime;
333 speed = pnode->GetData()->GetPlannedSpeed();
335 speed = m_pRoute->m_PlannedSpeed;
338 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
339 pnode->GetData()->GetLongitude(), gLat, gLon,
340 &bearing, &distance);
341 if (m_pRoute->m_PlannedDeparture.IsValid()) {
342 eta = wxString::Format(
343 "Start: %s", toUsrDateTime(m_pRoute->m_PlannedDeparture,
344 m_tz_selection, pnode->GetData()->m_lon)
345 .Format(ETA_FORMAT_STR)
347 eta.Append(wxString::Format(
349 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
350 pnode->GetData()->m_lon,
351 m_pRoute->m_PlannedDeparture))
353 eta_dt = m_pRoute->m_PlannedDeparture;
358 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
363 distance = pnode->GetData()->GetDistance();
364 bearing = pnode->GetData()->GetCourse();
365 if (pnode->GetData()->GetETA().IsValid()) {
366 eta = toUsrDateTime(pnode->GetData()->GetETA(), m_tz_selection,
367 pnode->GetData()->m_lon)
368 .Format(ETA_FORMAT_STR);
369 eta.Append(wxString::Format(
371 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
372 pnode->GetData()->m_lon,
373 pnode->GetData()->GetETA()))
375 eta_dt = pnode->GetData()->GetETA();
379 ete = pnode->GetData()->GetETE();
380 totalDistance += distance;
382 wxString name = pnode->GetData()->GetName();
383 double lat = pnode->GetData()->GetLatitude();
384 double lon = pnode->GetData()->GetLongitude();
385 wxString tide_station = pnode->GetData()->m_TideStation;
386 wxString desc = pnode->GetData()->GetDescription();
388 if (pnode->GetData()->GetManualETD().IsValid()) {
390 etd = toUsrDateTime(pnode->GetData()->GetManualETD(),
391 0 , pnode->GetData()->m_lon)
392 .Format(ETA_FORMAT_STR);
393 if (pnode->GetData()->GetManualETD().IsValid() &&
394 pnode->GetData()->GetETA().IsValid() &&
395 pnode->GetData()->GetManualETD() < pnode->GetData()->GetETA()) {
402 pnode = pnode->GetNext();
405 crs = formatAngle(pnode->GetData()->GetCourse());
411 data.push_back(wxVariant(
"---"));
413 std::ostringstream stm;
415 data.push_back(wxVariant(stm.str()));
418 wxString schar = wxEmptyString;
420 schar = wxString(
" ");
422 data.push_back(wxVariant(name + schar));
423 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(), toUsrDistance(distance));
424 data.push_back(wxVariant(schar + slen + schar));
425 data.push_back(wxVariant(schar + formatAngle(bearing)));
426 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(),
427 toUsrDistance(totalDistance));
428 data.push_back(wxVariant(schar + slen + schar));
429 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
430 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
431 data.push_back(wxVariant(schar + ete + schar));
432 data.push_back(schar + eta + schar);
434 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
435 data.push_back(wxVariant(
436 MakeTideInfo(tide_station, lat, lon, eta_dt)));
437 data.push_back(wxVariant(desc));
438 data.push_back(wxVariant(crs));
439 data.push_back(wxVariant(etd));
440 data.push_back(wxVariant(
443 m_dvlcWaypoints->AppendItem(data);
447 if (selected_row > 0) {
448 m_dvlcWaypoints->SelectRow(selected_row);
449 m_dvlcWaypoints->EnsureVisible(selection);
453 wxDateTime RoutePropDlgImpl::toUsrDateTime(
const wxDateTime ts,
454 const int format,
const double lon) {
459 switch (m_tz_selection) {
461 if (std::isnan(lon)) {
462 dt = wxInvalidDateTime;
465 ts.Add(wxTimeSpan(wxTimeSpan(0, 0, wxLongLong(lon * 3600. / 15.))));
478 wxDateTime RoutePropDlgImpl::fromUsrDateTime(
const wxDateTime ts,
485 switch (m_tz_selection) {
487 if (std::isnan(lon)) {
488 dt = wxInvalidDateTime;
490 dt = ts.Subtract(wxTimeSpan(0, 0, wxLongLong(lon * 3600. / 15.)));
503 void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
504 if (NULL == pR)
return;
510 m_OrigRoute.m_PlannedDeparture = pR->m_PlannedDeparture;
511 m_OrigRoute.m_PlannedSpeed = pR->m_PlannedSpeed;
514 pR->GetName() == wxEmptyString ? _(
"Route Properties") : pR->GetName();
515 if (!pR->m_bIsInLayer)
518 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title, _(
"Layer"),
519 GetLayerName(pR->m_LayerID)));
525 if (!pR->m_PlannedDeparture.IsValid())
526 pR->m_PlannedDeparture = wxDateTime::Now().ToUTC();
529 if (pR != m_pRoute) {
530 if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_UTC)
532 else if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_LOCAL)
534 m_pEnroutePoint = NULL;
540 m_tcPlanSpeed->SetValue(
541 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
543 if (m_scrolledWindowLinks) {
544 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
545 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
546 wxWindowListNode* node = kids.Item(i);
547 wxWindow* win = node->GetData();
548 if (win->IsKindOf(CLASSINFO(wxHyperlinkCtrl))) {
549 ((wxHyperlinkCtrl*)win)
551 wxEVT_COMMAND_HYPERLINK,
552 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
553 ((wxHyperlinkCtrl*)win)
556 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
560 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
561 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
562 if (NbrOfLinks > 0) {
563 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
566 wxString Link = link->Link;
567 wxString Descr = link->DescrText;
569 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
570 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
571 wxDefaultSize, wxHL_DEFAULT_STYLE);
573 wxEVT_COMMAND_HYPERLINK,
574 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
576 if (!m_pRoute->m_bIsInLayer) {
579 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
582 bSizerLinks->Add(ctrl, 0, wxALL, 5);
584 linknode = linknode->GetNext();
587 m_scrolledWindowLinks->InvalidateBestSize();
588 m_scrolledWindowLinks->Layout();
589 bSizerLinks->Layout();
592 m_choiceTimezone->SetSelection(m_tz_selection);
595 m_tcName->SetValue(m_pRoute->m_RouteNameString);
596 m_tcFrom->SetValue(m_pRoute->m_RouteStartString);
597 m_tcTo->SetValue(m_pRoute->m_RouteEndString);
598 m_tcDescription->SetValue(m_pRoute->m_RouteDescription);
600 m_tcName->SetFocus();
601 if (m_pRoute->m_PlannedDeparture.IsValid() &&
602 m_pRoute->m_PlannedDeparture.GetValue() > 0) {
603 m_dpDepartureDate->SetValue(
604 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
605 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
607 m_tpDepartureTime->SetValue(toUsrDateTime(
608 m_pRoute->m_PlannedDeparture, m_tz_selection,
609 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
611 m_dpDepartureDate->SetValue(
612 toUsrDateTime(wxDateTime::Now(), m_tz_selection,
613 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
615 m_tpDepartureTime->SetValue(toUsrDateTime(
616 wxDateTime::Now(), m_tz_selection,
617 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
621 m_btnSplit->Enable(
false);
622 if (!m_pRoute)
return;
624 if (m_pRoute->m_Colour == wxEmptyString) {
625 m_choiceColor->Select(0);
627 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
629 if (m_pRoute->m_Colour == ::GpxxColorNames[i]) {
630 m_choiceColor->Select(i + 1);
636 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
637 if (m_pRoute->m_style == ::StyleValues[i]) {
638 m_choiceStyle->Select(i);
643 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
644 if (m_pRoute->m_width == ::WidthValues[i]) {
645 m_choiceWidth->Select(i);
652 m_btnExtend->Enable(IsThisRouteExtendable());
655 void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
656 if (!m_pRoute)
return;
657 m_pRoute->SetDepartureDate(GetDepartureTS());
662 void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
663 if (!m_pRoute)
return;
664 m_pRoute->SetDepartureDate(GetDepartureTS());
669 void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
670 m_tz_selection = m_choiceTimezone->GetSelection();
671 m_dpDepartureDate->SetValue(
672 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
673 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
675 m_tpDepartureTime->SetValue(
676 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
677 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
682 void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
683 if (!m_pRoute)
return;
685 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
686 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
687 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
691 m_tcPlanSpeed->SetValue(
692 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
696 void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
697 if (!m_pRoute)
return;
699 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
700 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
701 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
705 m_tcPlanSpeed->SetValue(
706 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
712 void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
713 wxDataViewEvent& event) {
717 ev_col =
event.GetColumn();
720 void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
721 wxDataViewEvent& event) {
722 #if wxCHECK_VERSION(3, 1, 2)
724 if (!m_pRoute)
return;
725 wxDataViewModel*
const model =
event.GetModel();
727 model->GetValue(value, event.GetItem(), ev_col);
729 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
730 if (ev_col == COLUMN_PLANNED_SPEED) {
732 if (!value.GetString().ToDouble(&spd)) {
735 p->SetPlannedSpeed(fromUsrSpeed(spd));
736 }
else if (ev_col == COLUMN_ETD) {
737 wxString::const_iterator end;
740 wxString ts = value.GetString();
741 if (ts.StartsWith(
"!")) {
742 ts.Replace(
"!", wxEmptyString,
true);
748 if (!etd.ParseDateTime(ts, &end)) {
749 p->SetETD(wxInvalidDateTime);
752 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
755 p->SetETD(wxInvalidDateTime);
762 void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
763 wxDataViewEvent& event) {
764 long selected_row = m_dvlcWaypoints->GetSelectedRow();
765 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
766 m_btnSplit->Enable(
true);
768 m_btnSplit->Enable(
false);
770 if (IsThisRouteExtendable()) {
771 m_btnExtend->Enable(
true);
773 m_btnExtend->Enable(
false);
775 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
776 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
778 if (gFrame->GetFocusCanvas()) {
779 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), prp->m_lat,
781 gFrame->GetFocusCanvas()->GetVPScale());
784 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
790 wxDateTime RoutePropDlgImpl::GetDepartureTS() {
791 wxDateTime dt = m_dpDepartureDate->GetValue();
792 dt.SetHour(m_tpDepartureTime->GetValue().GetHour());
793 dt.SetMinute(m_tpDepartureTime->GetValue().GetMinute());
794 dt.SetSecond(m_tpDepartureTime->GetValue().GetSecond());
795 return fromUsrDateTime(
797 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon);
801 void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
802 wxString tab(
"\t", wxConvUTF8);
803 wxString eol(
"\n", wxConvUTF8);
806 csvString << this->GetTitle() << eol << _(
"Name") << tab
807 << m_pRoute->m_RouteNameString << eol << _(
"Depart From") << tab
808 << m_pRoute->m_RouteStartString << eol << _(
"Destination") << tab
809 << m_pRoute->m_RouteEndString << eol << _(
"Total distance") << tab
810 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
811 << m_tcPlanSpeed->GetValue() << eol
812 << _(
"Departure Time") + _T(
" (") + _T(ETA_FORMAT_STR) + _T(
")")
813 << tab << GetDepartureTS().Format(ETA_FORMAT_STR) << eol
814 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
819 noCols = m_dvlcWaypoints->GetColumnCount();
820 noRows = m_dvlcWaypoints->GetItemCount();
822 item.SetMask(wxLIST_MASK_TEXT);
824 for (
int i = 0; i < noCols; i++) {
825 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
826 csvString << col->GetTitle() << tab;
831 for (
int j = 0; j < noRows; j++) {
832 for (
int i = 0; i < noCols; i++) {
833 m_dvlcWaypoints->GetValue(value, j, i);
834 csvString << value.MakeString() << tab;
839 if (wxTheClipboard->Open()) {
840 wxTextDataObject* data =
new wxTextDataObject;
841 data->SetText(csvString);
842 wxTheClipboard->SetData(data);
843 wxTheClipboard->Close();
847 void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
849 switch (event.GetId()) {
850 case ID_RCLK_MENU_COPY_TEXT: {
851 OnRoutepropCopyTxtClick(event);
854 case ID_RCLK_MENU_MOVEUP_WP: {
857 case ID_RCLK_MENU_MOVEDOWN_WP: {
859 moveup ? _(
"Are you sure you want to move Up this waypoint?")
860 : _(
"Are you sure you want to move Down this waypoint?");
862 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
863 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
865 if (dlg_return == wxID_YES) {
866 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
868 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
869 int nRP = m_pRoute->pRoutePointList->IndexOf(pRP) + (moveup ? -1 : 1);
871 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
872 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
874 m_pRoute->pRoutePointList->DeleteObject(pRP);
875 m_pRoute->pRoutePointList->Insert(nRP, pRP);
877 pSelect->AddAllSelectableRouteSegments(m_pRoute);
878 pSelect->AddAllSelectableRoutePoints(m_pRoute);
880 pConfig->UpdateRoute(m_pRoute);
882 m_pRoute->FinalizeForRendering();
883 m_pRoute->UpdateSegmentDistances();
886 gFrame->InvalidateAllGL();
888 m_dvlcWaypoints->SelectRow(nRP);
890 SetRouteAndUpdate(m_pRoute,
true);
894 case ID_RCLK_MENU_DELETE: {
895 int dlg_return = OCPNMessageBox(
896 this, _(
"Are you sure you want to remove this waypoint?"),
897 _(
"OpenCPN Remove Waypoint"),
898 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
900 if (dlg_return == wxID_YES) {
901 int sel = m_dvlcWaypoints->GetSelectedRow();
902 m_dvlcWaypoints->SelectRow(sel);
904 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
906 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
908 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
909 gFrame->InvalidateAllGL();
914 case ID_RCLK_MENU_EDIT_WP: {
915 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
917 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
919 RouteManagerDialog::WptShowPropertiesDialog(std::vector<RoutePoint*> {pRP},
this);
925 void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
926 wxDataViewEvent& event) {
928 if (!m_pRoute->m_bIsInLayer) {
929 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
930 _(
"Waypoint Properties") + _T(
"..."));
931 wxMenuItem* moveUpItem =
932 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
933 wxMenuItem* moveDownItem =
934 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
935 wxMenuItem* delItem =
936 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
938 wxFont* pf = OCPNGetFont(_T(
"Menu"), 0);
939 editItem->SetFont(*pf);
940 moveUpItem->SetFont(*pf);
941 moveDownItem->SetFont(*pf);
942 delItem->SetFont(*pf);
944 #if defined(__WXMSW__)
945 wxFont* pf = GetOCPNScaledFont(_T(
"Menu"));
946 editItem->SetFont(*pf);
947 moveUpItem->SetFont(*pf);
948 moveDownItem->SetFont(*pf);
949 delItem->SetFont(*pf);
952 menu.Append(editItem);
953 if (g_btouch) menu.AppendSeparator();
954 menu.Append(moveUpItem);
955 if (g_btouch) menu.AppendSeparator();
956 menu.Append(moveDownItem);
957 if (g_btouch) menu.AppendSeparator();
958 menu.Append(delItem);
960 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
961 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
962 m_dvlcWaypoints->GetItemCount() > 2);
963 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
964 m_dvlcWaypoints->GetSelectedRow() <
965 m_dvlcWaypoints->GetItemCount() - 1 &&
966 m_dvlcWaypoints->GetItemCount() > 2);
967 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
968 m_dvlcWaypoints->GetItemCount() > 2);
971 wxMenuItem* copyItem =
972 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
974 #if defined(__WXMSW__)
975 wxFont* qFont = GetOCPNScaledFont(_T(
"Menu"));
976 copyItem->SetFont(*qFont);
979 if (g_btouch) menu.AppendSeparator();
980 menu.Append(copyItem);
986 void RoutePropDlgImpl::ResetChanges() {
987 if (!m_pRoute)
return;
988 m_pRoute->m_PlannedSpeed = m_OrigRoute.m_PlannedSpeed;
989 m_pRoute->m_PlannedDeparture = m_OrigRoute.m_PlannedDeparture;
993 void RoutePropDlgImpl::SaveChanges() {
994 if (m_pRoute && !m_pRoute->m_bIsInLayer) {
996 m_pRoute->m_RouteNameString = m_tcName->GetValue();
997 m_pRoute->m_RouteStartString = m_tcFrom->GetValue();
998 m_pRoute->m_RouteEndString = m_tcTo->GetValue();
999 m_pRoute->m_RouteDescription = m_tcDescription->GetValue();
1000 if (m_choiceColor->GetSelection() == 0) {
1001 m_pRoute->m_Colour = wxEmptyString;
1003 m_pRoute->m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
1006 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
1007 m_pRoute->m_width = ::WidthValues[m_choiceWidth->GetSelection()];
1008 switch (m_tz_selection) {
1010 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_PC;
1013 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_LOCAL;
1016 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_UTC;
1019 pConfig->UpdateRoute(m_pRoute);
1020 pConfig->UpdateSettings();
1025 void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
1027 void RoutePropDlgImpl::SaveGeometry() {
1028 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1029 GetPosition(&g_route_prop_x, &g_route_prop_y);
1032 void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1034 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1035 pRouteManagerDialog->UpdateRouteListCtrl();
1041 void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1042 m_btnSplit->Enable(
false);
1044 if (m_pRoute->m_bIsInLayer)
return;
1046 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1047 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1048 m_pHead =
new Route();
1049 m_pTail =
new Route();
1050 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1051 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1053 pRouteList->Append(m_pHead);
1054 pConfig->AddNewRoute(m_pHead);
1056 pRouteList->Append(m_pTail);
1057 pConfig->AddNewRoute(m_pTail);
1059 pConfig->DeleteConfigRoute(m_pRoute);
1061 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1062 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1063 g_pRouteMan->
DeleteRoute(m_pRoute, NavObjectChanges::getInstance());
1064 pSelect->AddAllSelectableRouteSegments(m_pTail);
1065 pSelect->AddAllSelectableRoutePoints(m_pTail);
1066 pSelect->AddAllSelectableRouteSegments(m_pHead);
1067 pSelect->AddAllSelectableRoutePoints(m_pHead);
1069 SetRouteAndUpdate(m_pTail);
1072 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1073 pRouteManagerDialog->UpdateRouteListCtrl();
1077 void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1080 dlg->ShowWindowModalThenDo([
this, dlg](
int retcode) {
1081 if (retcode == wxID_OK) {
1086 void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1087 m_btnExtend->Enable(
false);
1089 if (IsThisRouteExtendable()) {
1090 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1091 int to = m_pExtendRoute->GetnPoints();
1093 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1094 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1095 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1096 SetRouteAndUpdate(m_pRoute);
1100 m_btnExtend->Enable(
true);
1103 bool RoutePropDlgImpl::IsThisRouteExtendable() {
1104 m_pExtendRoute = NULL;
1105 m_pExtendPoint = NULL;
1106 if (m_pRoute->m_bRtIsActive || m_pRoute->m_bIsInLayer)
return false;
1108 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1109 wxArrayPtrVoid* pEditRouteArray;
1111 pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(pLastPoint);
1114 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1115 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1116 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1117 pEditRouteArray->RemoveAt(i - 1);
1119 if (pEditRouteArray->GetCount() == 1) {
1120 m_pExtendPoint = pLastPoint;
1122 if (pEditRouteArray->GetCount() == 0) {
1123 int nearby_radius_meters =
1124 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1125 double rlat = pLastPoint->m_lat;
1126 double rlon = pLastPoint->m_lon;
1128 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1129 rlat, rlon, nearby_radius_meters, pLastPoint->m_GUID);
1130 if (m_pExtendPoint) {
1131 wxArrayPtrVoid* pCloseWPRouteArray =
1132 g_pRouteMan->GetRouteArrayContaining(m_pExtendPoint);
1133 if (pCloseWPRouteArray) {
1134 pEditRouteArray = pCloseWPRouteArray;
1137 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1138 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1139 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1140 pEditRouteArray->RemoveAt(i - 1);
1146 if (pEditRouteArray->GetCount() == 1) {
1148 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1149 int to = p->GetnPoints();
1152 delete pEditRouteArray;
1156 delete pEditRouteArray;
1161 wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1162 double lon, wxDateTime utcTime) {
1163 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1165 if (stationName.IsEmpty()) {
1166 return wxEmptyString;
1168 if (!utcTime.IsValid()) {
1169 return _(
"Invalid date/time!");
1171 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1172 if (stationID == 0) {
1173 return _(
"Unknown station!");
1175 time_t dtmtt = utcTime.FromUTC().GetTicks();
1176 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1179 dtm.Set(dtmtt).MakeUTC();
1181 wxString tide_form = wxEmptyString;
1184 tide_form.Append(_T(
"LW: "));
1185 }
else if (ev == 2) {
1186 tide_form.Append(_T(
"HW: "));
1187 }
else if (ev == 0) {
1188 tide_form.Append(_(
"Unavailable: "));
1192 ptcmgr->GetStationTimeOffset((
IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1195 toUsrDateTime(dtm, m_tz_selection, lon).Format(ETA_FORMAT_STR));
1196 dtm.Add(wxTimeSpan(0, offset, 0));
1197 tide_form.Append(wxString::Format(_T(
" (") + _(
"Local") + _T(
": %s) @ %s"),
1198 dtm.Format(ETA_FORMAT_STR),
1199 stationName.c_str()));
1204 void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1205 wxString findurl = m_pEditedLink->GetURL();
1206 wxString findlabel = m_pEditedLink->GetLabel();
1209 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1210 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1211 DimeControl(LinkPropDlg);
1212 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1213 findlabel](
int retcode) {
1214 if (retcode == wxID_OK) {
1215 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1216 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1218 if (NbrOfLinks > 0) {
1219 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1222 wxString Link = link->Link;
1223 wxString Descr = link->DescrText;
1224 if (Link == findurl &&
1225 (Descr == findlabel ||
1226 (Link == findlabel && Descr == wxEmptyString))) {
1227 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1229 LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1230 wxHyperlinkCtrl* h =
1231 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1234 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1235 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1238 linknode = linknode->GetNext();
1242 m_scrolledWindowLinks->InvalidateBestSize();
1243 m_scrolledWindowLinks->Layout();
1244 bSizerLinks->Layout();
1250 void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1251 AddLinkOnButtonClick(event);
1255 wxHyperlinkListNode* nodeToDelete = NULL;
1256 wxString findurl = m_pEditedLink->GetURL();
1257 wxString findlabel = m_pEditedLink->GetLabel();
1259 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1260 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1261 wxWindowListNode* node = kids.Item(i);
1262 wxWindow* win = node->GetData();
1264 if (win->IsKindOf(CLASSINFO(wxHyperlinkCtrl))) {
1265 ((wxHyperlinkCtrl*)win)
1267 wxEVT_COMMAND_HYPERLINK,
1268 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1269 ((wxHyperlinkCtrl*)win)
1272 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1278 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1279 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1281 if (NbrOfLinks > 0) {
1282 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1285 wxString Link = link->Link;
1286 wxString Descr = link->DescrText;
1287 if (Link == findurl &&
1288 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1289 nodeToDelete = linknode;
1291 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1292 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1293 wxDefaultSize, wxHL_DEFAULT_STYLE);
1295 wxEVT_COMMAND_HYPERLINK,
1296 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1300 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1303 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1305 linknode = linknode->GetNext();
1309 hyperlinklist->DeleteNode(nodeToDelete);
1311 m_scrolledWindowLinks->InvalidateBestSize();
1312 m_scrolledWindowLinks->Layout();
1313 bSizerLinks->Layout();
1317 void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1319 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1320 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1321 DimeControl(LinkPropDlg);
1322 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1323 if (retcode == wxID_OK) {
1324 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1325 if (desc == wxEmptyString)
1326 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1327 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1328 m_scrolledWindowLinks, wxID_ANY, desc,
1329 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1330 wxDefaultSize, wxHL_DEFAULT_STYLE);
1331 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1332 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1334 ctrl->Connect(wxEVT_RIGHT_DOWN,
1335 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1338 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1339 m_scrolledWindowLinks->InvalidateBestSize();
1340 m_scrolledWindowLinks->Layout();
1341 bSizerLinks->Layout();
1344 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1345 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1346 h->LType = wxEmptyString;
1347 m_pRoute->m_HyperlinkList->Append(h);
1352 void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1353 if (m_toggleBtnEdit->GetValue()) {
1354 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1356 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1361 void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1362 if (m_toggleBtnEdit->GetValue()) {
1363 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1364 ItemEditOnMenuSelection(event);
1377 wxString cc =
event.GetURL();
1378 if (cc.Find(_T(
"#")) != wxNOT_FOUND) {
1380 wxString(_T(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command")));
1381 if (RegKey.Exists()) {
1382 wxString command_line;
1383 RegKey.QueryValue(wxString(_T(
"")), command_line);
1386 command_line.Replace(wxString(_T(
"\"")), wxString(_T(
"")));
1389 int l = command_line.Find(_T(
".exe"));
1390 if (wxNOT_FOUND == l) l = command_line.Find(_T(
".EXE"));
1392 if (wxNOT_FOUND != l) {
1393 wxString cl = command_line.Mid(0, l + 4);
1395 cc.Prepend(_T(
"\""));
1396 cc.Append(_T(
"\""));
1404 wxString url =
event.GetURL();
1405 url.Replace(_T(
" "), _T(
"%20"));
1406 ::wxLaunchDefaultBrowser(url);
1410 void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1411 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1412 m_scrolledWindowLinks->PopupMenu(
1413 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1414 m_pEditedLink->GetPosition().y +
event.GetPosition().y);
void ItemDeleteOnMenuSelection(wxCommandEvent &event)
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
General purpose GUI support.