26#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
39#include <wx/wfstream.h>
42#include <unordered_map>
48enum { SAILDOCS, ZYGRIB };
49enum { GFS, COAMPS, RTOFS, HRRR, ICON, ECMWF };
51wxString toMailFormat(
int NEflag,
54 char c = NEflag == 1 ? a < 0 ?
'S' :
'N' : a < 0 ?
'W' :
'E';
56 s.Printf(
"%01d%c", abs(a), c);
71 m_boundingBoxCanvasIndex = -1;
74#if defined(__WXOSX__) || defined(__WXGTK3__)
76 m_displayScale = wxWindow::GetContentScaleFactor();
82 m_downloading =
false;
83 m_bTransferSuccess =
true;
86 auto bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)
87 .GetAsString(wxC2S_HTML_SYNTAX);
88 auto fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)
89 .GetAsString(wxC2S_HTML_SYNTAX);
90 m_htmlWinWorld->SetBorders(10);
91 m_htmlWinWorld->SetPage(
92 "<html><body bgcolor="
101 _(
"<h1>OpenCPN world forecast</h1>"
102 "<p>Free service providing GRIB files from global weather and ocean "
103 "models based on open data published by their respective "
105 "<p>Select the model and the forecast length in hours. The length "
106 "counts from the start of the model run, not from the time of "
107 "download, and newly published runs are usually several hours old, "
108 "so the forecast reaches correspondingly less far into the future. "
109 "The maximum length depends on the selected model.</p>"
110 "<p>The data is updated as soon as new model runs finish and the "
111 "results are published by their producers.</p>"
112 "<p>The grib downloaded covers the area of the primary chart "
114 "<p>The service is provided on best effort basis and comes with no "
115 "guarantees. The server is hosted by a volunteer and the service is "
116 "provided free of charge and without accepting any liability "
117 "whatsoever for its continuous availability, or for any loss or damage "
118 "arising from its use. If you find the service useful, please "
119 "consider making a donation to the OpenCPN project.</p>"
120 "<p>Sources: European Centre for Medium-Range Weather Forecasts "
121 "(ECMWF, www.ecmwf.int, CC-BY-4.0), Deutscher Wetterdienst (DWD), "
122 "NOAA, Environment and Climate Change Canada (ECCC) and "
123 "Météo-France.</p>"
124 "<p>SMOC currents: Generated using E.U. Copernicus Marine Service "
125 "Information; https://doi.org/10.48670/moi-00016</p>"
126 "<p>Disclaimer: The data producers do not accept any liability "
127 "whatsoever for any error or omission in the data, their "
128 "availability, or for any loss or damage arising from their use.</p>"
129 "</font></body></html>"));
130 m_htmlInfoWin->SetBorders(10);
131 m_htmlInfoWin->SetPage(
132 "<html><body bgcolor="
141 _(
"<h1>Grib weather forecasts</h1>"
142 "<p>Collection of local weather models from various sources available "
143 "for download over the internet.</p>"
144 "</font></body></html>"));
146 m_bLocal_source_selected =
false;
147 EnableDownloadButtons();
149 m_selectedAtmModelIndex = 0;
150 m_selectedWaveModelIndex = 0;
151 InitializeXygribDialog();
154GribRequestSetting::~GribRequestSetting() {
160 wxEVT_DOWNLOAD_EVENT,
161 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
168void GribRequestSetting::SaveConfig() {
171 pConf->SetPath(
"/PlugIns/GRIB");
173 pConf->Write(
"MailRequestConfig", m_RequestConfigBase);
174 pConf->Write(
"MailSenderAddress", m_pSenderAddress->GetValue());
175 pConf->Write(
"MailRequestAddresses", m_MailToAddresses);
176 pConf->Write(
"ZyGribLogin", m_pLogin->GetValue());
177 pConf->Write(
"ZyGribCode", m_pCode->GetValue());
178 pConf->Write(
"SendMailMethod", m_SendMethod);
179 pConf->Write(
"MovingGribSpeed", m_sMovingSpeed->GetValue());
180 pConf->Write(
"MovingGribCourse", m_sMovingCourse->GetValue());
188 pConf->Write(
"RequestZoneMaxLat",
m_spMaxLat->GetValue());
189 pConf->Write(
"RequestZoneMinLat",
m_spMinLat->GetValue());
190 pConf->Write(
"RequestZoneMaxLon",
m_spMaxLon->GetValue());
191 pConf->Write(
"RequestZoneMinLon",
m_spMinLon->GetValue());
193 int sel = m_chWorldModel->GetSelection();
194 if (sel != wxNOT_FOUND) {
195 pConf->Write(
"WorldModel", m_world_models[sel][
"name"].AsString());
197 pConf->Write(
"WorldForecastLength", m_spForecastLength->GetValue());
201void GribRequestSetting::InitRequestConfig() {
205 pConf->SetPath(
"/PlugIns/GRIB");
208 pConf->Read(
"MailRequestConfig", &m_RequestConfigBase,
"000220XX........0");
209 pConf->Read(
"MailSenderAddress", &l,
"");
210 m_pSenderAddress->ChangeValue(l);
211 pConf->Read(
"MailRequestAddresses", &m_MailToAddresses,
212 "query@saildocs.com;gribauto@zygrib.org");
213 pConf->Read(
"ZyGribLogin", &l,
"");
214 m_pLogin->ChangeValue(l);
215 pConf->Read(
"ZyGribCode", &l,
"");
216 m_pCode->ChangeValue(l);
217 pConf->Read(
"SendMailMethod", &m_SendMethod, 0);
218 pConf->Read(
"MovingGribSpeed", &m, 0);
219 m_sMovingSpeed->SetValue(m);
220 pConf->Read(
"MovingGribCourse", &m, 0);
221 m_sMovingCourse->SetValue(m);
222 pConf->Read(
"ManualRequestZoneSizingMode", &m, 0);
224 pConf->Read(
"ManualRequestZoneSizing", &m, 0);
231 UpdateAreaSelectionState();
232 pConf->Read(
"RequestZoneMaxLat", &m, 0);
234 pConf->Read(
"RequestZoneMinLat", &m, 0);
236 pConf->Read(
"RequestZoneMaxLon", &m, 0);
238 pConf->Read(
"RequestZoneMinLon", &m, 0);
240 pConf->Read(
"WorldModel", &l,
"");
241 if (FindWorldModel(l) != wxNOT_FOUND) {
242 m_chWorldModel->SetSelection(FindWorldModel(l));
244 pConf->Read(
"WorldForecastLength", &m, 24);
245 m_spForecastLength->SetValue(m);
247 OnWorldModelChoice(evt);
249 SetCoordinatesText();
252 if (m_RequestConfigBase.Len() != wxString(
"000220XX..............").Len())
253 m_RequestConfigBase =
"000220XX..............";
256 wxString s1[] = {
"GFS",
"COAMPS",
"RTOFS",
"HRRR",
"ICON",
"ECMWF"};
257 for (
unsigned int i = 0; i < (
sizeof(s1) /
sizeof(wxString)); i++)
258 m_pModel->Append(s1[i]);
259 wxString s2[] = {
"Saildocs",
"zyGrib"};
260 for (
unsigned int i = 0; i < (
sizeof(s2) /
sizeof(wxString)); i++)
261 m_pMailTo->Append(s2[i]);
262 wxString s3[] = {
"WW3-GLOBAL",
"WW3-MEDIT"};
263 for (
unsigned int i = 0; i < (
sizeof(s3) /
sizeof(wxString)); i++)
264 m_pWModel->Append(s3[i]);
267 m_tResUnit->SetLabel(wxString::Format(
"\u00B0"));
268 m_sCourseUnit->SetLabel(wxString::Format(
"\u00B0"));
272 GetTextExtent(
"-360", &w, &h,
nullptr,
nullptr,
276 m_sMovingSpeed->SetMinSize(wxSize(w, h));
277 m_sMovingCourse->SetMinSize(wxSize(w, h));
284 m_pSenderAddress->SetToolTip(
285 _(
"Address used to send request eMail. (Mandatory for LINUX)"));
286 m_pLogin->SetToolTip(_(
"This is your zyGrib's forum access Login"));
288 _(
"Get this Code in zyGrib's forum ( This is not your password! )"));
289 m_sMovingSpeed->SetToolTip(_(
"Enter your forescasted Speed (in Knots)"));
290 m_sMovingCourse->SetToolTip(_(
"Enter your forecasted Course"));
293 ((wxString)m_RequestConfigBase.GetChar(0)).ToLong(&i);
294 m_pMailTo->SetSelection(i);
295 ((wxString)m_RequestConfigBase.GetChar(1)).ToLong(&i);
296 m_pModel->SetSelection(i);
297 m_cMovingGribEnabled->SetValue(m_RequestConfigBase.GetChar(16) ==
299 ((wxString)m_RequestConfigBase.GetChar(2)).ToLong(&i);
300 ((wxString)m_RequestConfigBase.GetChar(3)).ToLong(&j);
301 ((wxString)m_RequestConfigBase.GetChar(4)).ToLong(&k, 16);
305 m_pSenderSizer->ShowItems(
false);
307 if (m_SendMethod == 0)
308 m_pSenderSizer->ShowItems(
false);
310 m_pSenderSizer->ShowItems(
314 m_tMouseEventTimer.Connect(
315 wxEVT_TIMER, wxTimerEventHandler(GribRequestSetting::OnMouseEventTimer),
320 ApplyRequestConfig(i, j, k);
322 ((wxString)m_RequestConfigBase.GetChar(5)).ToLong(&j);
323 m_pWModel->SetSelection(j);
325 m_pWind->Enable(
false);
326 m_pPress->Enable(
false);
331 m_MailImage->SetValue(WriteMail());
334wxWindow *GetGRIBCanvas();
335void GribRequestSetting::OnClose(wxCloseEvent &event) {
338 m_downloading =
false;
339 m_download_handle = 0;
343 wxEVT_DOWNLOAD_EVENT,
344 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
353 m_parent.m_highlight_latmax = 0;
354 m_parent.m_highlight_lonmax = 0;
355 m_parent.m_highlight_latmin = 0;
356 m_parent.m_highlight_lonmin = 0;
360void GribRequestSetting::SetRequestDialogSize() {
363 GetTextExtent(
"abc",
nullptr, &y,
nullptr,
nullptr,
OCPNGetFont(_(
"Dialog")));
364 m_MailImage->SetMinSize(
365 wxSize(-1, ((y * m_MailImage->GetNumberOfLines()) + 10)));
369 m_fgScrollSizer->Fit(m_sScrolledDialog);
372 SetMinSize(wxSize(0, 0));
375 wxWindow *frame = wxTheApp->GetTopWindow();
377 int w = frame->GetClientSize().x;
378 int h = frame->GetClientSize().y;
384 m_sScrolledDialog->SetMinSize(
385 wxSize(wxMin(w, scroll.x),
386 wxMin(h, scroll.y)));
391 wxSize sd = GetSize();
392 if (sd.y == GetClientSize().y) sd.y += 30;
393 SetSize(wxSize(sd.x, sd.y));
394 SetMinSize(wxSize(sd.x, sd.y));
402 if ((fabs(vp->
lat_max) < 90.) && (fabs(lonmax) < 360.)) {
403 if (lonmax < -180.) lonmax += 360.;
404 if (lonmax > 180.) lonmax -= 360.;
406 if ((fabs(vp->
lat_min) < 90.) && (fabs(lonmin) < 360.)) {
407 if (lonmin < -180.) lonmin += 360.;
408 if (lonmin > 180.) lonmin -= 360.;
411 bool bnew_val =
false;
413 if (
m_spMinLon->GetValue() != (
int)floor(lonmin)) bnew_val =
true;
415 if (
m_spMaxLon->GetValue() != (
int)ceil(lonmax)) bnew_val =
true;
423 SetCoordinatesText();
424 m_MailImage->SetValue(WriteMail());
429 if (!(event.ShiftDown() || m_bpManualSelection->GetValue())) {
434 if (event.LeftDown() && !event.Dragging()) {
449 int xm =
event.GetX() * m_displayScale;
450 int ym =
event.GetY() * m_displayScale;
452 if (event.LeftDown() && !event.Dragging()) {
453 m_parent.pParent->SetFocus();
466 SetCoordinatesText();
467 UpdateAreaSelectionState();
468 m_MailImage->SetValue(WriteMail());
471 UpdateGribSizeEstimate();
472 m_boundingBoxCanvasIndex = -1;
473 }
else if (event.Dragging()) {
488 if (!m_tMouseEventTimer.IsRunning())
489 m_tMouseEventTimer.Start(20, wxTIMER_ONE_SHOT);
494void GribRequestSetting::OnMouseEventTimer(wxTimerEvent &event) {
516void GribRequestSetting::SetCoordinatesText() {
517 m_stMaxLatNS->SetLabel(
m_spMaxLat->GetValue() < 0 ? _(
"S") : _(
"N"));
518 m_stMinLonEW->SetLabel(
m_spMinLon->GetValue() < 0 ? _(
"W") : _(
"E"));
519 m_stMaxLonEW->SetLabel(
m_spMaxLon->GetValue() < 0 ? _(
"W") : _(
"E"));
520 m_stMinLatNS->SetLabel(
m_spMinLat->GetValue() < 0 ? _(
"S") : _(
"N"));
524std::string GribRequestSetting::FormatPerLocale(T value) {
525 std::stringstream ss;
527 ss.imbue(std::locale(
""));
532wxString GribRequestSetting::GetDownloadProgressText(
long transferredBytes,
534 if (totalBytes > 0) {
535 return wxString::Format(_(
"Downloading... %s kB / %s kB (%li%%)"),
536 FormatPerLocale(transferredBytes / 1024).c_str(),
537 FormatPerLocale(totalBytes / 1024).c_str(),
538 (
int)((
double)transferredBytes / totalBytes * 100));
540 return wxString::Format(_(
"Downloading... %s kB / ???"),
541 FormatPerLocale(transferredBytes / 1024).c_str());
548 switch (ev.getDLEventCondition()) {
552 Disconnect(wxEVT_DOWNLOAD_EVENT,
556 m_downloading =
false;
557 m_download_handle = 0;
562 switch (m_downloadType) {
564 m_staticTextInfo->SetLabelText(
565 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
569 m_stLocalDownloadInfo->SetLabelText(
570 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
575 m_xygribPanel->m_progress_gauge->SetValue(
576 100 * ev.getTransferred() / ev.getTotal());
579 m_xygribPanel->m_status_text->SetLabel(
580 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
592void GribRequestSetting::OnWorldDownload(wxCommandEvent &event) {
595 m_downloading =
false;
596 m_download_handle = 0;
598 wxEVT_DOWNLOAD_EVENT,
599 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
601 m_btnDownloadWorld->SetLabelText(_(
"Download"));
602 m_staticTextInfo->SetLabelText(_(
"Download canceled"));
605 EnableDownloadButtons();
606 wxTheApp->ProcessPendingEvents();
611 m_downloading =
true;
613 EnableDownloadButtons();
614 m_btnDownloadWorld->SetLabelText(_(
"Cancel"));
615 m_staticTextInfo->SetLabelText(_(
"Preparing data on server..."));
618 m_world_models[m_chWorldModel->GetSelection()][
"name"].
AsString();
619 int length = m_spForecastLength->GetValue();
620 std::ostringstream oss;
621 oss <<
"https://grib.bosun.io/grib?";
622 oss <<
"model=" << model;
627 oss <<
"&length=" << length;
628 oss <<
"&encoding=ccsds";
630 wxString::Format(
"ocpn_%s_%i_%s.grb2", model.c_str(), length,
631 wxDateTime::Now().Format(
"%F-%H-%M"));
632 wxString path = m_parent.GetGribDir();
633 path.Append(wxFileName::GetPathSeparator());
634 path.Append(filename);
638 wxEVT_DOWNLOAD_EVENT,
639 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
642 while (m_downloading) {
643 wxTheApp->ProcessPendingEvents();
647 if (m_bTransferSuccess) {
648 m_staticTextInfo->SetLabelText(
649 wxString::Format(_(
"Download complete: %s"), path.c_str()));
656 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
658 m_parent.SetDialogsStyleSizePosition(
true);
666 if (wxFileName::GetSize(path) < 1024 && f.Open(path)) f.ReadAll(&reason);
667 reason.Trim().Trim(
false);
668 if (reason.IsEmpty() || reason.StartsWith(
"<")) {
669 m_staticTextInfo->SetLabelText(_(
"Download failed"));
671 m_staticTextInfo->SetLabelText(
672 wxString::Format(_(
"Download failed: %s"), reason));
673 m_staticTextInfo->Wrap(m_panelWorld->GetClientSize().x - 10);
674 m_panelWorld->Layout();
678 if (m_canceled || !m_bTransferSuccess) wxRemoveFile(path);
679 m_btnDownloadWorld->SetLabelText(_(
"Download"));
681 EnableDownloadButtons();
684enum LocalSourceItem { SOURCE, AREA, GRIB };
686enum LocalGribDownloadType { DIRECT, MANIFEST, WEBPAGE };
689 GribCatalogInfo(LocalSourceItem type, wxString name, wxString description,
690 wxString url, wxString filename,
691 LocalGribDownloadType download_type,
double latmin,
692 double lonmin,
double latmax,
double lonmax)
695 description(description),
698 download_type(download_type),
703 LocalSourceItem type;
705 wxString description;
708 LocalGribDownloadType download_type;
715void GribRequestSetting::FillTreeCtrl(
wxJSONValue &data) {
716 m_SourcesTreeCtrl1->DeleteAllItems();
718 m_SourcesTreeCtrl1->AddRoot(_(
"Local high resolution forecasts"));
719 if (data.HasMember(
"sources") && data[
"sources"].IsArray()) {
720 for (
int i = 0; i < data[
"sources"].Size(); i++) {
723 LocalSourceItem::SOURCE, source[
"source"].AsString(),
724 source[
"description"].AsString(), source[
"url"].AsString(),
725 wxEmptyString, LocalGribDownloadType::WEBPAGE, 0, 0, 0, 0);
726 wxTreeItemId src_id = m_SourcesTreeCtrl1->AppendItem(
727 root, source[
"source"].AsString(), -1, -1, info);
728 if (source.
HasMember(
"areas") && source[
"areas"].IsArray()) {
729 for (
int j = 0; j < source[
"areas"].
Size(); j++) {
732 LocalSourceItem::AREA, area[
"name"].AsString(),
733 source[
"description"].AsString(), source[
"url"].AsString(),
734 wxEmptyString, LocalGribDownloadType::WEBPAGE,
735 area[
"boundary"][
"lat_min"].AsDouble(),
736 area[
"boundary"][
"lon_min"].AsDouble(),
737 area[
"boundary"][
"lat_max"].AsDouble(),
738 area[
"boundary"][
"lon_max"].AsDouble());
739 m_SourcesTreeCtrl1->AppendItem(src_id, area[
"name"].AsString(), -1,
741 if (area.
HasMember(
"gribs") && area[
"gribs"].IsArray()) {
742 for (
int k = 0; k < area[
"gribs"].
Size(); k++) {
745 LocalSourceItem::GRIB, grib[
"name"].AsString(),
746 source[
"description"].AsString(),
747 grib.
HasMember(
"url") ? grib[
"url"].AsString()
748 : grib[
"cat_url"].AsString(),
749 grib.HasMember(
"filename") ? grib[
"filename"].AsString() :
"",
750 grib.HasMember(
"url") ? LocalGribDownloadType::DIRECT
751 : LocalGribDownloadType::MANIFEST,
752 area[
"boundary"][
"lat_min"].AsDouble(),
753 area[
"boundary"][
"lon_min"].AsDouble(),
754 area[
"boundary"][
"lat_max"].AsDouble(),
755 area[
"boundary"][
"lon_max"].AsDouble());
756 m_SourcesTreeCtrl1->AppendItem(
757 m_SourcesTreeCtrl1->GetLastChild(src_id),
758 grib[
"name"].AsString(), -1, -1, inf_1);
763 m_SourcesTreeCtrl1->CollapseAllChildren(src_id);
766 m_SourcesTreeCtrl1->Expand(root);
769void GribRequestSetting::ReadLocalCatalog() {
771 wxFileInputStream str(m_parent.
pPlugIn->m_local_sources_catalog);
773 reader.
Parse(str, &root);
777void GribRequestSetting::ReadWorldModels() {
778 int sel = m_chWorldModel->GetSelection();
780 sel == wxNOT_FOUND ?
"" : m_world_models[sel][
"name"].
AsString();
782 wxFileInputStream str(m_parent.
pPlugIn->m_world_models_catalog);
784 if (str.IsOk()) reader.
Parse(str, &m_world_models);
785 m_chWorldModel->Clear();
786 for (
int i = 0; i < m_world_models.
Size(); i++) {
787 m_chWorldModel->Append(m_world_models[i][
"title"].AsString());
789 sel = FindWorldModel(current);
790 m_chWorldModel->SetSelection(
791 sel != wxNOT_FOUND ? sel : (m_chWorldModel->IsEmpty() ? wxNOT_FOUND : 0));
793 OnWorldModelChoice(evt);
796int GribRequestSetting::FindWorldModel(
const wxString &name) {
797 for (
int i = 0; i < m_world_models.
Size(); i++) {
798 if (m_world_models[i][
"name"].AsString() == name)
return i;
803void GribRequestSetting::OnUpdateWorldModels(wxCommandEvent &event) {
805 m_downloading =
true;
807 EnableDownloadButtons();
808 m_btnDownloadWorld->SetLabelText(_(
"Cancel"));
809 m_staticTextInfo->SetLabelText(_(
"Downloading model list update..."));
814 wxEVT_DOWNLOAD_EVENT,
815 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
817 wxString tmp = m_parent.
pPlugIn->m_world_models_catalog +
"new";
819 while (m_downloading) {
820 wxTheApp->ProcessPendingEvents();
827 wxFileInputStream str(tmp);
828 if (m_bTransferSuccess && str.IsOk() && reader.
Parse(str, &models) == 0 &&
830 wxRenameFile(tmp, m_parent.
pPlugIn->m_world_models_catalog,
true);
832 m_staticTextInfo->SetLabelText(_(
"Model list update complete."));
834 m_staticTextInfo->SetLabelText(_(
"Model list update failed"));
838 m_btnDownloadWorld->SetLabelText(_(
"Download"));
840 EnableDownloadButtons();
843void GribRequestSetting::OnWorldModelChoice(wxCommandEvent &event) {
844 int sel = m_chWorldModel->GetSelection();
845 if (sel == wxNOT_FOUND)
return;
846 int max = m_world_models[sel][
"maxlength"].
AsInt();
847 m_spForecastLength->SetRange(1, max);
848 m_spForecastLength->SetValue(std::min(m_spForecastLength->GetValue(), max));
851void GribRequestSetting::HighlightArea(
double latmax,
double lonmax,
852 double latmin,
double lonmin) {
853 m_parent.m_highlight_latmax = latmax;
854 m_parent.m_highlight_lonmax = lonmax;
855 m_parent.m_highlight_latmin = latmin;
856 m_parent.m_highlight_lonmin = lonmin;
859void GribRequestSetting::OnLocalTreeSelChanged(wxTreeEvent &event) {
860 wxTreeItemId item = m_SourcesTreeCtrl1->GetSelection();
863 if (src->type == LocalSourceItem::GRIB) {
864 m_stLocalDownloadInfo->SetLabelText(_(
"Download grib..."));
865 m_bLocal_source_selected =
true;
866 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
868 m_stLocalDownloadInfo->SetLabelText(_(
"Select grib..."));
869 m_bLocal_source_selected =
false;
870 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
873 EnableDownloadButtons();
876void GribRequestSetting::OnUpdateLocalCatalog(wxCommandEvent &event) {
879 m_downloading =
false;
880 m_download_handle = 0;
882 wxEVT_DOWNLOAD_EVENT,
883 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
885 m_btnDownloadLocal->SetLabelText(_(
"Download"));
886 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
889 EnableDownloadButtons();
890 wxTheApp->ProcessPendingEvents();
895 m_downloading =
true;
897 EnableDownloadButtons();
898 m_btnDownloadLocal->SetLabelText(_(
"Cancel"));
899 m_stLocalDownloadInfo->SetLabelText(_(
"Downloading catalog update..."));
904 wxEVT_DOWNLOAD_EVENT,
905 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
908 m_parent.
pPlugIn->m_local_sources_catalog +
"new",
909 this, &m_download_handle);
910 while (m_downloading) {
911 wxTheApp->ProcessPendingEvents();
915 if (m_bTransferSuccess) {
916 wxRenameFile(m_parent.
pPlugIn->m_local_sources_catalog +
"new",
917 m_parent.
pPlugIn->m_local_sources_catalog,
true);
919 m_stLocalDownloadInfo->SetLabelText(_(
"Catalog update complete."));
921 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
924 m_btnDownloadLocal->SetLabelText(_(
"Download"));
926 EnableDownloadButtons();
929void GribRequestSetting::OnDownloadLocal(wxCommandEvent &event) {
932 m_downloading =
false;
933 m_download_handle = 0;
935 wxEVT_DOWNLOAD_EVENT,
936 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
938 m_btnDownloadLocal->SetLabelText(_(
"Download"));
939 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
942 EnableDownloadButtons();
943 wxTheApp->ProcessPendingEvents();
948 m_downloading =
true;
950 EnableDownloadButtons();
951 m_btnDownloadLocal->SetLabelText(_(
"Cancel"));
952 m_staticTextInfo->SetLabelText(_(
"Downloading grib..."));
955 m_SourcesTreeCtrl1->GetSelection()));
956 if (!src || src->type != LocalSourceItem::GRIB || src->url.IsEmpty()) {
957 m_downloading =
false;
958 m_stLocalDownloadInfo->SetLabelText(_(
"Download can't be started."));
959 m_btnDownloadWorld->SetLabelText(_(
"Download"));
961 EnableDownloadButtons();
967 wxEVT_DOWNLOAD_EVENT,
968 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
970 wxString url = src->url;
973 if (src->download_type == LocalGribDownloadType::MANIFEST) {
974 wxString path = m_parent.GetGribDir();
975 path.Append(wxFileName::GetPathSeparator());
976 path.Append(
"grib_manifest.json");
978 while (m_downloading) {
979 wxTheApp->ProcessPendingEvents();
984 if (!m_bTransferSuccess) {
986 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
990 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
994 wxFileInputStream str(path);
996 reader.
Parse(str, &root);
998 wxString parsed = root[
"url"].
AsString();
999 if (parsed.StartsWith(
"http")) {
1002 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
1010 m_downloading =
false;
1011 m_download_handle = 0;
1012 Disconnect(wxEVT_DOWNLOAD_EVENT,
1015 m_connected =
false;
1016 m_btnDownloadLocal->SetLabelText(_(
"Download"));
1017 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
1020 EnableDownloadButtons();
1021 wxTheApp->ProcessPendingEvents();
1027 m_downloading =
true;
1032 wxEVT_DOWNLOAD_EVENT,
1033 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
1036 if (!src->filename.IsEmpty()) {
1037 filename = src->filename;
1042 filename.Replace(
"?",
"_");
1043 filename.Replace(
"&",
"_");
1044 if (!(filename.Contains(
".grb2") || filename.Contains(
".grib2") ||
1045 filename.Contains(
".grb") || filename.Contains(
".grib"))) {
1046 filename.Append(
".grb");
1050 wxString path = m_parent.GetGribDir();
1051 path.Append(wxFileName::GetPathSeparator());
1052 path.Append(filename);
1054 while (m_downloading) {
1055 wxTheApp->ProcessPendingEvents();
1059 if (m_bTransferSuccess) {
1060 m_stLocalDownloadInfo->SetLabelText(_(
"Grib download complete."));
1061 m_stLocalDownloadInfo->SetLabelText(
1062 wxString::Format(_(
"Download complete: %s"), path.c_str()));
1063 wxFileName fn(path);
1068 m_parent.OpenFile();
1070 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
1072 m_parent.SetDialogsStyleSizePosition(
true);
1076 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
1079 if (m_canceled || !m_bTransferSuccess) wxRemoveFile(path);
1080 m_btnDownloadWorld->SetLabelText(_(
"Download"));
1082 EnableDownloadButtons();
1085void GribRequestSetting::EnableDownloadButtons() {
1086 switch (m_downloadType) {
1088 m_btnDownloadWorld->Enable(
true);
1089 m_btnDownloadLocal->Enable(
false);
1090 m_buttonUpdateCatalog->Enable(
false);
1091 m_btnUpdateWorldModels->Enable(
false);
1095 m_btnDownloadWorld->Enable(
false);
1096 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
1097 m_buttonUpdateCatalog->Enable(
false);
1098 m_btnUpdateWorldModels->Enable(
false);
1101 m_xygribPanel->m_download_button->Enable(
true);
1104 m_btnDownloadWorld->Enable(m_chWorldModel->GetSelection() != wxNOT_FOUND);
1105 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
1106 m_buttonUpdateCatalog->Enable(
true);
1107 m_btnUpdateWorldModels->Enable(
true);
1108 m_xygribPanel->m_download_button->Enable(
true);
1113void GribRequestSetting::StopGraphicalZoneSelection() {
1133 if (!m_AllowSend)
return;
1139 UpdateGribSizeEstimate();
1142void GribRequestSetting::ApplyRequestConfig(
unsigned rs,
unsigned it,
1145 const wxString res[][RESOLUTIONS] = {
1146 {
"0.25",
"0.5",
"1.0",
"2.0"},
1147 {
"0.2",
"0.8",
"1.6", wxEmptyString},
1148 {
"0.08",
"0.24",
"1.0", wxEmptyString},
1149 {
"0.03",
"0.24",
"1.0", wxEmptyString},
1150 {
"0.0625",
"0.125", wxEmptyString, wxEmptyString},
1151 {
"0.4",
"1.0",
"2.0", wxEmptyString}
1154 IsZYGRIB = m_pMailTo->GetCurrentSelection() == ZYGRIB;
1156 m_pModel->SetSelection(GFS);
1157 IsGFS = m_pModel->GetCurrentSelection() == GFS;
1158 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1159 bool IsHRRR = m_pModel->GetCurrentSelection() == HRRR;
1160 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1161 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1164 m_pResolution->Clear();
1165 if (m_pModel->GetCurrentSelection() >= 0) {
1166 for (
int i = 0; i < RESOLUTIONS; i++) {
1167 if (res[m_pModel->GetCurrentSelection()][i] != wxEmptyString) {
1168 wxString s = res[m_pModel->GetCurrentSelection()][i];
1169 m_pResolution->Append(s);
1173 m_pResolution->SetSelection(rs);
1177 l = (IsGFS || IsRTOFS || IsICON || IsECMWF) ? 3 : IsHRRR ? 1 : 6;
1180 m = IsHRRR ? 2 : 25;
1182 m_pInterval->Clear();
1183 for (
unsigned i = l; i < m; i *= 2)
1184 m_pInterval->Append(wxString::Format(
"%d", i));
1185 m_pInterval->SetSelection(wxMin(it, m_pInterval->GetCount() - 1));
1195 m_pTimeRange->Clear();
1196 for (
unsigned i = 2; i < l + 1; i++)
1197 m_pTimeRange->Append(wxString::Format(
"%d", i));
1198 m_pTimeRange->SetSelection(wxMin(l - 2, tr));
1200 m_pModel->Enable(!IsZYGRIB);
1201 m_pWind->SetValue(!IsRTOFS);
1202 m_pPress->SetValue(!IsRTOFS);
1203 m_pWaves->SetValue(m_RequestConfigBase.GetChar(8) ==
'X' && IsGFS);
1204 m_pWaves->Enable(IsECMWF ||
1205 (IsGFS && m_pTimeRange->GetCurrentSelection() < 7));
1207 m_pRainfall->SetValue(m_RequestConfigBase.GetChar(9) ==
'X' &&
1209 m_pRainfall->Enable(IsGFS || IsHRRR);
1210 m_pCloudCover->SetValue(m_RequestConfigBase.GetChar(10) ==
'X' && IsGFS);
1211 m_pCloudCover->Enable(IsGFS);
1212 m_pAirTemp->SetValue(m_RequestConfigBase.GetChar(11) ==
'X' &&
1213 (IsGFS || IsHRRR || IsICON || IsECMWF));
1214 m_pAirTemp->Enable(IsGFS || IsHRRR || IsICON || IsECMWF);
1215 m_pSeaTemp->SetValue(m_RequestConfigBase.GetChar(12) ==
'X' &&
1216 ((!IsZYGRIB && IsGFS) || IsRTOFS || IsHRRR || IsICON));
1217 m_pSeaTemp->Enable(!IsZYGRIB && (IsGFS || IsHRRR || IsICON));
1218 m_pWindGust->SetValue(m_RequestConfigBase.GetChar(14) ==
'X' &&
1219 (IsGFS || IsHRRR || IsICON));
1220 m_pWindGust->Enable(IsGFS || IsHRRR || IsICON);
1221 m_pCAPE->SetValue(m_RequestConfigBase.GetChar(15) ==
'X' &&
1223 m_pCAPE->Enable(IsGFS || IsHRRR);
1224 m_pReflectivity->Enable(IsGFS || IsHRRR);
1226 m_pAltitudeData->SetValue(
1227 (IsGFS || IsICON || IsECMWF)
1228 ? m_RequestConfigBase.GetChar(17) ==
'X'
1230 m_pAltitudeData->Enable(IsGFS || IsICON || IsECMWF);
1231 m_p850hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(18) ==
'X'
1233 m_p850hpa->Enable(IsZYGRIB);
1234 m_p700hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(19) ==
'X'
1236 m_p700hpa->Enable(IsZYGRIB);
1237 m_p500hpa->SetValue((IsGFS || IsICON || IsECMWF)
1238 ? m_RequestConfigBase.GetChar(20) ==
'X'
1240 m_p500hpa->Enable(IsGFS || IsICON || IsECMWF);
1241 m_p300hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(21) ==
'X'
1243 m_p300hpa->Enable(IsZYGRIB);
1245 m_pCurrent->SetValue(IsRTOFS);
1246 m_pCurrent->Enable(
false);
1249 m_cMovingGribEnabled->Show(!IsZYGRIB);
1250 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1251 m_cMovingGribEnabled->IsShown());
1253 m_fgLog->ShowItems(IsZYGRIB);
1255 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1257 m_fgAltitudeData->ShowItems(
1258 m_pAltitudeData->IsChecked());
1261void GribRequestSetting::OnTopChange(wxCommandEvent &event) {
1263 if (m_pMailTo->GetCurrentSelection() == ZYGRIB) {
1264 m_pMailTo->SetSelection(0);
1267 _(
"Sorry...\nZyGrib momentary stopped providing this service...\nOnly "
1268 "Saildocs option is available"),
1269 _(
"Warning"), wxOK);
1271 ApplyRequestConfig(m_pResolution->GetCurrentSelection(),
1272 m_pInterval->GetCurrentSelection(),
1273 m_pTimeRange->GetCurrentSelection());
1275 m_cMovingGribEnabled->Show(m_pMailTo->GetCurrentSelection() == SAILDOCS);
1277 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1279 SetRequestDialogSize();
1282void GribRequestSetting::UpdateAreaSelectionState() {
1291void GribRequestSetting::OnZoneSelectionModeChange(wxCommandEvent &event) {
1292 StopGraphicalZoneSelection();
1301 }
else if (event.GetId() ==
MANSELECT) {
1307 m_cUseSavedZone->SetValue(
false);
1308 }
else if (event.GetId() ==
SAVEDZONE) {
1316 UpdateAreaSelectionState();
1317 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1319 SetRequestDialogSize();
1333 center.x = x + (zw / 2);
1334 center.y = y + (zh / 2);
1340 wxColour pen_color, back_color;
1341 GetGlobalColor(
"DASHR", &pen_color);
1342 GetGlobalColor(
"YELO1", &back_color);
1344 int label_offsetx = 5, label_offsety = 1;
1347 EstimateFileSize(&size);
1349 wxString label(_(
"Coord. "));
1350 label.Append(toMailFormat(1,
m_spMaxLat->GetValue()) +
" ");
1351 label.Append(toMailFormat(0,
m_spMinLon->GetValue()) +
" ");
1352 label.Append(toMailFormat(1,
m_spMinLat->GetValue()) +
" ");
1353 label.Append(toMailFormat(0,
m_spMaxLon->GetValue()) +
"\n");
1354 label.Append(
"Estim. Size ")
1355 .Append((wxString::Format(
"%1.2f ", size) + _(
"MB")));
1358 wxPen pen(pen_color);
1361 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
1362 m_pdc->DrawRectangle(x, y, zw, zh);
1367 sdc.GetMultiLineTextExtent(label, &w, &h, &sl, font);
1369 m_pdc->GetMultiLineTextExtent(label, &w, &h, &sl, font);
1373 w += 2 * label_offsetx, h += 2 * label_offsety;
1374 x = center.x - (w / 2);
1375 y = center.y - (h / 2);
1377 h *= m_displayScale;
1378 w *= m_displayScale;
1385 mdc.SetBrush(back_color);
1386 mdc.SetPen(*wxTRANSPARENT_PEN);
1387 mdc.SetTextForeground(wxColor(0, 0, 0));
1388 mdc.DrawRectangle(0, 0, w, h);
1389 mdc.DrawLabel(label, wxRect(label_offsetx, label_offsety, w, h));
1391 wxImage im = bm.ConvertToImage();
1393 w = im.GetWidth(), h = im.GetHeight();
1394 for (
int j = 0; j < h; j++)
1395 for (
int i = 0; i < w; i++) im.SetAlpha(i, j, 155);
1397 m_pdc->DrawBitmap(im, x, y,
true);
1401#ifndef USE_ANDROID_GLES2
1408 m_oDC->SetPen(wxPen(pen_color, 3));
1411 outline[0] = wxPoint(x, y);
1412 outline[1] = wxPoint(x + zw, y);
1413 outline[2] = wxPoint(x + zw, y + zh);
1414 outline[3] = wxPoint(x, y + zh);
1415 outline[4] = wxPoint(x, y);
1416 m_oDC->DrawLines(5, outline);
1418 m_oDC->SetFont(*font);
1420 m_oDC->GetTextExtent(label, &w, &h);
1421 h *= m_displayScale;
1422 w *= m_displayScale;
1424 m_oDC->GetTextExtent(
"W", &ww, &hw);
1426 int label_offsetx_ = ww, label_offsety_ = 1;
1427 int x_ = center.x - w / 2;
1428 int y_ = center.y - h / 2;
1430 w += 2 * label_offsetx_, h += 2 * label_offsety_;
1432 m_oDC->SetBrush(wxBrush(back_color));
1433 m_oDC->DrawRoundedRectangle(x_, y_, w, h, 0);
1436 m_oDC->SetPen(wxPen(wxColour(0, 0, 0), 1));
1438 outline[0] = wxPoint(x_, y_);
1439 outline[1] = wxPoint(x_ + w, y_);
1440 outline[2] = wxPoint(x_ + w, y_ + h);
1441 outline[3] = wxPoint(x_, y_ + h);
1442 outline[4] = wxPoint(x_, y_);
1443 m_oDC->DrawLines(5, outline);
1445 m_oDC->DrawText(label, x_ + label_offsetx_, y_ + label_offsety_);
1465void GribRequestSetting::OnMovingClick(wxCommandEvent &event) {
1466 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1467 m_cMovingGribEnabled->IsShown());
1469 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1470 SetRequestDialogSize();
1475void GribRequestSetting::OnCoordinatesChange(wxSpinEvent &event) {
1476 SetCoordinatesText();
1478 StopGraphicalZoneSelection();
1480 if (!m_AllowSend)
return;
1482 m_MailImage->SetValue(WriteMail());
1485void GribRequestSetting::OnAnyChange(wxCommandEvent &event) {
1486 m_fgAltitudeData->ShowItems(m_pAltitudeData->IsChecked());
1488 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1490 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1492 SetRequestDialogSize();
1495void GribRequestSetting::OnTimeRangeChange(wxCommandEvent &event) {
1496 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1498 if (m_pModel->GetCurrentSelection() == 0) {
1499 if (m_pTimeRange->GetCurrentSelection() >
1501 m_pWaves->SetValue(0);
1502 m_pWaves->Enable(
false);
1505 _(
"You request a forecast for more than 8 days horizon.\nThis is "
1506 "conflicting with Wave data which will be removed from your "
1507 "request.\nDon't forget that beyond the first 8 days, the "
1508 "resolution will be only 2.5\u00B0x2.5\u00B0\nand the time "
1509 "intervall 12 hours."),
1512 m_pWaves->Enable(
true);
1515 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1517 SetRequestDialogSize();
1521 bool IsCOAMPS = m_pModel->GetCurrentSelection() == COAMPS;
1522 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1523 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1524 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1525 m_RequestConfigBase.SetChar(
1526 0, (
char)(m_pMailTo->GetCurrentSelection() +
'0'));
1527 m_cMovingGribEnabled->IsChecked()
1528 ? m_RequestConfigBase.SetChar(16,
'X')
1529 : m_RequestConfigBase.SetChar(16,
'.');
1532 m_RequestConfigBase.SetChar(
1533 1, (
char)(m_pModel->GetCurrentSelection() +
'0'));
1535 m_RequestConfigBase.SetChar(
1536 2, (
char)(m_pResolution->GetCurrentSelection() +
'0'));
1538 m_RequestConfigBase.SetChar(3,
1539 (
char)(m_pInterval->GetCurrentSelection() +
'0'));
1542 range.Printf(
"%x", m_pTimeRange->GetCurrentSelection() +
1544 m_RequestConfigBase.SetChar(4, range.GetChar(0));
1546 if (IsZYGRIB && m_pWModel->IsShown())
1547 m_RequestConfigBase.SetChar(
1548 5, (
char)(m_pWModel->GetCurrentSelection() +
'0'));
1550 m_RequestConfigBase.SetChar(
1552 m_RequestConfigBase.SetChar(
1555 if (!IsCOAMPS && !IsRTOFS) {
1556 m_pWindGust->IsChecked() ? m_RequestConfigBase.SetChar(14,
'X')
1557 : m_RequestConfigBase.SetChar(14,
'.');
1558 m_pWaves->IsChecked() ? m_RequestConfigBase.SetChar(8,
'X')
1559 : m_RequestConfigBase.SetChar(8,
'.');
1560 m_pRainfall->IsChecked() ? m_RequestConfigBase.SetChar(9,
'X')
1561 : m_RequestConfigBase.SetChar(9,
'.');
1562 m_pCloudCover->IsChecked() ? m_RequestConfigBase.SetChar(10,
'X')
1563 : m_RequestConfigBase.SetChar(10,
'.');
1564 m_pAirTemp->IsChecked() ? m_RequestConfigBase.SetChar(11,
'X')
1565 : m_RequestConfigBase.SetChar(11,
'.');
1566 m_pSeaTemp->IsChecked() ? m_RequestConfigBase.SetChar(12,
'X')
1567 : m_RequestConfigBase.SetChar(12,
'.');
1568 m_pCAPE->IsChecked() ? m_RequestConfigBase.SetChar(15,
'X')
1569 : m_RequestConfigBase.SetChar(15,
'.');
1572 m_pCurrent->IsChecked() ? m_RequestConfigBase.SetChar(13,
'X')
1573 : m_RequestConfigBase.SetChar(13,
'.');
1575 if (IsGFS || IsICON || IsECMWF) {
1576 m_pAltitudeData->IsChecked()
1577 ? m_RequestConfigBase.SetChar(17,
'X')
1578 : m_RequestConfigBase.SetChar(17,
'.');
1579 m_p500hpa->IsChecked() ? m_RequestConfigBase.SetChar(20,
'X')
1580 : m_RequestConfigBase.SetChar(20,
'.');
1583 m_p850hpa->IsChecked() ? m_RequestConfigBase.SetChar(18,
'X')
1584 : m_RequestConfigBase.SetChar(18,
'.');
1585 m_p700hpa->IsChecked() ? m_RequestConfigBase.SetChar(19,
'X')
1586 : m_RequestConfigBase.SetChar(19,
'.');
1587 m_p300hpa->IsChecked() ? m_RequestConfigBase.SetChar(21,
'X')
1588 : m_RequestConfigBase.SetChar(21,
'.');
1595wxString GribRequestSetting::WriteMail() {
1597 int limit = IsZYGRIB ? 2 : 0;
1601 const wxString s[] = {
",",
" "};
1602 const wxString p[][11] = {
1604 {
"APCP",
"TCDC",
"AIRTMP",
"HTSGW,WVPER,WVDIR",
"SEATMP",
"GUST",
"CAPE",
1605 wxEmptyString, wxEmptyString,
"WIND500,HGT500", wxEmptyString},
1610 {
"",
"",
"AIRTMP",
"",
"SFCTMP",
"GUST",
"",
"",
"",
"WIND500,HGT500",
1613 {
"",
"",
"TEMP",
"WAVES",
"",
"",
"",
"",
"",
"WIND500,HGT500",
""},
1615 {
"PRECIP",
"CLOUD",
"TEMP",
"WVSIG WVWIND", wxEmptyString,
"GUST",
"CAPE",
1616 "A850",
"A700",
"A500",
"A300"}};
1618 wxString r_topmess, r_parameters, r_zone;
1620 switch (m_pMailTo->GetCurrentSelection()) {
1622 r_zone = toMailFormat(1,
m_spMaxLat->GetValue()) +
"," +
1623 toMailFormat(1,
m_spMinLat->GetValue()) +
"," +
1624 toMailFormat(2,
m_spMinLon->GetValue()) +
"," +
1626 r_topmess =
"send ";
1627 r_topmess.Append(m_pModel->GetStringSelection() +
":");
1628 r_topmess.Append(r_zone +
"|");
1629 r_topmess.Append(m_pResolution->GetStringSelection())
1631 .Append(m_pResolution->GetStringSelection())
1634 m_pInterval->GetStringSelection().ToDouble(&v);
1635 r_topmess.Append(wxString::Format(
"0,%d,%d", (
int)v, (
int)v * 2));
1636 m_pTimeRange->GetStringSelection().ToDouble(&v);
1637 r_topmess.Append(wxString::Format(
"..%d", (
int)v * 24) +
"|=\n");
1644 r_zone = toMailFormat(1,
m_spMinLat->GetValue()) +
1645 toMailFormat(2,
m_spMinLon->GetValue()) +
" " +
1647 toMailFormat(2, maxlon);
1648 r_topmess =
"login : ";
1649 r_topmess.Append(m_pLogin->GetValue() +
"\n");
1650 r_topmess.Append(
"code :");
1651 r_topmess.Append(m_pCode->GetValue() +
"\n");
1652 r_topmess.Append(
"area : ");
1653 r_topmess.append(r_zone +
"\n");
1654 r_topmess.Append(
"resol : ");
1655 r_topmess.append(m_pResolution->GetStringSelection() +
"\n");
1656 r_topmess.Append(
"days : ");
1657 r_topmess.append(m_pTimeRange->GetStringSelection() +
"\n");
1658 r_topmess.Append(
"hours : ");
1659 r_topmess.append(m_pInterval->GetStringSelection() +
"\n");
1660 if (m_pWaves->IsChecked()) {
1661 r_topmess.Append(
"waves : ");
1662 r_topmess.append(m_pWModel->GetStringSelection() +
"\n");
1664 r_topmess.Append(
"meteo : ");
1665 r_topmess.append(m_pModel->GetStringSelection() +
"\n");
1666 if (m_pLogin->GetValue().IsEmpty() || m_pCode->GetValue().IsEmpty())
1671 int GFSZ = IsZYGRIB ? 6 : 0;
1672 switch (m_pModel->GetCurrentSelection()) {
1674 r_parameters =
"WIND" + s[m_pMailTo->GetCurrentSelection()] +
1676 if (m_pRainfall->IsChecked())
1677 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1679 if (m_pCloudCover->IsChecked())
1680 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1682 if (m_pAirTemp->IsChecked())
1683 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1685 if (m_pWaves->IsChecked())
1686 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1688 if (m_pSeaTemp->IsChecked())
1689 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1691 if (m_pWindGust->IsChecked())
1692 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1694 if (m_pCAPE->IsChecked())
1695 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1697 if (m_pAltitudeData->IsChecked()) {
1698 if (m_p850hpa->IsChecked())
1699 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1701 if (m_p700hpa->IsChecked())
1702 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1704 if (m_p500hpa->IsChecked())
1705 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1707 if (m_p300hpa->IsChecked())
1708 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1713 r_parameters =
"WIND,PRMSL";
1717 r_parameters =
"CUR,WTMP";
1720 r_parameters =
"WIND,PRMSL";
1722 if (m_pRainfall->IsChecked())
1723 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][0]);
1724 if (m_pAirTemp->IsChecked())
1725 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][2]);
1726 if (m_pSeaTemp->IsChecked())
1727 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][4]);
1728 if (m_pWindGust->IsChecked())
1729 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][5]);
1730 if (m_pCAPE->IsChecked())
1731 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][6]);
1734 r_parameters =
"WIND,PRMSL";
1736 if (m_pAirTemp->IsChecked())
1737 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][2]);
1738 if (m_pSeaTemp->IsChecked())
1739 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][4]);
1740 if (m_pWindGust->IsChecked())
1741 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][5]);
1742 if (m_pAltitudeData->IsChecked()) {
1743 if (m_p500hpa->IsChecked())
1744 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][9]);
1748 r_parameters =
"WIND,MSLP";
1750 if (m_pAirTemp->IsChecked())
1751 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][2]);
1752 if (m_pAltitudeData->IsChecked()) {
1753 if (m_p500hpa->IsChecked())
1754 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1757 if (m_pWaves->IsChecked())
1758 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][3]);
1761 if (!IsZYGRIB && m_cMovingGribEnabled->IsChecked())
1762 r_parameters.Append(wxString::Format(
"|%d,%d", m_sMovingSpeed->GetValue(),
1763 m_sMovingCourse->GetValue()));
1767 char c = m_pMailTo->GetCurrentSelection() == SAILDOCS ?
',' :
' ';
1768 for (
size_t i = 0; i < r_parameters.Len(); i++) {
1769 if (r_parameters.GetChar(i) ==
'|')
1771 if (r_parameters.GetChar(i) == c) j++;
1773 r_parameters.insert(
1774 i + 1, m_pMailTo->GetCurrentSelection() == SAILDOCS ?
"=\n" :
"\n");
1780 m_MailError_Nb += EstimateFileSize(&size);
1782 m_tFileSize->SetLabel(wxString::Format(
"%1.2f ", size) + _(
"MB"));
1785 m_tLimit->SetLabel(wxString(
"( ") + _(
"Max") +
1786 wxString::Format(
" %d ", limit) + _(
"MB") +
" )");
1787 if (size > limit) m_MailError_Nb += 2;
1789 m_tLimit->SetLabel(wxEmptyString);
1791 return wxString(r_topmess + r_parameters);
1794int GribRequestSetting::EstimateFileSize(
double *size) {
1795 if (!size)
return 0;
1799 double reso, time, inter;
1800 m_pResolution->GetStringSelection().ToDouble(&reso);
1801 m_pTimeRange->GetStringSelection().ToDouble(&time);
1802 m_pInterval->GetStringSelection().ToDouble(&inter);
1806 if (maxlat - minlat < 0)
return 3;
1807 double wlon = (maxlon > minlon ? 0 : 360) + maxlon - minlon;
1808 if (wlon > 180 || (maxlat - minlat > 180))
return 4;
1810 if (fabs(wlon) < 2 * reso || maxlat - minlat < 2 * reso)
1813 int npts = (int)(ceil(((
double)(maxlat - minlat) / reso)) *
1814 ceil(((
double)(wlon) / reso)));
1816 if (m_pModel->GetCurrentSelection() == COAMPS)
1817 npts = wxMin(npts, (
int)(ceil(40.0 / reso) * ceil(40.0 / reso)));
1820 int nbrec = (int)(time * 24 / inter) + 1;
1821 int nbPress = (m_pPress->IsChecked()) ? nbrec : 0;
1822 int nbWind = (m_pWind->IsChecked()) ? 2 * nbrec : 0;
1823 int nbwave = (m_pWaves->IsChecked()) ? 2 * nbrec : 0;
1824 int nbRain = (m_pRainfall->IsChecked()) ? nbrec - 1 : 0;
1825 int nbCloud = (m_pCloudCover->IsChecked()) ? nbrec - 1 : 0;
1826 int nbTemp = (m_pAirTemp->IsChecked()) ? nbrec : 0;
1827 int nbSTemp = (m_pSeaTemp->IsChecked()) ? nbrec : 0;
1828 int nbGUSTsfc = (m_pWindGust->IsChecked()) ? nbrec : 0;
1829 int nbCurrent = (m_pCurrent->IsChecked()) ? nbrec : 0;
1830 int nbCape = (m_pCAPE->IsChecked()) ? nbrec : 0;
1832 IsZYGRIB ? 5 * nbrec : 3 * nbrec;
1836 double estime = 0.0;
1840 estime += nbWind * (head + (nbits * npts) / 8 + 2);
1841 estime += nbCurrent * (head + (nbits * npts) / 8 + 2);
1844 estime += nbTemp * (head + (nbits * npts) / 8 + 2);
1845 estime += nbSTemp * (head + (nbits * npts) / 8 + 2);
1848 estime += nbRain * (head + (nbits * npts) / 8 + 2);
1851 estime += nbPress * (head + (nbits * npts) / 8 + 2);
1854 estime += nbCloud * (head + (nbits * npts) / 8 + 2);
1857 estime += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
1860 estime += nbCape * (head + (nbits * npts) / 8 + 2);
1863 estime += nbwave * (head + (nbits * npts) / 8 + 2);
1865 if (m_pAltitudeData->IsChecked()) {
1867 if (m_p850hpa->IsChecked()) nbalt++;
1868 if (m_p700hpa->IsChecked()) nbalt++;
1869 if (m_p500hpa->IsChecked()) nbalt++;
1870 if (m_p300hpa->IsChecked()) nbalt++;
1873 estime += nbAltitude * nbalt * (head + (nbits * npts) / 8 + 2);
1876 *size = estime / (1024. * 1024.);
1881const wxString EncodeURL(
const wxString &uri) {
1882 static std::unordered_map<int, wxString> sEncodeMap = {
1883 {(int)
'!',
"%21"}, {(int)
'#',
"%23"}, {(int)
'$',
"%24"},
1884 {(int)
'&',
"%26"}, {(int)
'\'',
"%27"}, {(int)
'(',
"%28"},
1885 {(int)
')',
"%29"}, {(int)
'*',
"%2A"}, {(int)
'+',
"%2B"},
1886 {(int)
',',
"%2C"}, {(int)
';',
"%3B"}, {(int)
'=',
"%3D"},
1887 {(int)
'?',
"%3F"}, {(int)
'@',
"%40"}, {(int)
'[',
"%5B"},
1888 {(int)
']',
"%5D"}, {(int)
' ',
"%20"}, {(int)
'|',
"%7C"},
1889 {(int)
':',
"%3A"}, {(int)
'\n',
"%0A"}};
1892 for (
size_t i = 0; i < uri.length(); ++i) {
1894 std::unordered_map<int, wxString>::iterator iter = sEncodeMap.find((
int)ch);
1895 if (iter != sEncodeMap.end()) {
1896 encoded << iter->second;
1905 StopGraphicalZoneSelection();
1912 m_MailImage->SetForegroundColour(
1916 m_MailImage->SetValue(WriteMail());
1917 SetRequestDialogSize();
1922 const wxString error[] = {
1924 _(
"Before sending an email to Zygrib you have to enter your Login and "
1925 "Code.\nPlease visit www.zygrib.org/ and follow instructions..."),
1926 _(
"Too big file! zyGrib limit is 2Mb!"),
1927 _(
"Error! Max Lat lower than Min Lat or Max Lon lower than Min Lon!"),
1928 _(
"Too large area! Each side must be less than 180\u00B0!"),
1929 _(
"Too small area for this resolution!")};
1931 ::wxBeginBusyCursor();
1933 m_MailImage->SetForegroundColour(wxColor(255, 0, 0));
1934 m_AllowSend =
false;
1936 if (m_MailError_Nb) {
1937 if (m_MailError_Nb > 7) {
1938 m_MailImage->SetValue(error[1] + error[0] + error[m_MailError_Nb - 6]);
1940 if (m_MailError_Nb == 6) m_MailError_Nb = 1;
1941 m_MailImage->SetValue(error[m_MailError_Nb]);
1945 SetRequestDialogSize();
1947 ::wxEndBusyCursor();
1952 std::string mailto =
1953 (m_pMailTo->GetCurrentSelection() == SAILDOCS
1954 ? m_MailToAddresses.BeforeFirst(
';')
1955 : m_MailToAddresses.AfterFirst(
';').BeforeFirst(
';'))
1957 std::string mailfrom = m_pSenderAddress->GetValue().ToStdString();
1959 std::regex mailregex(
"^([a-z0-9+_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$");
1961 if ((!mailto.empty() && !std::regex_match(mailto, mailregex)) ||
1962 (!mailfrom.empty() && !std::regex_match(mailfrom, mailregex))) {
1965 _(
"Sender or recipient e-mail address seems invalid.\nPlease correct "
1966 "it in the configuration file."),
1967 _(
"Error"), wxOK | wxICON_ERROR);
1977 new wxMailMessage((m_pMailTo->GetCurrentSelection() == SAILDOCS)
1981 EncodeURL(WriteMail()),
1985 new wxMailMessage((m_pMailTo->GetCurrentSelection() == SAILDOCS)
1994 if (mail.Send(*message, m_SendMethod)) {
1996 m_MailImage->SetValue(
1997 _(
"Your request is ready. An email is prepared in your email "
1998 "environment. \nYou have just to verify and send it...\nSave or "
1999 "Cancel to finish...or Continue..."));
2001 if (m_SendMethod == 0) {
2002 m_MailImage->SetValue(
2003 _(
"Your request is ready. An email is prepared in your email "
2004 "environment. \nYou have just to verify and send it...\nSave or "
2005 "Cancel to finish...or Continue..."));
2007 m_MailImage->SetValue(
2008 _(
"Your request was sent \n(if your system has an MTA configured and "
2009 "is able to send email).\nSave or Cancel to finish...or "
2014 m_MailImage->SetValue(
2015 _(
"Request can't be sent. Please verify your email systeme "
2016 "parameters.\nYou should also have a look at your log file.\nSave or "
2017 "Cancel to finish..."));
2021 SetRequestDialogSize();
2023 ::wxEndBusyCursor();
2028wxString GribRequestSetting::BuildXyGribUrl() {
2031 wxString::Format(
"http://grbsrv.opengribs.org/getmygribs2.php?");
2033 urlStr << wxString::Format(
"la1=%.0f", floor(
GetMinLat()));
2034 urlStr << wxString::Format(
"&la2=%.0f", ceil(
GetMaxLat()));
2035 urlStr << wxString::Format(
"&lo1=%.0f", floor(
GetMinLon()));
2036 urlStr << wxString::Format(
"&lo2=%.0f", ceil(
GetMaxLon()));
2039 urlStr << wxString::Format(
2041 xygribAtmModelList[m_selectedAtmModelIndex]
2042 ->reqName[m_xygribPanel->m_resolution_choice->GetSelection()]);
2044 urlStr << wxString::Format(
2046 xygribAtmModelList[m_selectedAtmModelIndex]
2047 ->interval[m_xygribPanel->m_interval_choice->GetSelection()]);
2049 urlStr << wxString::Format(
2050 "&days=%d", m_xygribPanel->m_duration_choice->GetSelection() + 1);
2054 wxString selStr = m_xygribPanel->m_run_choice->GetStringSelection();
2055 if (selStr.IsSameAs(
"18h",
false)) {
2056 urlStr <<
"&cyc=18";
2057 }
else if (selStr.IsSameAs(
"12h",
false)) {
2058 urlStr <<
"&cyc=12";
2059 }
else if (selStr.IsSameAs(
"6h",
false)) {
2060 urlStr <<
"&cyc=06";
2061 }
else if (selStr.IsSameAs(
"0h",
false)) {
2062 urlStr <<
"&cyc=00";
2064 urlStr <<
"&cyc=last";
2069 if (m_xygribPanel->m_wind_cbox->IsEnabled() &&
2070 m_xygribPanel->m_wind_cbox->IsChecked())
2072 if (m_xygribPanel->m_pressure_cbox->IsEnabled() &&
2073 m_xygribPanel->m_pressure_cbox->IsChecked()) {
2074 if (xygribAtmModelList[m_selectedAtmModelIndex]->altPressure) {
2080 if (m_xygribPanel->m_precipitation_cbox->IsEnabled() &&
2081 m_xygribPanel->m_precipitation_cbox->IsChecked())
2083 if (m_xygribPanel->m_cloudcover_cbox->IsEnabled() &&
2084 m_xygribPanel->m_cloudcover_cbox->IsChecked())
2086 if (m_xygribPanel->m_temperature_cbox->IsEnabled() &&
2087 m_xygribPanel->m_temperature_cbox->IsChecked())
2089 if (m_xygribPanel->m_cape_cbox->IsEnabled() &&
2090 m_xygribPanel->m_cape_cbox->IsChecked())
2092 if (m_xygribPanel->m_reflectivity_cbox->IsEnabled() &&
2093 m_xygribPanel->m_reflectivity_cbox->IsChecked())
2095 if (m_xygribPanel->m_gust_cbox->IsEnabled() &&
2096 m_xygribPanel->m_gust_cbox->IsChecked())
2100 if ((m_selectedWaveModelIndex >= 0) &&
2101 (xygribWaveModelList[m_selectedWaveModelIndex] !=
nullptr)) {
2102 wxString modelStr = wxString::Format(
2103 "&wmdl=%s", xygribWaveModelList[m_selectedWaveModelIndex]->reqName);
2104 wxString wParams =
"";
2105 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2108 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2109 wParams <<
"h;d;p;";
2111 if (wParams.length() > 0) {
2112 urlStr << wxString::Format(
"%s&wpar=%s", modelStr.c_str(),
2115 urlStr <<
"&wmdl=none";
2118 urlStr <<
"&wmdl=none";
2126wxString GribRequestSetting::BuildGribFileName() {
2127 wxString selStr = m_xygribPanel->m_resolution_choice->GetStringSelection();
2128 selStr.Replace(
".",
"P");
2131 if (m_selectedWaveModelIndex < 0) {
2132 fileName = wxString::Format(
2133 "XyGrib_%s_%s_%s.grb2", wxDateTime::Now().Format(
"%F-%H-%M"),
2134 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr);
2136 fileName = wxString::Format(
2137 "XyGrib_%s_%s_%s_%s.grb2", wxDateTime::Now().Format(
"%F-%H-%M"),
2138 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr,
2139 m_xygribPanel->m_wavemodel_choice->GetStringSelection());
2151void GribRequestSetting::OnXyGribDownloadButton(wxCommandEvent &event) {
2153 if (m_downloading) {
2157 m_downloading =
false;
2158 m_download_handle = 0;
2160 wxEVT_DOWNLOAD_EVENT,
2161 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2162 m_connected =
false;
2163 m_xygribPanel->m_progress_gauge->SetValue(0);
2164 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2165 m_xygribPanel->m_status_text->SetLabelText(_(
"Download cancelled"));
2168 EnableDownloadButtons();
2169 wxTheApp->ProcessPendingEvents();
2174 if (m_gribSizeEstimate > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB * 1024 * 1024) {
2175 m_xygribPanel->m_status_text->SetLabelText(
2176 wxString::Format(_(
"Can't download GRIB file bigger than %d MB"),
2177 (
int)XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB));
2183 MemorizeXyGribConfiguration();
2185 m_downloading =
true;
2187 EnableDownloadButtons();
2189 m_xygribPanel->m_download_button->SetLabelText(_(
"Cancel"));
2190 m_xygribPanel->m_status_text->SetLabelText(
2191 _(
"Preparing GRIB file on server..."));
2195 wxString requestUrl = BuildXyGribUrl();
2200 wxString filename = wxString::Format(
"ocpn_xygrib_%s.xml",
2201 wxDateTime::Now().Format(
"%F-%H-%M"));
2202 wxString path = m_parent.GetGribDir();
2203 path << wxFileName::GetPathSeparator();
2208 wxEVT_DOWNLOAD_EVENT,
2209 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2212 &m_download_handle);
2217 while (m_downloading) {
2218 wxTheApp->ProcessPendingEvents();
2222 if ((m_canceled) || (!m_bTransferSuccess)) {
2224 m_xygribPanel->m_status_text->SetLabelText(_(
"Grib request failed"));
2225 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2227 EnableDownloadButtons();
2235 bool readOk = xmlFile.Open(path);
2237 readOk &= xmlFile.ReadAll(&strXml);
2245 if (readOk && (((
int)strXml.find(
"\"status\":true") == wxNOT_FOUND))) {
2248 int errPos = strXml.find(
"\"message\":\"");
2249 int errEnd = strXml.find(
"\"}");
2250 if ((errPos != wxNOT_FOUND) && (errEnd != wxNOT_FOUND)) {
2252 errorStr = strXml.Mid(errPos, errEnd - errPos);
2254 errorStr =
"Unknown server error";
2257 m_xygribPanel->m_status_text->SetLabelText(
2258 wxString::Format(
"%s (%s)", _(
"Server Error"), errorStr));
2259 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2261 EnableDownloadButtons();
2266 int urlPos = strXml.find(
"\"url\":\"http:");
2267 int urlEnd = strXml.find(
".grb2\"");
2268 if ((urlPos != wxNOT_FOUND) && (urlEnd != wxNOT_FOUND)) {
2271 url = strXml.Mid(urlPos, urlEnd - urlPos);
2272 url.Replace(
"\\/",
"/");
2283 m_xygribPanel->m_status_text->SetLabelText(
2284 _(
"Error parsing XML file from server"));
2285 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2287 EnableDownloadButtons();
2291 m_xygribPanel->m_status_text->SetLabelText(_(
"Downloading GRIB file"));
2294 path = m_parent.GetGribDir();
2295 path << wxFileName::GetPathSeparator();
2296 path << BuildGribFileName();
2300 m_downloading =
true;
2304 wxEVT_DOWNLOAD_EVENT,
2305 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2311 while (m_downloading) {
2312 wxTheApp->ProcessPendingEvents();
2317 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2320 if (m_bTransferSuccess) {
2322 m_xygribPanel->m_status_text->SetLabelText(_(
"Download complete"));
2323 wxFileName fn(path);
2327 m_parent.OpenFile();
2329 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
2331 m_parent.SetDialogsStyleSizePosition(
true);
2336 m_xygribPanel->m_status_text->SetLabelText(_(
"Download failed"));
2339 if (m_canceled || !m_bTransferSuccess) wxRemoveFile(path);
2341 EnableDownloadButtons();
2351 wxString atmModel = m_xygribPanel->m_atmmodel_choice->GetStringSelection();
2353 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) !=
nullptr) {
2354 if (selectedAtmModel->name.IsSameAs(atmModel,
true)) {
2361 if (selectedAtmModel ==
nullptr) {
2362 selectedAtmModel = xygribAtmModelList[0];
2367 if (selectedAtmModel->wind)
2368 m_xygribPanel->m_wind_cbox->Enable();
2370 m_xygribPanel->m_wind_cbox->Disable();
2372 if (selectedAtmModel->gust)
2373 m_xygribPanel->m_gust_cbox->Enable();
2375 m_xygribPanel->m_gust_cbox->Disable();
2377 if (selectedAtmModel->pressure)
2378 m_xygribPanel->m_pressure_cbox->Enable();
2380 m_xygribPanel->m_pressure_cbox->Disable();
2382 if (selectedAtmModel->temperature)
2383 m_xygribPanel->m_temperature_cbox->Enable();
2385 m_xygribPanel->m_temperature_cbox->Disable();
2387 if (selectedAtmModel->cape)
2388 m_xygribPanel->m_cape_cbox->Enable();
2390 m_xygribPanel->m_cape_cbox->Disable();
2392 if (selectedAtmModel->reflectivity)
2393 m_xygribPanel->m_reflectivity_cbox->Enable();
2395 m_xygribPanel->m_reflectivity_cbox->Disable();
2397 if (selectedAtmModel->cloudCover)
2398 m_xygribPanel->m_cloudcover_cbox->Enable();
2400 m_xygribPanel->m_cloudcover_cbox->Disable();
2402 if (selectedAtmModel->precipitation)
2403 m_xygribPanel->m_precipitation_cbox->Enable();
2405 m_xygribPanel->m_precipitation_cbox->Disable();
2408 m_xygribPanel->m_resolution_choice->Clear();
2409 for (
int i = 0; i < selectedAtmModel->nbRes; i++) {
2410 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2415 m_xygribPanel->m_duration_choice->Clear();
2416 for (
int i = 0; i < selectedAtmModel->duration; i++) {
2417 m_xygribPanel->m_duration_choice->Insert(wxString::Format(
"%d", i + 1), i);
2421 m_xygribPanel->m_interval_choice->Clear();
2422 for (
int i = 0; i < selectedAtmModel->nbInterval; i++) {
2423 m_xygribPanel->m_interval_choice->Insert(
2424 wxString::Format(
"%dh", selectedAtmModel->interval[i]), i);
2428 m_xygribPanel->m_run_choice->Clear();
2429 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2430 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2431 m_xygribPanel->m_run_choice->Insert(
"12h", 1);
2432 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 2);
2434 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2435 m_xygribPanel->m_run_choice->Insert(
"6h", 1);
2436 m_xygribPanel->m_run_choice->Insert(
"12h", 2);
2437 m_xygribPanel->m_run_choice->Insert(
"18h", 3);
2438 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 4);
2441 if (modelIndex == m_parent.xyGribConfig.atmModelIndex) {
2442 ApplyXyGribConfiguration();
2444 m_selectedAtmModelIndex = modelIndex;
2445 m_xygribPanel->m_resolution_choice->SetSelection(0);
2446 m_xygribPanel->m_duration_choice->SetSelection(
2447 m_xygribPanel->m_duration_choice->GetCount() - 1);
2448 m_xygribPanel->m_interval_choice->SetSelection(0);
2449 m_xygribPanel->m_run_choice->SetSelection(
2450 m_xygribPanel->m_run_choice->GetCount() - 1);
2452 MemorizeXyGribConfiguration();
2462 wxString waveModel = m_xygribPanel->m_wavemodel_choice->GetStringSelection();
2464 while ((selectedModel = xygribWaveModelList[modelIndex]) !=
nullptr) {
2465 if (selectedModel->name.IsSameAs(waveModel,
true)) {
2472 if (selectedModel ==
nullptr) {
2474 m_selectedWaveModelIndex = -1;
2475 m_xygribPanel->m_waveheight_cbox->Disable();
2476 m_xygribPanel->m_windwave_cbox->Disable();
2477 MemorizeXyGribConfiguration();
2481 m_selectedWaveModelIndex = modelIndex;
2484 if (selectedModel->significantHeight) {
2485 m_xygribPanel->m_waveheight_cbox->Enable();
2487 m_xygribPanel->m_waveheight_cbox->Disable();
2490 if (selectedModel->windWaves) {
2491 m_xygribPanel->m_windwave_cbox->Enable();
2493 m_xygribPanel->m_windwave_cbox->Disable();
2495 MemorizeXyGribConfiguration();
2502 MemorizeXyGribConfiguration();
2506void GribRequestSetting::InitializeXygribDialog() {
2511 m_xygribPanel->m_atmmodel_choice->Clear();
2513 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) !=
nullptr) {
2514 m_xygribPanel->m_atmmodel_choice->Insert(selectedAtmModel->name,
2519 m_selectedAtmModelIndex = m_parent.xyGribConfig.atmModelIndex;
2520 selectedAtmModel = xygribAtmModelList[m_selectedAtmModelIndex];
2523 m_xygribPanel->m_wavemodel_choice->Clear();
2525 while ((selectedWaveModel = xygribWaveModelList[modelIndex]) !=
nullptr) {
2526 m_xygribPanel->m_wavemodel_choice->Insert(selectedWaveModel->name,
2531 m_xygribPanel->m_wavemodel_choice->Insert(
"None", modelIndex);
2532 m_selectedWaveModelIndex = m_parent.xyGribConfig.waveModelIndex;
2533 selectedWaveModel = xygribWaveModelList[m_selectedWaveModelIndex];
2534 if (selectedWaveModel ==
nullptr) {
2535 m_selectedWaveModelIndex = -1;
2539 m_xygribPanel->m_resolution_choice->Clear();
2540 for (
int i = 0; i < selectedAtmModel->nbRes; i++) {
2541 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2546 m_xygribPanel->m_duration_choice->Clear();
2547 for (
int i = 0; i < selectedAtmModel->duration; i++) {
2548 m_xygribPanel->m_duration_choice->Insert(wxString::Format(
"%d", i + 1), i);
2552 m_xygribPanel->m_interval_choice->Clear();
2553 for (
int i = 0; i < selectedAtmModel->nbInterval; i++) {
2554 m_xygribPanel->m_interval_choice->Insert(
2555 wxString::Format(
"%dh", selectedAtmModel->interval[i]), i);
2559 m_xygribPanel->m_run_choice->Clear();
2560 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2561 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2562 m_xygribPanel->m_run_choice->Insert(
"12h", 1);
2563 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 2);
2565 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2566 m_xygribPanel->m_run_choice->Insert(
"6h", 1);
2567 m_xygribPanel->m_run_choice->Insert(
"12h", 2);
2568 m_xygribPanel->m_run_choice->Insert(
"18h", 3);
2569 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 4);
2572 if (selectedAtmModel->wind)
2573 m_xygribPanel->m_wind_cbox->Enable();
2575 m_xygribPanel->m_wind_cbox->Disable();
2577 if (selectedAtmModel->gust)
2578 m_xygribPanel->m_gust_cbox->Enable();
2580 m_xygribPanel->m_gust_cbox->Disable();
2582 if (selectedAtmModel->pressure)
2583 m_xygribPanel->m_pressure_cbox->Enable();
2585 m_xygribPanel->m_pressure_cbox->Disable();
2587 if (selectedAtmModel->temperature)
2588 m_xygribPanel->m_temperature_cbox->Enable();
2590 m_xygribPanel->m_temperature_cbox->Disable();
2592 if (selectedAtmModel->cape)
2593 m_xygribPanel->m_cape_cbox->Enable();
2595 m_xygribPanel->m_cape_cbox->Disable();
2597 if (selectedAtmModel->reflectivity)
2598 m_xygribPanel->m_reflectivity_cbox->Enable();
2600 m_xygribPanel->m_reflectivity_cbox->Disable();
2602 if (selectedAtmModel->cloudCover)
2603 m_xygribPanel->m_cloudcover_cbox->Enable();
2605 m_xygribPanel->m_cloudcover_cbox->Disable();
2607 if (selectedAtmModel->precipitation)
2608 m_xygribPanel->m_precipitation_cbox->Enable();
2610 m_xygribPanel->m_precipitation_cbox->Disable();
2612 if ((selectedWaveModel !=
nullptr) && (selectedWaveModel->significantHeight))
2613 m_xygribPanel->m_waveheight_cbox->Enable();
2615 m_xygribPanel->m_waveheight_cbox->Disable();
2617 if ((selectedWaveModel !=
nullptr) && (selectedWaveModel->windWaves))
2618 m_xygribPanel->m_windwave_cbox->Enable();
2620 m_xygribPanel->m_windwave_cbox->Disable();
2622 ApplyXyGribConfiguration();
2629void GribRequestSetting::ApplyXyGribConfiguration() {
2630 m_xygribPanel->m_atmmodel_choice->SetSelection(
2631 m_parent.xyGribConfig.atmModelIndex);
2632 m_xygribPanel->m_wavemodel_choice->SetSelection(
2633 m_parent.xyGribConfig.waveModelIndex);
2635 m_xygribPanel->m_wind_cbox->SetValue(m_parent.xyGribConfig.wind);
2636 m_xygribPanel->m_gust_cbox->SetValue(m_parent.xyGribConfig.gust);
2637 m_xygribPanel->m_pressure_cbox->SetValue(m_parent.xyGribConfig.pressure);
2638 m_xygribPanel->m_temperature_cbox->SetValue(
2639 m_parent.xyGribConfig.temperature);
2640 m_xygribPanel->m_cape_cbox->SetValue(m_parent.xyGribConfig.cape);
2641 m_xygribPanel->m_reflectivity_cbox->SetValue(
2642 m_parent.xyGribConfig.reflectivity);
2643 m_xygribPanel->m_cloudcover_cbox->SetValue(m_parent.xyGribConfig.cloudCover);
2644 m_xygribPanel->m_precipitation_cbox->SetValue(
2645 m_parent.xyGribConfig.precipitation);
2646 m_xygribPanel->m_waveheight_cbox->SetValue(m_parent.xyGribConfig.waveHeight);
2647 m_xygribPanel->m_windwave_cbox->SetValue(m_parent.xyGribConfig.windWaves);
2648 m_xygribPanel->m_resolution_choice->SetSelection(
2649 m_parent.xyGribConfig.resolutionIndex);
2650 m_xygribPanel->m_duration_choice->SetSelection(
2651 m_parent.xyGribConfig.durationIndex);
2652 m_xygribPanel->m_interval_choice->SetSelection(
2653 m_parent.xyGribConfig.intervalIndex);
2654 m_xygribPanel->m_run_choice->SetSelection(m_parent.xyGribConfig.runIndex);
2656 UpdateGribSizeEstimate();
2663void GribRequestSetting::MemorizeXyGribConfiguration() {
2664 m_parent.xyGribConfig.atmModelIndex =
2665 m_xygribPanel->m_atmmodel_choice->GetSelection();
2666 m_parent.xyGribConfig.waveModelIndex =
2667 m_xygribPanel->m_wavemodel_choice->GetSelection();
2669 m_parent.xyGribConfig.wind = m_xygribPanel->m_wind_cbox->IsChecked();
2670 m_parent.xyGribConfig.gust = m_xygribPanel->m_gust_cbox->IsChecked();
2671 m_parent.xyGribConfig.pressure = m_xygribPanel->m_pressure_cbox->IsChecked();
2672 m_parent.xyGribConfig.temperature =
2673 m_xygribPanel->m_temperature_cbox->IsChecked();
2674 m_parent.xyGribConfig.cape = m_xygribPanel->m_cape_cbox->IsChecked();
2675 m_parent.xyGribConfig.reflectivity =
2676 m_xygribPanel->m_reflectivity_cbox->IsChecked();
2677 m_parent.xyGribConfig.cloudCover =
2678 m_xygribPanel->m_cloudcover_cbox->IsChecked();
2679 m_parent.xyGribConfig.precipitation =
2680 m_xygribPanel->m_precipitation_cbox->IsChecked();
2681 m_parent.xyGribConfig.waveHeight =
2682 m_xygribPanel->m_waveheight_cbox->IsChecked();
2683 m_parent.xyGribConfig.windWaves = m_xygribPanel->m_windwave_cbox->IsChecked();
2685 m_parent.xyGribConfig.resolutionIndex =
2686 m_xygribPanel->m_resolution_choice->GetSelection();
2687 m_parent.xyGribConfig.durationIndex =
2688 m_xygribPanel->m_duration_choice->GetSelection();
2689 m_parent.xyGribConfig.intervalIndex =
2690 m_xygribPanel->m_interval_choice->GetSelection();
2691 m_parent.xyGribConfig.runIndex = m_xygribPanel->m_run_choice->GetSelection();
2693 UpdateGribSizeEstimate();
2699void GribRequestSetting::UpdateGribSizeEstimate() {
2704 if (!m_xygribPanel->m_resolution_choice->GetStringSelection().ToCDouble(
2706 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2709 if (!m_xygribPanel->m_duration_choice->GetStringSelection().ToCLong(&days)) {
2710 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2713 wxString intvStr = m_xygribPanel->m_interval_choice->GetStringSelection();
2714 intvStr.Replace(
"h",
"");
2715 if (!intvStr.ToCLong(&interval)) {
2716 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2721 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2730 int npts = (int)(ceil(fabs(xmax - xmin) / resolution) *
2731 ceil(fabs(ymax - ymin) / resolution));
2734 int nbrec = (int)days * 24 / interval + 1;
2736 int nbPress = (m_xygribPanel->m_pressure_cbox->IsChecked() &&
2737 m_xygribPanel->m_pressure_cbox->IsEnabled())
2740 int nbWind = (m_xygribPanel->m_wind_cbox->IsChecked() &&
2741 m_xygribPanel->m_wind_cbox->IsEnabled())
2744 int nbRain = (m_xygribPanel->m_precipitation_cbox->IsChecked() &&
2745 m_xygribPanel->m_precipitation_cbox->IsEnabled())
2748 int nbCloud = (m_xygribPanel->m_cloudcover_cbox->IsChecked() &&
2749 m_xygribPanel->m_cloudcover_cbox->IsEnabled())
2752 int nbTemp = (m_xygribPanel->m_temperature_cbox->IsChecked() &&
2753 m_xygribPanel->m_temperature_cbox->IsEnabled())
2757 int nbCAPEsfc = (m_xygribPanel->m_cape_cbox->IsChecked() &&
2758 m_xygribPanel->m_cape_cbox->IsEnabled())
2761 int nbReflectivity = (m_xygribPanel->m_reflectivity_cbox->IsChecked() &&
2762 m_xygribPanel->m_reflectivity_cbox->IsEnabled())
2765 int nbGUSTsfc = (m_xygribPanel->m_gust_cbox->IsChecked() &&
2766 m_xygribPanel->m_gust_cbox->IsEnabled())
2776 estimate += nbWind * (head + (nbits * npts) / 8 + 2);
2779 estimate += nbTemp * (head + (nbits * npts) / 8 + 2);
2785 estimate += nbRain * (head + 24 + (nbits * npts) / 8 + 2);
2788 estimate += nbPress * (head + (nbits * npts) / 8 + 2);
2791 estimate += nbCloud * (head + 24 + (nbits * npts) / 8 + 2);
2794 estimate += nbReflectivity * (head + (nbits * npts) / 8 + 2);
2797 estimate += nbCAPEsfc * (head + (nbits * npts) / 8 + 2);
2800 estimate += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
2804 int atmEstimate = estimate;
2808 if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2811 npts = (int)(ceil(fabs(xmax - xmin) / 0.5) * ceil(fabs(ymax - ymin) / 0.5));
2812 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2813 }
else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2817 (int)(ceil(fabs(xmax - xmin) / 0.25) * ceil(fabs(ymax - ymin) / 0.25));
2818 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2819 }
else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2823 (int)(ceil(fabs(xmax - xmin) / 0.05) * ceil(fabs(ymax - ymin) / 0.1));
2824 nbrec = (int)fmin(4, days) * 24 / interval + 1;
2830 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2832 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2835 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2837 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2839 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2841 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2844 int wavEstimate = estimate - atmEstimate;
2846 wavEstimate = wavEstimate * 0.6;
2848 estimate = atmEstimate + wavEstimate;
2851 estimate = estimate * 0.65;
2853 wxString warningStr =
"";
2854 if (estimate / (1024 * 1024) > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB) {
2855 warningStr = wxString::Format(
"(Warning GRIB exceeds %d MB limit)",
2856 XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB);
2859 m_xygribPanel->m_sizeestimate_text->SetLabel(
2860 wxString::Format(
"%d kB %s", estimate / 1024, warningStr));
2862 m_gribSizeEstimate = estimate;
void SetRequestButtonBitmap(int type)
Set the icon and tooltip for the download request button.
GribPi * pPlugIn
Plugin instance that owns this control bar.
wxString m_grib_dir
Directory containing GRIB files.
wxArrayString m_file_names
List of GRIB filenames being displayed.
Class GribRequestSettingBase.
wxButton * m_rButtonCancel
Button to Cancel a request to download, close the dialog without saving the configuration.
wxSpinCtrl * m_spMaxLon
A spinner for the max longitude of the bounding box for downloads.
wxSpinCtrl * m_spMaxLat
A spinner for the max latitude of the bounding box for downloads.
wxRadioButton * m_rbManualSelect
Radio button selected to indicate the download area is based on the area selected by the user.
wxRadioButton * m_rbCurrentView
Radio button selected to indicate the download area is based on the visible area of the chart in the ...
wxSpinCtrl * m_spMinLat
A spinner for the min latitude of the bounding box for downloads.
wxButton * m_rButtonApply
Button to Save the "download request" configuration.
wxButton * m_rButtonYes
Button to Send a download request through e-mail.
wxSpinCtrl * m_spMinLon
A spinner for the min longitude of the bounding box for downloads.
Manages GRIB file request configuration and downloads.
double m_StartLat
The latitude at the starting point of the bounding box.
void OnXyGribWaveModelChoice(wxCommandEvent &event) override
Handle action of changing wave model selection.
void OnSendMaiL(wxCommandEvent &event) override
Callback invoked when the user clicks the "Send" button in the "e-mail" tab.
double GetMinLat() const
Get the minimum latitude of the bounding box for the download request.
double GetMaxLat() const
Get the maximum latitude of the bounding box for the download request.
double m_Lat
The latitude at the mouse cursor while drawing a bounding box.
void OnVpUnderMouseChange(PlugIn_ViewPort *vp)
Callback invoked when the view port under mouse has changed.
bool RenderGlZoneOverlay()
Renders the GRIB area selection overlay using OpenGL.
bool RenderZoneOverlay(wxDC &dc)
Renders the GRIB area selection overlay using standard device context.
double m_Lon
The longitude at the mouse cursor while drawing a bounding box.
void OnXyGribAtmModelChoice(wxCommandEvent &event) override
Handle action of changing atmospheric model selection.
wxPoint m_StartPoint
Starting point of the bounding box in physical pixels.
bool DoRenderZoneOverlay()
Draws the GRIB area selection overlay on the chart.
bool MouseEventHook(wxMouseEvent &event)
Intercepts mouse events to handle GRIB area selection.
void OnVpWithFocusChange(PlugIn_ViewPort *vp)
Callback invoked when the focused view port has changed, such as in multi-chart mode when user switch...
PlugIn_ViewPort * m_VpMouse
The viewport under the mouse.
ZoneSelectionRenderState m_RenderSelectionZoneState
Current state of the bounding box overlay rendering.
void OnXyGribConfigChange(wxCommandEvent &event) override
Handle action of changing a GRIB configuration parameter.
double GetMaxLon() const
Get the maximum longitude of the bounding box for the download request.
PlugIn_ViewPort * m_VpFocus
The viewport currently in focus.
double m_StartLon
The longitude at the starting point of the bounding box.
double GetMinLon() const
Get the minimum longitude of the bounding box for the download request.
void OnOK(wxCommandEvent &event) override
Callback invoked when the user clicks the "OK" button in the "download" dialog.
Contains view parameters and status information for a chart display viewport.
double lon_max
Maximum longitude of the viewport.
double lat_max
Maximum latitude of the viewport.
double lon_min
Minimum longitude of the viewport.
double lat_min
Minimum latitude of the viewport.
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
bool IsArray() const
Return TRUE if the type of the value stored is an array type.
int Size() const
Return the size of the array or map stored in this value.
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
wxString AsString() const
Return the stored value as a wxWidget's string.
int AsInt() const
Return the stored value as an integer.
Email Request System for GRIB Data.
GRIB Data Visualization and Rendering Factory.
GRIB Weather Data Plugin for OpenCPN.
int m_SavedZoneSelMode
Persisted version of the GRIB area selection mode.
int m_ZoneSelMode
Tracks the current state of GRIB area selection for zone coordinates.
GRIB Weather Data Request and Download Management.
@ WORLD
Global forecast downloads (e.g., GFS)
@ XYGRIB
Downloads from XyGrib service.
@ NONE
No download source selected.
@ LOCAL_CATALOG
Downloads from configured catalogs.
@ LOCAL
Downloads from local sources.
@ AUTO_SELECTION
Area automatically set from current viewport bounds.
@ DRAW_SELECTION
Manual mode has been selected.
@ START_SELECTION
User has clicked Shift + Left click and is drawing the bounding box by dragging the mouse.
@ COMPLETE_SELECTION
Selection box completed in manual mode, coordinates have been captured after the user has released th...
@ SAVED_SELECTION
Area loaded from previously saved coordinates.
#define SAVEDZONE
Save zone.
#define MANSELECT
Manual selection mode.
#define AUTOSELECT
Automatic selection mode.
@ OCPN_DL_EVENT_TYPE_PROGRESS
Download progress update.
@ OCPN_DL_EVENT_TYPE_END
Download has completed.
@ OCPN_DL_NO_ERROR
Download completed successfully.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
void RequestRefresh(wxWindow *win)
Requests window refresh.
void GetCanvasLLPix(PlugIn_ViewPort *vp, wxPoint p, double *plat, double *plon)
Converts canvas physical pixel coordinates to lat/lon.
OpenGL Platform Abstraction Layer.
void OCPN_cancelDownloadFileBackground(long handle)
Cancels a background download.
int OCPNMessageBox_PlugIn(wxWindow *parent, const wxString &message, const wxString &caption, int style, int x, int y)
Shows a message box dialog.
_OCPN_DLStatus OCPN_downloadFileBackground(const wxString &url, const wxString &outputFile, wxEvtHandler *handler, long *handle)
Asynchronously downloads a file in the background.
XyGrib Model Configuration and Definitions.