26#include <wx/statline.h>
51#include "androidUTIL.h"
54#define TIMER_AUTOSCAN 94522
55#define TIMER_SCANTICK 94523
57static PeerDlgResult ConfirmWriteDlg() {
58 std::string msg(_(
"Objects exists on server. OK to overwrite?"));
59 long style = wxYES | wxNO | wxNO_DEFAULT | wxICON_QUESTION;
61 int reply = dlg.ShowModal();
62 return reply == wxID_YES ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
65static PeerDlgResult RunStatusDlg(PeerDlg kind,
int status) {
67 case PeerDlg::InvalidHttpResponse: {
70 ss << _(
"Server HTTP response is :") << status;
72 ss << _(
"Curl transfer error: ")
73 << curl_easy_strerror(
static_cast<CURLcode
>(-status));
76 wxICON_ERROR | wxOK | wxCANCEL);
77 int r = dlg.ShowModal();
78 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
80 case PeerDlg::ErrorReturn: {
82 ss << _(
"Server internal error response:") << status;
84 wxICON_ERROR | wxOK | wxCANCEL);
85 int r = dlg.ShowModal();
86 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
88 case PeerDlg::TransferOk: {
90 std::string msg(_(
"Transfer successfully completed"));
92 wxICON_INFORMATION | wxOK);
94 return PeerDlgResult::Ok;
96 case PeerDlg::JsonParseError: {
97 std::string msg(_(
"Cannot parse server reply"));
99 wxICON_ERROR | wxOK | wxCANCEL);
100 int r = dlg.ShowModal();
101 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
103 case PeerDlg::BadPincode: {
104 std::string msg(_(
"Pincode not accepted"));
106 wxICON_ERROR | wxOK | wxCANCEL);
107 int r = dlg.ShowModal();
108 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
110 case PeerDlg::ActivateUnsupported: {
111 std::string msg(_(
"Server does not support activation"));
113 wxICON_ERROR | wxOK | wxCANCEL);
115 int r = dlg.ShowModal();
116 return r == wxID_OK ? PeerDlgResult::Ok : PeerDlgResult::Cancel;
118 case PeerDlg::PinConfirm:
119 assert(
false &&
"Illegal PinConfirm result dialog");
121 return PeerDlgResult::Cancel;
125static void ParsePeer(
const wxString& ui_value,
PeerData& peer_data) {
126 wxString server_name = ui_value.BeforeFirst(
'{').Trim();
127 wxString peer_ip = ui_value;
128 int tail = ui_value.Find(
'{');
129 if (tail != wxNOT_FOUND) peer_ip = peer_ip.Mid(tail + 1);
130 peer_ip = peer_ip.BeforeFirst(
'}') +
":";
132 peer_ip += server_name.BeforeFirst(
'-') ==
"Portable" ?
"8444" :
"8443";
133 peer_data.server_name = server_name.ToStdString();
134 peer_data.dest_ip_address = peer_ip.ToStdString();
137std::pair<PeerDlgResult, std::string> RunPincodeDlg() {
139 _(
"OpenCPN Server Message"),
"", wxDefaultPosition,
140 wxDefaultSize, SYMBOL_PCD_STYLE);
142 static const char*
const msg =
143 _(
"A server pin is needed.\n"
144 "Please enter PIN number from server to pair with this device");
147 dlg.SetPincodeText(
"");
148 if (dlg.ShowModal() == wxID_OK) {
149 auto pin = dlg.GetPincodeText().Trim().Trim(
false);
150 return {PeerDlgResult::HasPincode, pin.ToStdString()};
152 return {PeerDlgResult::Cancel,
""};
156EVT_BUTTON(ID_STP_CANCEL, SendToPeerDlg::OnCancelClick)
157EVT_BUTTON(ID_STP_OK, SendToPeerDlg::OnSendClick)
158EVT_BUTTON(ID_STP_SCAN, SendToPeerDlg::OnScanClick)
159EVT_TIMER(TIMER_AUTOSCAN, SendToPeerDlg::OnTimerAutoscan)
160EVT_TIMER(TIMER_SCANTICK, SendToPeerDlg::OnTimerScanTick)
164 m_PeerListBox = NULL;
167 m_CancelButton = NULL;
170 m_bScanOnCreate =
false;
173 std::vector<std::string> ipv4_addrs = get_local_ipv4_addresses();
174 if (ipv4_addrs.size()) m_ownipAddr = ipv4_addrs[0];
177 androidDisableRotation();
181SendToPeerDlg::~SendToPeerDlg() {
182 delete m_PeerListBox;
185 delete m_CancelButton;
187 androidEnableRotation();
191bool SendToPeerDlg::Create(wxWindow* parent, wxWindowID
id,
192 const wxString& caption,
const wxString& hint,
193 const wxPoint& pos,
const wxSize& size,
long style) {
194 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
198 wxDialog::Create(parent,
id, caption, pos, size, style);
200 CreateControls(hint);
201 GetSizer()->Fit(
this);
202 GetSizer()->SetSizeHints(
this);
205 if (m_bScanOnCreate) {
206 m_autoScanTimer.SetOwner(
this, TIMER_AUTOSCAN);
207 m_autoScanTimer.Start(500, wxTIMER_ONE_SHOT);
209 m_ScanTickTimer.SetOwner(
this, TIMER_SCANTICK);
211 auto action = [&](
ObservedEvt& evt) { m_pgauge->SetValue(evt.GetInt()); };
212 progress_listener.
Init(progress, action);
214 androidDisableRotation();
219bool SendToPeerDlg::EnableActivateChkbox() {
220 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
224void SendToPeerDlg::CreateControls(
const wxString&) {
227 wxBoxSizer* itemBoxSizer2 =
new wxBoxSizer(wxVERTICAL);
228 itemDialog1->SetSizer(itemBoxSizer2);
232 wxStaticBox* comm_box =
233 new wxStaticBox(
this, wxID_ANY, _(
"Detected OpenCPN peer instances"));
235 wxStaticBoxSizer* comm_box_sizer =
new wxStaticBoxSizer(comm_box, wxVERTICAL);
236 itemBoxSizer2->Add(comm_box_sizer, 0, wxEXPAND | wxALL, 5);
238 m_PeerListBox =
new wxComboBox(
this, ID_STP_CHOICE_PEER);
241 for (
auto& entry :
MdnsCache::GetInstance().GetCache()) {
242 wxString item(entry.hostname.c_str());
245 if (!g_hostname.IsSameAs(item.BeforeFirst(
'.')) ||
246 (m_ownipAddr != entry.ip)) {
248 item += entry.ip.c_str();
250 m_PeerListBox->Append(item);
254 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
255 m_PeerListBox->Bind(wxEVT_TEXT, [&](wxCommandEvent&) {
256 m_SendButton->Enable(m_PeerListBox->GetValue() !=
"");
258 m_PeerListBox->Enable(!m_bScanOnCreate);
259 comm_box_sizer->Add(m_PeerListBox, 0, wxEXPAND | wxALL, 5);
261 wxBoxSizer* itemBoxSizer3 =
new wxBoxSizer(wxVERTICAL);
262 itemBoxSizer2->Add(itemBoxSizer3, 0, wxEXPAND | wxALL, 5);
264 m_RescanButton =
new wxButton(itemDialog1, ID_STP_SCAN, _(
"Scan again"),
265 wxDefaultPosition, wxDefaultSize, 0);
266 itemBoxSizer3->Add(m_RescanButton, 0, wxALL, 5);
268 m_pgauge =
new wxGauge(itemDialog1, -1, m_scanTime * 2, wxDefaultPosition,
269 wxSize(-1, GetCharHeight()));
270 itemBoxSizer3->Add(m_pgauge, 0, wxEXPAND | wxALL, 20);
272 itemBoxSizer2->AddSpacer(30);
273 itemBoxSizer2->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
275 new wxCheckBox(
this, wxID_ANY, _(
"Activate after transfer"),
276 wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
277 itemBoxSizer2->Add(m_activate_chkbox, 0, wxALIGN_RIGHT | wxALL, 10);
278 if (!EnableActivateChkbox()) m_activate_chkbox->Disable();
281 wxBoxSizer* itemBoxSizer16 =
new wxBoxSizer(wxHORIZONTAL);
282 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
284 m_CancelButton =
new wxButton(itemDialog1, ID_STP_CANCEL, _(
"Cancel"),
285 wxDefaultPosition, wxDefaultSize, 0);
286 itemBoxSizer16->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
288 m_SendButton =
new wxButton(itemDialog1, ID_STP_OK, _(
"Send"),
289 wxDefaultPosition, wxDefaultSize, 0);
290 itemBoxSizer16->Add(m_SendButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
291 m_SendButton->SetDefault();
292 m_SendButton->Enable(!m_PeerListBox->IsListEmpty());
295void SendToPeerDlg::SetMessage(wxString msg) {
297 premtext->SetLabel(msg);
298 premtext->Refresh(
true);
302void SendToPeerDlg::OnSendClick(wxCommandEvent&) {
303 if (m_RouteList.empty() && m_TrackList.empty() && m_RoutePointList.empty()) {
309 ParsePeer(m_PeerListBox->GetValue(), peer_data);
310 auto addr_port =
ocpn::split(peer_data.dest_ip_address,
":");
311 if (addr_port.size() == 1) addr_port.push_back(
"8443");
312 MdnsCache::GetInstance().
Add(addr_port[0], addr_port[1]);
313 peer_data.routes = m_RouteList;
314 peer_data.tracks = m_TrackList;
315 peer_data.routepoints = m_RoutePointList;
318 peer_data.
activate = m_activate_chkbox->GetValue();
321 m_pgauge->SetRange(100);
322 m_pgauge->SetValue(0);
325 GetApiVersion(peer_data);
330 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
339void SendToPeerDlg::OnScanClick(wxCommandEvent&) { DoScan(); }
341void SendToPeerDlg::OnTimerAutoscan(wxTimerEvent&) { DoScan(); }
343void SendToPeerDlg::OnTimerScanTick(wxTimerEvent&) {
346 int v = m_pgauge->GetValue();
347 if (v + 1 <= m_pgauge->GetRange()) m_pgauge->SetValue(v + 1);
352 m_ScanTickTimer.Stop();
353 g_Platform->HideBusySpinner();
354 m_RescanButton->Enable();
355 m_SendButton->SetDefault();
357 m_PeerListBox->Enable(
true);
358 m_bScanOnCreate =
false;
360 m_PeerListBox->Clear();
363 using namespace ocpn;
365 if (g_hostname !=
split(e.hostname,
".")[0] || m_ownipAddr != e.ip) {
366 m_PeerListBox->Append(e.hostname +
" {" + e.ip.c_str() +
"}");
369 if (m_PeerListBox->GetCount()) m_PeerListBox->SetSelection(0);
370 m_SendButton->Enable(m_PeerListBox->GetCount() > 0);
374void SendToPeerDlg::DoScan() {
375 m_RescanButton->Disable();
376 m_SendButton->Disable();
377 g_Platform->ShowBusySpinner();
378 m_pgauge->SetRange(m_scanTime);
379 m_pgauge->SetValue(0);
382 FindAllOCPNServers(m_scanTime);
384 m_tick = m_scanTime * 2;
385 m_ScanTickTimer.Start(500, wxTIMER_CONTINUOUS);
388void SendToPeerDlg::OnCancelClick(wxCommandEvent&) {
389 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.