26#include <wx/statline.h>
50#include "androidUTIL.h"
53#define TIMER_AUTOSCAN 94522
54#define TIMER_SCANTICK 94523
56static PeerDlgResult ConfirmWriteDlg() {
57 std::string msg(_(
"Objects exists on server. OK to overwrite?"));
58 long style = wxYES | wxNO | wxNO_DEFAULT | wxICON_QUESTION;
60 int reply = dlg.ShowModal();
61 return reply == wxID_YES ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
64static PeerDlgResult RunStatusDlg(PeerDlg kind,
int status) {
66 case PeerDlg::InvalidHttpResponse: {
69 ss << _(
"Server HTTP response is :") << status;
71 ss << _(
"Curl transfer error: ")
72 << curl_easy_strerror(
static_cast<CURLcode
>(-status));
75 wxICON_ERROR | wxOK | wxCANCEL);
76 int r = dlg.ShowModal();
77 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
79 case PeerDlg::ErrorReturn: {
81 ss << _(
"Server internal error response:") << status;
83 wxICON_ERROR | wxOK | wxCANCEL);
84 int r = dlg.ShowModal();
85 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
87 case PeerDlg::TransferOk: {
89 std::string msg(_(
"Transfer successfully completed"));
91 wxICON_INFORMATION | wxOK);
93 return PeerDlgResult::Ok;
95 case PeerDlg::JsonParseError: {
96 std::string msg(_(
"Cannot parse server reply"));
98 wxICON_ERROR | wxOK | wxCANCEL);
99 int r = dlg.ShowModal();
100 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
102 case PeerDlg::BadPincode: {
103 std::string msg(_(
"Pincode not accepted"));
105 wxICON_ERROR | wxOK | wxCANCEL);
106 int r = dlg.ShowModal();
107 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
109 case PeerDlg::ActivateUnsupported: {
110 std::string msg(_(
"Server does not support activation"));
112 wxICON_ERROR | wxOK | wxCANCEL);
114 int r = dlg.ShowModal();
115 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
117 case PeerDlg::PinConfirm:
118 assert(
false &&
"Illegal PinConfirm result dialog");
120 return PeerDlgResult::Cancel;
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(
'}') +
":";
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();
136std::pair<PeerDlgResult, std::string> RunPincodeDlg() {
138 _(
"OpenCPN Server Message"),
"", wxDefaultPosition,
139 wxDefaultSize, SYMBOL_PCD_STYLE);
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");
146 dlg.SetPincodeText(
"");
147 if (dlg.ShowModal() == wxID_OK) {
148 auto pin = dlg.GetPincodeText().Trim().Trim(
false);
149 return {PeerDlgResult::HasPincode, pin.ToStdString()};
151 return {PeerDlgResult::Cancel,
""};
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)
163 m_PeerListBox = NULL;
166 m_CancelButton = NULL;
169 m_bScanOnCreate =
false;
172 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
173 if (ipv4_addrs.size()) m_ownipAddr = ipv4_addrs[0];
176 androidDisableRotation();
180SendToPeerDlg::~SendToPeerDlg() {
181 delete m_PeerListBox;
184 delete m_CancelButton;
186 androidEnableRotation();
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);
197 wxDialog::Create(parent,
id, caption, pos, size, style);
199 CreateControls(hint);
200 GetSizer()->Fit(
this);
201 GetSizer()->SetSizeHints(
this);
204 if (m_bScanOnCreate) {
205 m_autoScanTimer.SetOwner(
this, TIMER_AUTOSCAN);
206 m_autoScanTimer.Start(500, wxTIMER_ONE_SHOT);
208 m_ScanTickTimer.SetOwner(
this, TIMER_SCANTICK);
210 auto action = [&](
ObservedEvt& evt) { m_pgauge->SetValue(evt.GetInt()); };
211 progress_listener.
Init(progress, action);
213 androidDisableRotation();
218bool SendToPeerDlg::EnableActivateChkbox() {
219 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
223void SendToPeerDlg::CreateControls(
const wxString&) {
226 wxBoxSizer* itemBoxSizer2 =
new wxBoxSizer(wxVERTICAL);
227 itemDialog1->SetSizer(itemBoxSizer2);
231 wxStaticBox* comm_box =
232 new wxStaticBox(
this, wxID_ANY, _(
"Detected OpenCPN peer instances"));
234 wxStaticBoxSizer* comm_box_sizer =
new wxStaticBoxSizer(comm_box, wxVERTICAL);
235 itemBoxSizer2->Add(comm_box_sizer, 0, wxEXPAND | wxALL, 5);
237 m_PeerListBox =
new wxComboBox(
this, ID_STP_CHOICE_PEER);
240 for (
auto& entry :
MdnsCache::GetInstance().GetCache()) {
241 wxString item(entry.hostname.c_str());
244 if (!g_hostname.IsSameAs(item.BeforeFirst(
'.')) ||
245 (m_ownipAddr != entry.ip)) {
247 item += entry.ip.c_str();
249 m_PeerListBox->Append(item);
253 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
254 m_PeerListBox->Bind(wxEVT_TEXT, [&](wxCommandEvent&) {
255 m_SendButton->Enable(m_PeerListBox->GetValue() !=
"");
257 m_PeerListBox->Enable(!m_bScanOnCreate);
258 comm_box_sizer->Add(m_PeerListBox, 0, wxEXPAND | wxALL, 5);
260 wxBoxSizer* itemBoxSizer3 =
new wxBoxSizer(wxVERTICAL);
261 itemBoxSizer2->Add(itemBoxSizer3, 0, wxEXPAND | wxALL, 5);
263 m_RescanButton =
new wxButton(itemDialog1, ID_STP_SCAN, _(
"Scan again"),
264 wxDefaultPosition, wxDefaultSize, 0);
265 itemBoxSizer3->Add(m_RescanButton, 0, wxALL, 5);
267 m_pgauge =
new wxGauge(itemDialog1, -1, m_scanTime * 2, wxDefaultPosition,
268 wxSize(-1, GetCharHeight()));
269 itemBoxSizer3->Add(m_pgauge, 0, wxEXPAND | wxALL, 20);
271 itemBoxSizer2->AddSpacer(30);
272 itemBoxSizer2->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
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();
280 wxBoxSizer* itemBoxSizer16 =
new wxBoxSizer(wxHORIZONTAL);
281 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
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);
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());
294void SendToPeerDlg::SetMessage(wxString msg) {
296 premtext->SetLabel(msg);
297 premtext->Refresh(
true);
301void SendToPeerDlg::OnSendClick(wxCommandEvent&) {
302 if (m_RouteList.empty() && m_TrackList.empty() && m_RoutePointList.empty()) {
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;
317 peer_data.
activate = m_activate_chkbox->GetValue();
320 m_pgauge->SetRange(100);
321 m_pgauge->SetValue(0);
324 GetApiVersion(peer_data);
329 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
338void SendToPeerDlg::OnScanClick(wxCommandEvent&) { DoScan(); }
340void SendToPeerDlg::OnTimerAutoscan(wxTimerEvent&) { DoScan(); }
342void SendToPeerDlg::OnTimerScanTick(wxTimerEvent&) {
345 int v = m_pgauge->GetValue();
346 if (v + 1 <= m_pgauge->GetRange()) m_pgauge->SetValue(v + 1);
351 m_ScanTickTimer.Stop();
352 g_Platform->HideBusySpinner();
353 m_RescanButton->Enable();
354 m_SendButton->SetDefault();
356 m_PeerListBox->Enable(
true);
357 m_bScanOnCreate =
false;
359 m_PeerListBox->Clear();
362 using namespace ocpn;
364 if (g_hostname !=
split(e.hostname,
".")[0] || m_ownipAddr != e.ip) {
365 m_PeerListBox->Append(e.hostname +
" {" + e.ip.c_str() +
"}");
368 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
369 m_SendButton->Enable(m_PeerListBox->GetCount() > 0);
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);
381 FindAllOCPNServers(m_scanTime);
383 m_tick = m_scanTime * 2;
384 m_ScanTickTimer.Start(500, wxTIMER_CONTINUOUS);
387void SendToPeerDlg::OnCancelClick(wxCommandEvent&) {
388 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, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
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.
Standard, mostly strings utilities.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
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.
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.
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.