OpenCPN Partial API docs
Loading...
Searching...
No Matches
SendToPeerDlg.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2010 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************
23 */
24#include <memory>
25
26#include <wx/statline.h>
27
28#include <curl/curl.h>
29
30#include "model/cmdline.h"
31#include "model/config_vars.h"
32#include "model/mdns_cache.h"
33#include "model/mdns_query.h"
34#include "model/ocpn_utils.h"
35#include "model/peer_client.h"
36#include "model/route.h"
37#include "model/route_point.h"
38
39#include "gui_lib.h"
40#include "OCPNPlatform.h"
41#include "ocpn_frame.h"
42#include "peer_client_dlg.h"
43#include "route_gui.h"
44#include "route_point_gui.h"
45
46#include "SendToPeerDlg.h"
47#include "ocpn_plugin.h"
48
49#ifdef __ANDROID__
50#include "androidUTIL.h"
51#endif
52
53#define TIMER_AUTOSCAN 94522
54#define TIMER_SCANTICK 94523
55
56extern MyFrame* gFrame;
57extern OCPNPlatform* g_Platform;
58
59static PeerDlgResult ConfirmWriteDlg() {
60 std::string msg(_("Objects exists on server. OK to overwrite?"));
61 long style = wxYES | wxNO | wxNO_DEFAULT | wxICON_QUESTION;
62 OCPNMessageDialog dlg(NULL, msg, _("OpenCPN Info"), style);
63 int reply = dlg.ShowModal();
64 return reply == wxID_YES ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
65}
66
67static PeerDlgResult RunStatusDlg(PeerDlg kind, int status) {
68 switch (kind) {
69 case PeerDlg::InvalidHttpResponse: {
70 std::stringstream ss;
71 if (status >= 0) {
72 ss << _("Server HTTP response is :") << status;
73 } else {
74 ss << _("Curl transfer error: ")
75 << curl_easy_strerror(static_cast<CURLcode>(-status));
76 }
77 OCPNMessageDialog dlg(NULL, ss.str(), _("OpenCPN Info"),
78 wxICON_ERROR | wxOK | wxCANCEL);
79 int r = dlg.ShowModal();
80 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
81 }
82 case PeerDlg::ErrorReturn: {
83 std::stringstream ss;
84 ss << _("Server internal error response:") << status;
85 OCPNMessageDialog dlg(NULL, ss.str(), _("OpenCPN Info"),
86 wxICON_ERROR | wxOK | wxCANCEL);
87 int r = dlg.ShowModal();
88 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
89 }
90 case PeerDlg::TransferOk: {
91 std::stringstream ss;
92 std::string msg(_("Transfer successfully completed"));
93 OCPNMessageDialog dlg(NULL, msg, _("OpenCPN Info"),
94 wxICON_INFORMATION | wxOK);
95 dlg.ShowModal();
96 return PeerDlgResult::Ok;
97 }
98 case PeerDlg::JsonParseError: {
99 std::string msg(_("Cannot parse server reply"));
100 OCPNMessageDialog dlg(NULL, msg, _("OpenCPN Info"),
101 wxICON_ERROR | wxOK | wxCANCEL);
102 int r = dlg.ShowModal();
103 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
104 }
105 case PeerDlg::BadPincode: {
106 std::string msg(_("Pincode not accepted"));
107 OCPNMessageDialog dlg(NULL, msg, _("OpenCPN Info"),
108 wxICON_ERROR | wxOK | wxCANCEL);
109 int r = dlg.ShowModal();
110 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
111 }
112 case PeerDlg::ActivateUnsupported: {
113 std::string msg(_("Server does not support activation"));
114 OCPNMessageDialog dlg(NULL, msg, _("OpenCPN Info"),
115 wxICON_ERROR | wxOK | wxCANCEL);
116
117 int r = dlg.ShowModal();
118 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
119 }
120 case PeerDlg::PinConfirm:
121 assert(false && "Illegal PinConfirm result dialog");
122 }
123 return PeerDlgResult::Cancel; // For the compiler, not reached
124}
125
126std::pair<PeerDlgResult, std::string> RunPincodeDlg() {
127 PinConfirmDlg dlg(gFrame, wxID_ANY, _("OpenCPN Server Message"), "",
128 wxDefaultPosition, wxDefaultSize, SYMBOL_PCD_STYLE);
129
130 static const char* const msg =
131 _("A server pin is needed.\n"
132 "Please enter PIN number from server to pair with this device");
133
134 dlg.SetMessage(msg);
135 dlg.SetPincodeText("");
136 if (dlg.ShowModal() == wxID_OK) {
137 auto pin = dlg.GetPincodeText().Trim().Trim(false);
138 return {PeerDlgResult::HasPincode, pin.ToStdString()};
139 }
140 return {PeerDlgResult::Cancel, ""};
141}
142
144static void ParsePeer(const wxString& ui_value, PeerData& peer_data) {
145 wxString server_name = ui_value.BeforeFirst('{').Trim();
146 wxString peer_ip = ui_value;
147 int tail = ui_value.Find('{');
148 if (tail != wxNOT_FOUND) peer_ip = peer_ip.Mid(tail + 1);
149 peer_ip = peer_ip.BeforeFirst('}') + ":";
150 // Is the destination a portable? Detect by string inspection.
151 peer_ip += server_name.BeforeFirst('-') == "Portable" ? "8444" : "8443";
152 peer_data.server_name = server_name.ToStdString();
153 peer_data.dest_ip_address = peer_ip.ToStdString();
154}
155
156BEGIN_EVENT_TABLE(SendToPeerDlg, wxDialog)
157EVT_BUTTON(ID_STP_CANCEL, SendToPeerDlg::OnCancelClick)
158EVT_BUTTON(ID_STP_OK, SendToPeerDlg::OnSendClick)
159EVT_BUTTON(ID_STP_SCAN, SendToPeerDlg::OnScanClick)
160EVT_TIMER(TIMER_AUTOSCAN, SendToPeerDlg::OnTimerAutoscan)
161EVT_TIMER(TIMER_SCANTICK, SendToPeerDlg::OnTimerScanTick)
162END_EVENT_TABLE()
163
165 m_PeerListBox = NULL;
166 m_pgauge = NULL;
167 m_SendButton = NULL;
168 m_CancelButton = NULL;
169 premtext = NULL;
170 m_scanTime = 5; // default, seconds
171 m_bScanOnCreate = false;
172
173 // Get our own local ipv4 address, for filtering
174 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
175 if (ipv4_addrs.size()) m_ownipAddr = ipv4_addrs[0];
176
177#ifdef __ANDROID__
178 androidDisableRotation();
179#endif
180}
181
182SendToPeerDlg::~SendToPeerDlg() {
183 delete m_PeerListBox;
184 delete m_pgauge;
185 delete m_SendButton;
186 delete m_CancelButton;
187#ifdef __ANDROID__
188 androidEnableRotation();
189#endif
190}
191
192bool SendToPeerDlg::Create(wxWindow* parent, wxWindowID id,
193 const wxString& caption, const wxString& hint,
194 const wxPoint& pos, const wxSize& size, long style) {
195 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
196 wxFont* pF = OCPNGetFont(_("Dialog"), 0);
197 SetFont(*pF);
198
199 wxDialog::Create(parent, id, caption, pos, size, style);
200
201 CreateControls(hint);
202 GetSizer()->Fit(this);
203 GetSizer()->SetSizeHints(this);
204 Centre();
205
206 if (m_bScanOnCreate) {
207 m_autoScanTimer.SetOwner(this, TIMER_AUTOSCAN);
208 m_autoScanTimer.Start(500, wxTIMER_ONE_SHOT);
209 }
210 m_ScanTickTimer.SetOwner(this, TIMER_SCANTICK);
211
212 auto action = [&](ObservedEvt& evt) { m_pgauge->SetValue(evt.GetInt()); };
213 progress_listener.Init(progress, action);
214#ifdef __ANDROID__
215 androidDisableRotation();
216#endif
217 return true;
218}
219
220bool SendToPeerDlg::EnableActivateChkbox() {
221 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
222 m_TrackList.empty();
223}
224
225void SendToPeerDlg::CreateControls(const wxString&) {
226 SendToPeerDlg* itemDialog1 = this;
227
228 wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
229 itemDialog1->SetSizer(itemBoxSizer2);
230
231 // Create the ScrollBox list of available com ports in a labeled static
232 // box
233 wxStaticBox* comm_box =
234 new wxStaticBox(this, wxID_ANY, _("Detected OpenCPN peer instances"));
235
236 wxStaticBoxSizer* comm_box_sizer = new wxStaticBoxSizer(comm_box, wxVERTICAL);
237 itemBoxSizer2->Add(comm_box_sizer, 0, wxEXPAND | wxALL, 5);
238
239 m_PeerListBox = new wxComboBox(this, ID_STP_CHOICE_PEER);
240
241 // Fill in the wxComboBox with all detected peers
242 for (auto& entry : MdnsCache::GetInstance().GetCache()) {
243 wxString item(entry.hostname.c_str());
244
245 // skip "self"
246 if (!g_hostname.IsSameAs(item.BeforeFirst('.')) ||
247 (m_ownipAddr != entry.ip)) {
248 item += " {";
249 item += entry.ip.c_str();
250 item += "}";
251 m_PeerListBox->Append(item);
252 }
253 }
254
255 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
256 m_PeerListBox->Bind(wxEVT_TEXT, [&](wxCommandEvent&) {
257 m_SendButton->Enable(m_PeerListBox->GetValue() != "");
258 });
259 m_PeerListBox->Enable(!m_bScanOnCreate);
260 comm_box_sizer->Add(m_PeerListBox, 0, wxEXPAND | wxALL, 5);
261
262 wxBoxSizer* itemBoxSizer3 = new wxBoxSizer(wxVERTICAL);
263 itemBoxSizer2->Add(itemBoxSizer3, 0, wxEXPAND | wxALL, 5);
264
265 m_RescanButton = new wxButton(itemDialog1, ID_STP_SCAN, _("Scan again"),
266 wxDefaultPosition, wxDefaultSize, 0);
267 itemBoxSizer3->Add(m_RescanButton, 0, wxALL, 5);
268
269 m_pgauge = new wxGauge(itemDialog1, -1, m_scanTime * 2, wxDefaultPosition,
270 wxSize(-1, GetCharHeight()));
271 itemBoxSizer3->Add(m_pgauge, 0, wxEXPAND | wxALL, 20);
272
273 itemBoxSizer2->AddSpacer(30);
274 itemBoxSizer2->Add(new wxStaticLine(this), wxSizerFlags(0).Expand());
275 m_activate_chkbox =
276 new wxCheckBox(this, wxID_ANY, _("Activate after transfer"),
277 wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
278 itemBoxSizer2->Add(m_activate_chkbox, 0, wxALIGN_RIGHT | wxALL, 10);
279 if (!EnableActivateChkbox()) m_activate_chkbox->Disable();
280
281 // OK/Cancel/etc.
282 wxBoxSizer* itemBoxSizer16 = new wxBoxSizer(wxHORIZONTAL);
283 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
284
285 m_CancelButton = new wxButton(itemDialog1, ID_STP_CANCEL, _("Cancel"),
286 wxDefaultPosition, wxDefaultSize, 0);
287 itemBoxSizer16->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
288
289 m_SendButton = new wxButton(itemDialog1, ID_STP_OK, _("Send"),
290 wxDefaultPosition, wxDefaultSize, 0);
291 itemBoxSizer16->Add(m_SendButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
292 m_SendButton->SetDefault();
293 m_SendButton->Enable(!m_PeerListBox->IsListEmpty());
294}
295
296void SendToPeerDlg::SetMessage(wxString msg) {
297 if (premtext) {
298 premtext->SetLabel(msg);
299 premtext->Refresh(true);
300 }
301}
302
303void SendToPeerDlg::OnSendClick(wxCommandEvent&) {
304 if (m_RouteList.empty() && m_TrackList.empty() && m_RoutePointList.empty()) {
305 Close();
306 return;
307 }
308 // Set up transfer data
309 PeerData peer_data(progress);
310 ParsePeer(m_PeerListBox->GetValue(), peer_data);
311 auto addr_port = ocpn::split(peer_data.dest_ip_address, ":");
312 if (addr_port.size() == 1) addr_port.push_back("8443");
313 MdnsCache::GetInstance().Add(addr_port[0], addr_port[1]);
314 peer_data.routes = m_RouteList;
315 peer_data.tracks = m_TrackList;
316 peer_data.routepoints = m_RoutePointList;
317 peer_data.run_status_dlg = RunStatusDlg;
318 peer_data.run_pincode_dlg = RunPincodeDlg;
319 peer_data.activate = m_activate_chkbox->GetValue();
320
321 // And send it out
322 m_pgauge->SetRange(100);
323 m_pgauge->SetValue(0);
324 m_pgauge->Show();
325
326 GetApiVersion(peer_data);
327 if (peer_data.api_version < SemanticVersion(5, 9)) {
328 SendNavobjects(peer_data);
329 } else {
330 bool is_writable = CheckNavObjects(peer_data);
331 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
332 peer_data.overwrite = true;
333 SendNavobjects(peer_data);
334 }
335 }
336 m_pgauge->Hide();
337 Close();
338}
339
340void SendToPeerDlg::OnScanClick(wxCommandEvent&) { DoScan(); }
341
342void SendToPeerDlg::OnTimerAutoscan(wxTimerEvent&) { DoScan(); }
343
344void SendToPeerDlg::OnTimerScanTick(wxTimerEvent&) {
345 m_tick--;
346 if (m_pgauge) {
347 int v = m_pgauge->GetValue();
348 if (v + 1 <= m_pgauge->GetRange()) m_pgauge->SetValue(v + 1);
349 }
350
351 if (m_tick == 0) {
352 // Housekeeping
353 m_ScanTickTimer.Stop();
354 g_Platform->HideBusySpinner();
355 m_RescanButton->Enable();
356 m_SendButton->SetDefault();
357 m_pgauge->Hide();
358 m_PeerListBox->Enable(true);
359 m_bScanOnCreate = false;
360
361 m_PeerListBox->Clear();
362
363 // Fill in the wxComboBox with all detected peers besides own host
364 using namespace ocpn;
365 for (const MdnsCache::Entry& e : MdnsCache::GetInstance().GetCache()) {
366 if (g_hostname != split(e.hostname, ".")[0] || m_ownipAddr != e.ip) {
367 m_PeerListBox->Append(e.hostname + " {" + e.ip.c_str() + "}");
368 }
369 }
370 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
371 m_SendButton->Enable(m_PeerListBox->GetCount() > 0);
372 }
373}
374
375void SendToPeerDlg::DoScan() {
376 m_RescanButton->Disable();
377 m_SendButton->Disable();
378 g_Platform->ShowBusySpinner();
379 m_pgauge->SetRange(m_scanTime);
380 m_pgauge->SetValue(0);
381 m_pgauge->Show();
382
383 FindAllOCPNServers(m_scanTime);
384
385 m_tick = m_scanTime * 2;
386 m_ScanTickTimer.Start(500, wxTIMER_CONTINUOUS);
387}
388
389void SendToPeerDlg::OnCancelClick(wxCommandEvent&) {
390 g_Platform->HideBusySpinner();
391 Close();
392}
Singleton cache for hosts looked up using mdns.
Definition mdns_cache.h:41
bool Add(const Entry &entry)
Add new entry to the cache.
Main application frame.
Definition ocpn_frame.h:136
Provides platform-specific support utilities for OpenCPN.
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition observable.h:255
Adds a std::shared<void> element to wxCommandEvent.
Dialog for sending navigation objects to peer devices.
Global variables reflecting command line options and arguments.
General purpose GUI support.
MdnsCache mDNS host lookups cache.
mDNS lookup wrappers.
Standard, mostly strings utilities.
PlugIn Object Definition/API.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
bool activate
API parameter, activate route after transfer.
Definition peer_client.h:60
std::function< std::pair< PeerDlgResult, std::string >()> run_pincode_dlg
Pin confirm dialog, returns new {0, user_pin} or {error_code, error msg)
Definition peer_client.h:72
SemanticVersion api_version
server API version
Definition peer_client.h:55
std::function< PeerDlgResult(PeerDlg, int)> run_status_dlg
Dialog displaying status (good, bad, ...)
Definition peer_client.h:66
bool overwrite
API parameter, force overwrite w/o server dialogs.
Definition peer_client.h:59
Versions uses a modified semantic versioning scheme: major.minor.revision.post-tag+build.