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 m_own_ip_addresses = get_local_ipv4_addresses();
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::IsOwnAddress(
const std::string& address)
const {
219 const auto& v = m_own_ip_addresses;
220 return std::find(v.begin(), v.end(), address) != v.end();
223bool SendToPeerDlg::EnableActivateChkbox() {
224 return m_RouteList.size() == 1 && m_RoutePointList.empty() &&
228void 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 == item.BeforeFirst(
'.'))
continue;
250 if (IsOwnAddress(entry.ip))
continue;
251 item += std::string(
" {") + entry.ip.c_str() +
"}";
252 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);
331 if (is_writable || ConfirmWriteDlg() == PeerDlgResult::Ok) {
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] || !IsOwnAddress(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, 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.