26#include <wx/statline.h>
31#include "model/config_vars.h"
34#include "model/ocpn_utils.h"
35#include "model/peer_client.h"
36#include "model/route.h"
37#include "model/route_point.h"
40#include "OCPNPlatform.h"
41#include "ocpn_frame.h"
42#include "peer_client_dlg.h"
44#include "route_point_gui.h"
46#include "SendToPeerDlg.h"
50#include "androidUTIL.h"
53#define TIMER_AUTOSCAN 94522
54#define TIMER_SCANTICK 94523
59static PeerDlgResult ConfirmWriteDlg() {
60 std::string msg(_(
"Objects exists on server. OK to overwrite?"));
61 long style = wxYES | wxNO | wxNO_DEFAULT | wxICON_QUESTION;
63 int reply = dlg.ShowModal();
64 return reply == wxID_YES ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
67static PeerDlgResult RunStatusDlg(PeerDlg kind,
int status) {
69 case PeerDlg::InvalidHttpResponse: {
72 ss << _(
"Server HTTP response is :") << status;
74 ss << _(
"Curl transfer error: ")
75 << curl_easy_strerror(
static_cast<CURLcode
>(-status));
78 wxICON_ERROR | wxOK | wxCANCEL);
79 int r = dlg.ShowModal();
80 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
82 case PeerDlg::ErrorReturn: {
84 ss << _(
"Server internal error response:") << status;
86 wxICON_ERROR | wxOK | wxCANCEL);
87 int r = dlg.ShowModal();
88 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
90 case PeerDlg::TransferOk: {
92 std::string msg(_(
"Transfer successfully completed"));
94 wxICON_INFORMATION | wxOK);
96 return PeerDlgResult::Ok;
98 case PeerDlg::JsonParseError: {
99 std::string msg(_(
"Cannot parse server reply"));
101 wxICON_ERROR | wxOK | wxCANCEL);
102 int r = dlg.ShowModal();
103 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
105 case PeerDlg::BadPincode: {
106 std::string msg(_(
"Pincode not accepted"));
108 wxICON_ERROR | wxOK | wxCANCEL);
109 int r = dlg.ShowModal();
110 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
112 case PeerDlg::ActivateUnsupported: {
113 std::string msg(_(
"Server does not support activation"));
115 wxICON_ERROR | wxOK | wxCANCEL);
117 int r = dlg.ShowModal();
118 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
120 case PeerDlg::PinConfirm:
121 assert(
false &&
"Illegal PinConfirm result dialog");
123 return PeerDlgResult::Cancel;
126std::pair<PeerDlgResult, std::string> RunPincodeDlg() {
127 PinConfirmDlg dlg(gFrame, wxID_ANY, _(
"OpenCPN Server Message"),
"",
128 wxDefaultPosition, wxDefaultSize, SYMBOL_PCD_STYLE);
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");
135 dlg.SetPincodeText(
"");
136 if (dlg.ShowModal() == wxID_OK) {
137 auto pin = dlg.GetPincodeText().Trim().Trim(
false);
138 return {PeerDlgResult::HasPincode, pin.ToStdString()};
140 return {PeerDlgResult::Cancel,
""};
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(
'}') +
":";
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();
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)
165 m_PeerListBox = NULL;
168 m_CancelButton = NULL;
171 m_bScanOnCreate =
false;
174 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
175 if (ipv4_addrs.size()) m_ownipAddr = ipv4_addrs[0];
178 androidDisableRotation();
182SendToPeerDlg::~SendToPeerDlg() {
183 delete m_PeerListBox;
186 delete m_CancelButton;
188 androidEnableRotation();
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);
199 wxDialog::Create(parent,
id, caption, pos, size, style);
201 CreateControls(hint);
202 GetSizer()->Fit(
this);
203 GetSizer()->SetSizeHints(
this);
206 if (m_bScanOnCreate) {
207 m_autoScanTimer.SetOwner(
this, TIMER_AUTOSCAN);
208 m_autoScanTimer.Start(500, wxTIMER_ONE_SHOT);
210 m_ScanTickTimer.SetOwner(
this, TIMER_SCANTICK);
212 auto action = [&](
ObservedEvt& evt) { m_pgauge->SetValue(evt.GetInt()); };
213 progress_listener.
Init(progress, action);
215 androidDisableRotation();
220bool SendToPeerDlg::EnableActivateChkbox() {
221 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
225void SendToPeerDlg::CreateControls(
const wxString&) {
228 wxBoxSizer* itemBoxSizer2 =
new wxBoxSizer(wxVERTICAL);
229 itemDialog1->SetSizer(itemBoxSizer2);
233 wxStaticBox* comm_box =
234 new wxStaticBox(
this, wxID_ANY, _(
"Detected OpenCPN peer instances"));
236 wxStaticBoxSizer* comm_box_sizer =
new wxStaticBoxSizer(comm_box, wxVERTICAL);
237 itemBoxSizer2->Add(comm_box_sizer, 0, wxEXPAND | wxALL, 5);
239 m_PeerListBox =
new wxComboBox(
this, ID_STP_CHOICE_PEER);
242 for (
auto& entry :
MdnsCache::GetInstance().GetCache()) {
243 wxString item(entry.hostname.c_str());
246 if (!g_hostname.IsSameAs(item.BeforeFirst(
'.')) ||
247 (m_ownipAddr != entry.ip)) {
249 item += entry.ip.c_str();
251 m_PeerListBox->Append(item);
255 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
256 m_PeerListBox->Bind(wxEVT_TEXT, [&](wxCommandEvent&) {
257 m_SendButton->Enable(m_PeerListBox->GetValue() !=
"");
259 m_PeerListBox->Enable(!m_bScanOnCreate);
260 comm_box_sizer->Add(m_PeerListBox, 0, wxEXPAND | wxALL, 5);
262 wxBoxSizer* itemBoxSizer3 =
new wxBoxSizer(wxVERTICAL);
263 itemBoxSizer2->Add(itemBoxSizer3, 0, wxEXPAND | wxALL, 5);
265 m_RescanButton =
new wxButton(itemDialog1, ID_STP_SCAN, _(
"Scan again"),
266 wxDefaultPosition, wxDefaultSize, 0);
267 itemBoxSizer3->Add(m_RescanButton, 0, wxALL, 5);
269 m_pgauge =
new wxGauge(itemDialog1, -1, m_scanTime * 2, wxDefaultPosition,
270 wxSize(-1, GetCharHeight()));
271 itemBoxSizer3->Add(m_pgauge, 0, wxEXPAND | wxALL, 20);
273 itemBoxSizer2->AddSpacer(30);
274 itemBoxSizer2->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
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();
282 wxBoxSizer* itemBoxSizer16 =
new wxBoxSizer(wxHORIZONTAL);
283 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
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);
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());
296void SendToPeerDlg::SetMessage(wxString msg) {
298 premtext->SetLabel(msg);
299 premtext->Refresh(
true);
303void SendToPeerDlg::OnSendClick(wxCommandEvent&) {
304 if (m_RouteList.empty() && m_TrackList.empty() && m_RoutePointList.empty()) {
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;
319 peer_data.
activate = m_activate_chkbox->GetValue();
322 m_pgauge->SetRange(100);
323 m_pgauge->SetValue(0);
326 GetApiVersion(peer_data);
328 SendNavobjects(peer_data);
330 bool is_writable = CheckNavObjects(peer_data);
331 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
333 SendNavobjects(peer_data);
340void SendToPeerDlg::OnScanClick(wxCommandEvent&) { DoScan(); }
342void SendToPeerDlg::OnTimerAutoscan(wxTimerEvent&) { DoScan(); }
344void SendToPeerDlg::OnTimerScanTick(wxTimerEvent&) {
347 int v = m_pgauge->GetValue();
348 if (v + 1 <= m_pgauge->GetRange()) m_pgauge->SetValue(v + 1);
353 m_ScanTickTimer.Stop();
354 g_Platform->HideBusySpinner();
355 m_RescanButton->Enable();
356 m_SendButton->SetDefault();
358 m_PeerListBox->Enable(
true);
359 m_bScanOnCreate =
false;
361 m_PeerListBox->Clear();
364 using namespace ocpn;
366 if (g_hostname != split(e.hostname,
".")[0] || m_ownipAddr != e.ip) {
367 m_PeerListBox->Append(e.hostname +
" {" + e.ip.c_str() +
"}");
370 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
371 m_SendButton->Enable(m_PeerListBox->GetCount() > 0);
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);
383 FindAllOCPNServers(m_scanTime);
385 m_tick = m_scanTime * 2;
386 m_ScanTickTimer.Start(500, wxTIMER_CONTINUOUS);
389void SendToPeerDlg::OnCancelClick(wxCommandEvent&) {
390 g_Platform->HideBusySpinner();
Singleton cache for hosts looked up using mdns.
bool Add(const Entry &entry)
Add new entry to the cache.
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
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.
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.
std::function< std::pair< PeerDlgResult, std::string >()> run_pincode_dlg
Pin confirm dialog, returns new {0, user_pin} or {error_code, error msg)
SemanticVersion api_version
server API version
std::function< PeerDlgResult(PeerDlg, int)> run_status_dlg
Dialog displaying status (good, bad, ...)
bool overwrite
API parameter, force overwrite w/o server dialogs.
Versions uses a modified semantic versioning scheme: major.minor.revision.post-tag+build.