26 #include <wx/statline.h>
28 #include <curl/curl.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"
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"
46 #include "SendToPeerDlg.h"
50 #include "androidUTIL.h"
53 #define TIMER_AUTOSCAN 94522
54 #define TIMER_SCANTICK 94523
59 static 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;
67 static 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;
126 std::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,
""};
144 static 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();
159 EVT_BUTTON(ID_STP_CANCEL, SendToPeerDlg::OnCancelClick)
160 EVT_BUTTON(ID_STP_OK, SendToPeerDlg::OnSendClick)
161 EVT_BUTTON(ID_STP_SCAN, SendToPeerDlg::OnScanClick)
162 EVT_TIMER(TIMER_AUTOSCAN, SendToPeerDlg::OnTimerAutoscan)
163 EVT_TIMER(TIMER_SCANTICK, SendToPeerDlg::OnTimerScanTick)
167 m_PeerListBox = NULL;
170 m_CancelButton = NULL;
173 m_bScanOnCreate =
false;
176 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
177 if (ipv4_addrs.size())
178 m_ownipAddr = ipv4_addrs[0];
181 androidDisableRotation();
185 SendToPeerDlg::~SendToPeerDlg() {
186 delete m_PeerListBox;
189 delete m_CancelButton;
191 androidEnableRotation();
195 bool SendToPeerDlg::Create(wxWindow* parent, wxWindowID
id,
196 const wxString& caption,
const wxString& hint,
197 const wxPoint& pos,
const wxSize& size,
long style) {
198 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
199 wxFont* pF = OCPNGetFont(_T(
"Dialog"), 0);
202 wxDialog::Create(parent,
id, caption, pos, size, style);
204 CreateControls(hint);
205 GetSizer()->Fit(
this);
206 GetSizer()->SetSizeHints(
this);
209 if (m_bScanOnCreate) {
210 m_autoScanTimer.SetOwner(
this, TIMER_AUTOSCAN);
211 m_autoScanTimer.Start(500, wxTIMER_ONE_SHOT);
213 m_ScanTickTimer.SetOwner(
this, TIMER_SCANTICK);
215 auto action = [&](
ObservedEvt& evt) { m_pgauge->SetValue(evt.GetInt()); };
216 progress_listener.
Init(progress, action);
218 androidDisableRotation();
223 bool SendToPeerDlg::EnableActivateChkbox() {
224 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
228 void SendToPeerDlg::CreateControls(
const wxString&) {
231 wxBoxSizer* itemBoxSizer2 =
new wxBoxSizer(wxVERTICAL);
232 itemDialog1->SetSizer(itemBoxSizer2);
236 wxStaticBox* comm_box =
237 new wxStaticBox(
this, wxID_ANY, _(
"Detected OpenCPN peer instances"));
239 wxStaticBoxSizer* comm_box_sizer =
new wxStaticBoxSizer(comm_box, wxVERTICAL);
240 itemBoxSizer2->Add(comm_box_sizer, 0, wxEXPAND | wxALL, 5);
242 m_PeerListBox =
new wxComboBox(
this, ID_STP_CHOICE_PEER);
245 for (
auto& entry : MdnsCache::GetInstance().GetCache()) {
246 wxString item(entry.hostname.c_str());
249 if (!g_hostname.IsSameAs(item.BeforeFirst(
'.')) ||
250 (m_ownipAddr != entry.ip)) {
252 item += entry.ip.c_str();
254 m_PeerListBox->Append(item);
258 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
261 [&](wxCommandEvent&) {
262 m_SendButton->Enable(m_PeerListBox->GetValue() !=
""); });
263 m_PeerListBox->Enable(!m_bScanOnCreate);
264 comm_box_sizer->Add(m_PeerListBox, 0, wxEXPAND | wxALL, 5);
266 wxBoxSizer* itemBoxSizer3 =
new wxBoxSizer(wxVERTICAL);
267 itemBoxSizer2->Add(itemBoxSizer3, 0, wxEXPAND | wxALL, 5);
269 m_RescanButton =
new wxButton(itemDialog1, ID_STP_SCAN, _(
"Scan again"),
270 wxDefaultPosition, wxDefaultSize, 0);
271 itemBoxSizer3->Add(m_RescanButton, 0, wxALL, 5);
273 m_pgauge =
new wxGauge(itemDialog1, -1, m_scanTime * 2, wxDefaultPosition,
274 wxSize(-1, GetCharHeight()));
275 itemBoxSizer3->Add(m_pgauge, 0, wxEXPAND | wxALL, 20);
277 itemBoxSizer2->AddSpacer(30);
278 itemBoxSizer2->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
279 m_activate_chkbox =
new wxCheckBox(
this, wxID_ANY,
280 _(
"Activate after transfer"),
281 wxDefaultPosition, wxDefaultSize,
283 itemBoxSizer2->Add(m_activate_chkbox, 0,
284 wxALIGN_RIGHT | wxALL, 10);
285 if (!EnableActivateChkbox()) m_activate_chkbox->Disable();
289 wxBoxSizer* itemBoxSizer16 =
new wxBoxSizer(wxHORIZONTAL);
290 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
292 m_CancelButton =
new wxButton(itemDialog1, ID_STP_CANCEL, _(
"Cancel"),
293 wxDefaultPosition, wxDefaultSize, 0);
294 itemBoxSizer16->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
296 m_SendButton =
new wxButton(itemDialog1, ID_STP_OK, _(
"Send"),
297 wxDefaultPosition, wxDefaultSize, 0);
298 itemBoxSizer16->Add(m_SendButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
299 m_SendButton->SetDefault();
300 m_SendButton->Enable(!m_PeerListBox->IsListEmpty());
303 void SendToPeerDlg::SetMessage(wxString msg) {
305 premtext->SetLabel(msg);
306 premtext->Refresh(
true);
310 void SendToPeerDlg::OnSendClick(wxCommandEvent&) {
311 if (m_RouteList.empty() && m_TrackList.empty() && m_RoutePointList.empty()) {
317 ParsePeer(m_PeerListBox->GetValue(), peer_data);
318 auto addr_port = ocpn::split(peer_data.dest_ip_address,
":");
319 if (addr_port.size() == 1) addr_port.push_back(
"8443");
320 MdnsCache::GetInstance().
Add(addr_port[0], addr_port[1]);
321 peer_data.routes = m_RouteList;
322 peer_data.tracks = m_TrackList;
323 peer_data.routepoints = m_RoutePointList;
326 peer_data.
activate = m_activate_chkbox->GetValue();
329 m_pgauge->SetRange(100);
330 m_pgauge->SetValue(0);
333 GetApiVersion(peer_data);
335 SendNavobjects(peer_data);
337 bool is_writable = CheckNavObjects(peer_data);
338 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
340 SendNavobjects(peer_data);
347 void SendToPeerDlg::OnScanClick(wxCommandEvent&) { DoScan(); }
349 void SendToPeerDlg::OnTimerAutoscan(wxTimerEvent&) { DoScan(); }
351 void SendToPeerDlg::OnTimerScanTick(wxTimerEvent&) {
354 int v = m_pgauge->GetValue();
355 if (v + 1 <= m_pgauge->GetRange()) m_pgauge->SetValue(v + 1);
360 m_ScanTickTimer.Stop();
361 g_Platform->HideBusySpinner();
362 m_RescanButton->Enable();
363 m_SendButton->SetDefault();
365 m_PeerListBox->Enable(
true);
366 m_bScanOnCreate =
false;
369 m_PeerListBox->Clear();
372 for (
auto& entry : MdnsCache::GetInstance().GetCache()) {
373 wxString item(entry.hostname.c_str());
376 if (!g_hostname.IsSameAs(item.BeforeFirst(
'.')) ||
377 (m_ownipAddr != entry.ip)) {
379 item += entry.ip.c_str();
381 m_PeerListBox->Append(item);
384 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
385 m_SendButton->Enable(m_PeerListBox->GetCount() > 0);
389 void SendToPeerDlg::DoScan() {
390 m_RescanButton->Disable();
391 m_SendButton->Disable();
392 g_Platform->ShowBusySpinner();
393 m_pgauge->SetRange(m_scanTime);
394 m_pgauge->SetValue(0);
397 FindAllOCPNServers(m_scanTime);
399 m_tick = m_scanTime * 2;
400 m_ScanTickTimer.Start(500, wxTIMER_CONTINUOUS);
403 void SendToPeerDlg::OnCancelClick(wxCommandEvent&) {
404 g_Platform->HideBusySpinner();
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.
Route "Send to Peer..." Dialog Definition.
Global variables reflecting command line options and arguments.
General purpose GUI support.
bool activate
API parameter, activate route after transfer.
SemanticVersion api_version
server API version
std::function< PeerDlgResult(PeerDlg, int)> run_status_dlg
Dialog displaying status (good, bad, ...)
std::function< std::pair< PeerDlgResult, std::string >)> run_pincode_dlg
Pin confirm dialog, returns new {0, user_pin} or {error_code, error msg)
bool overwrite
API parameter, force overwrite w/o server dialogs.
Versions uses a modified semantic versioning scheme: major.minor.revision.post-tag+build.