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