OpenCPN Partial API docs
Loading...
Searching...
No Matches
ais_target_query_dlg.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2013 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************
23 */
24
25#include <wx/wxprec.h>
26
27#include <wx/html/htmlwin.h>
28
29#include "model/ais_decoder.h"
31#include "model/ais_target_data.h"
32#include "model/route_point.h"
33#include "model/select.h"
34#include "model/track.h"
35
36#include "ais.h"
38#include "chcanv.h"
39#include "FontMgr.h"
40#include "navutil.h"
41#include "ocpn_frame.h"
42#include "OCPNPlatform.h"
43#include "routemanagerdialog.h"
44#include "model/navobj_db.h"
45
46extern AISTargetQueryDialog *g_pais_query_dialog_active;
47extern ColorScheme global_color_scheme;
48extern wxString g_default_wp_icon;
49extern MyConfig *pConfig;
50extern RouteManagerDialog *pRouteManagerDialog;
51extern std::vector<Track *> g_TrackList;
52extern OCPNPlatform *g_Platform;
53extern MyFrame *gFrame;
54
55#define xID_OK 10009
56#define xID_WPT_CREATE 10010
57#define xID_TRK_CREATE 10011
58IMPLEMENT_CLASS(AISTargetQueryDialog, wxDialog)
59// AISTargetQueryDialog event table definition
60BEGIN_EVENT_TABLE(AISTargetQueryDialog, wxFrame)
61EVT_BUTTON(xID_OK, AISTargetQueryDialog::OnIdOKClick)
62EVT_BUTTON(xID_WPT_CREATE, AISTargetQueryDialog::OnIdWptCreateClick)
63EVT_BUTTON(xID_TRK_CREATE, AISTargetQueryDialog::OnIdTrkCreateClick)
64EVT_CLOSE(AISTargetQueryDialog::OnClose)
65EVT_MOVE(AISTargetQueryDialog::OnMove)
66EVT_SIZE(AISTargetQueryDialog::OnSize)
67EVT_CHAR_HOOK(AISTargetQueryDialog::OnKey)
68END_EVENT_TABLE()
69
70AISTargetQueryDialog *g_pais_query_dialog_active;
71
73
74AISTargetQueryDialog::AISTargetQueryDialog(wxWindow *parent, wxWindowID id,
75 const wxString &caption,
76 const wxPoint &pos,
77 const wxSize &size, long style) {
78 Init();
79 Create(parent, id, caption, pos, size, style);
80}
81
82AISTargetQueryDialog::~AISTargetQueryDialog() { delete m_pQueryTextCtl; }
83
85 m_MMSI = -1;
86 m_pQueryTextCtl = NULL;
87 m_nl = 0;
88 m_colorscheme = (ColorScheme)(-1);
89 m_okButton = NULL;
90 m_bautoCentre = false;
91 m_bautosize = false;
92}
93void AISTargetQueryDialog::OnClose(wxCloseEvent &event) {
94 Destroy();
96}
97
98void AISTargetQueryDialog::OnIdOKClick(wxCommandEvent &event) { Close(); }
99
100void AISTargetQueryDialog::OnKey(wxKeyEvent &ke) {
101 if (ke.GetKeyCode() == WXK_ESCAPE)
102 Close(true);
103 else
104 ke.Skip();
105}
106
107void AISTargetQueryDialog::OnIdWptCreateClick(wxCommandEvent &event) {
108 if (m_MMSI != 0) { // Faulty MMSI could be reported as 0
109 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
110 if (td) {
111 wxString n0 = wxString::Format("%s", td->ShipName);
112 n0.Replace("@", " ");
113 n0.Trim();
114 wxString mmsi = wxString::Format("%i ", td->MMSI);
115 wxString n = "\"" + n0 + "\" " + mmsi;
116 n.append(wxDateTime::Now().Format("%H:%M"));
117 // wxString n = wxString::Format("\"%s\" %i ",td->ShipName,
118 // td->MMSI).append(wxDateTime::Now().Format("%H:%M"));
119 RoutePoint *pWP =
120 new RoutePoint(td->Lat, td->Lon, g_default_wp_icon, n, wxEmptyString);
121 pWP->m_bIsolatedMark = true; // This is an isolated mark
122 pSelect->AddSelectableRoutePoint(td->Lat, td->Lon, pWP);
123 // pConfig->AddNewWayPoint(pWP, -1); // use auto next num
124 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
125
126 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
127 pRouteManagerDialog->UpdateWptListCtrl();
128 gFrame->GetPrimaryCanvas()->undo->BeforeUndoableAction(
129 Undo_CreateWaypoint, pWP, Undo_HasParent, NULL);
130 gFrame->GetPrimaryCanvas()->undo->AfterUndoableAction(NULL);
131 Refresh(false);
132 }
133 }
134}
135
136void AISTargetQueryDialog::OnIdTrkCreateClick(wxCommandEvent &event) {
137 if (m_MMSI != 0) { // Faulty MMSI could be reported as 0
138 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
139 if (td) {
140 if (td->b_PersistTrack) // The target was tracked and the user wants to
141 // stop it
142 {
143 td->b_PersistTrack = false;
144 g_pAIS->m_persistent_tracks.erase(td->MMSI);
145 m_createTrkBtn->SetLabel(_("Record Track"));
146 td->b_show_track = td->b_show_track_old;
147 } else {
148 TrackPoint *tp = NULL;
149 TrackPoint *tp1 = NULL;
150
151 Track *t = new Track();
152
153 t->SetName(wxString::Format("AIS %s (%u) %s %s",
154 td->GetFullName().c_str(), td->MMSI,
155 wxDateTime::Now().FormatISODate().c_str(),
156 wxDateTime::Now().FormatISOTime().c_str()));
157 for (const AISTargetTrackPoint &ptrack_point : td->m_ptrack) {
158 vector2D point(ptrack_point.m_lon, ptrack_point.m_lat);
159 tp1 = t->AddNewPoint(point, wxDateTime(ptrack_point.m_time).ToUTC());
160 if (tp) {
161 pSelect->AddSelectableTrackSegment(tp->m_lat, tp->m_lon, tp1->m_lat,
162 tp1->m_lon, tp, tp1, t);
163 }
164 tp = tp1;
165 }
166
167 g_TrackList.push_back(t);
168 // pConfig->AddNewTrack(t);
169 NavObj_dB::GetInstance().InsertTrack(t);
170
171 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
172 pRouteManagerDialog->UpdateTrkListCtrl();
173 Refresh(false);
174
175 if (wxID_YES ==
176 OCPNMessageBox(
177 gFrame,
178 _("The recently captured track of this target has been "
179 "recorded.\nDo you want to continue recording until the end "
180 "of the current OpenCPN session?"),
181 _("OpenCPN Info"), wxYES_NO | wxCENTER, 60)) {
182 td->b_PersistTrack = true;
183 g_pAIS->m_persistent_tracks[td->MMSI] = t;
184 td->b_show_track_old = td->b_show_track;
185 td->b_show_track = true;
186 }
187 }
188 }
189 }
190}
191
192bool AISTargetQueryDialog::Create(wxWindow *parent, wxWindowID id,
193 const wxString &caption, const wxPoint &pos,
194 const wxSize &size, long style) {
195 long wstyle = AIS_TARGET_QUERY_STYLE;
196
197 if (!wxFrame::Create(parent, id, caption, pos, size, wstyle)) return false;
198
199 m_parent = parent;
200
201 wxFont *dFont = FontMgr::Get().GetFont(_("AISTargetQuery"));
202 int font_size = wxMax(8, dFont->GetPointSize());
203 wxString face = dFont->GetFaceName();
204#ifdef __WXGTK__
205 face = "Monospace";
206#endif
207 m_basefont = FontMgr::Get().FindOrCreateFont(font_size, wxFONTFAMILY_MODERN,
208 wxFONTSTYLE_NORMAL,
209 dFont->GetWeight(), false, face);
210 m_adjustedFontSize = dFont->GetPointSize();
211 m_control_font_size = dFont->GetPointSize();
212 SetFont(*m_basefont);
213
214 CreateControls();
215
216 SetColorScheme(global_color_scheme);
217
218 // Set the maximum size of the entire settings dialog
219 wxSize sz = g_Platform->getDisplaySize();
220 SetSizeHints(50, 50, sz.x - 20, sz.y - 40);
221
222 if (!m_bautosize) {
223 Fit(); // Sets the horizontal size OK
224 Layout();
225 SetSize(-1, m_adjustedFontSize * 30); // Estimated vertical size
226 }
227
228 return true;
229}
230
231void AISTargetQueryDialog::SetMMSI(int mmsi) {
232 m_MMSI = mmsi;
233
234 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
235 AdjustBestSize(td.get());
236}
237
238void AISTargetQueryDialog::RecalculateSize() {
239 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
240 AdjustBestSize(td.get());
241 return;
242}
243
244void AISTargetQueryDialog::SetColorScheme(ColorScheme cs) {
245 DimeControl(this);
246 wxColor bg = GetBackgroundColour();
247 m_pQueryTextCtl->SetBackgroundColour(bg);
248 SetBackgroundColour(
249 bg); // This looks like non-sense, but is needed for __WXGTK__
250 // to get colours to propagate down the control's family tree.
251
252#ifdef __WXQT__
253 // wxQT has some trouble clearing the background of HTML window...
254 wxBitmap tbm(GetSize().x, GetSize().y, -1);
255 wxMemoryDC tdc(tbm);
256 // wxColour cback = GetGlobalColor( "YELO1" );
257 tdc.SetBackground(bg);
258 tdc.Clear();
259 m_pQueryTextCtl->SetBackgroundImage(tbm);
260#endif
261
262 if (cs != m_colorscheme) {
263 Refresh();
264 }
265 m_colorscheme = cs;
266}
267
268void AISTargetQueryDialog::CreateControls() {
269 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
270 SetSizer(topSizer);
271
272 m_pQueryTextCtl =
273 new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
274 wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION);
275 m_pQueryTextCtl->SetBorders(1);
276 m_pQueryTextCtl->SetFont(*m_basefont);
277 topSizer->Add(m_pQueryTextCtl, 1, wxALL | wxEXPAND, 5);
278
279 wxSizer *opt = new wxBoxSizer(wxHORIZONTAL);
280 m_createWptBtn = new wxButton(this, xID_WPT_CREATE, _("Create Waypoint"),
281 wxDefaultPosition, wxDefaultSize, 0);
282 opt->Add(m_createWptBtn, 0, wxALL | wxEXPAND, 5);
283
284 m_createTrkBtn = new wxButton(this, xID_TRK_CREATE, _("Record Track"),
285 wxDefaultPosition, wxDefaultSize, 0);
286 opt->Add(m_createTrkBtn, 0, wxALL | wxEXPAND, 5);
287 topSizer->Add(opt, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 5);
288
289 topSizer->Add(new wxButton(this, xID_OK, _("OK")), 0,
290 wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 5);
291
292 Fit();
293}
294
295void AISTargetQueryDialog::UpdateText() {
296 wxString html;
297
298 if (!m_pQueryTextCtl) return;
299
300 int scroll_x, scroll_y;
301 m_pQueryTextCtl->GetViewStart(&scroll_x, &scroll_y);
302
303 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
304 // AdjustBestSize(td);
305
306 DimeControl(this);
307 wxColor bg = GetBackgroundColour();
308 m_pQueryTextCtl->SetBackgroundColour(bg);
309 SetBackgroundColour(bg);
310
311 if (td) {
312 if (td->b_PersistTrack)
313 m_createTrkBtn->SetLabel(_("Save Track"));
314 else
315 m_createTrkBtn->SetLabel(_("Record Track"));
316
317 m_createWptBtn->Enable(td->b_positionOnceValid);
318
319 if (td->Class == AIS_METEO || td->Class == AIS_BASE)
320 m_createTrkBtn->Disable();
321 else
322 m_createTrkBtn->Enable();
323
324 RenderHTMLQuery(td.get());
325 }
326
327#ifdef __WXQT__
328 SetColorScheme(m_colorscheme);
329#endif
330
331 m_pQueryTextCtl->Scroll(scroll_x, scroll_y);
332}
333
334void AISTargetQueryDialog::OnMove(wxMoveEvent &event) {
335 // Record the dialog position
336 wxPoint p = event.GetPosition();
337 g_ais_query_dialog_x = p.x;
338 g_ais_query_dialog_y = p.y;
339
340 event.Skip();
341}
342
343void AISTargetQueryDialog::OnSize(wxSizeEvent &event) { event.Skip(); }
344
345void AISTargetQueryDialog::AdjustBestSize(AisTargetData *td) {
346 if (!td) return;
347
348 wxSize origSize = GetSize();
349
350 Fit();
351 RenderHTMLQuery(td);
352
353 int target_x = -1;
354 int target_y = -1;
355
356 // Width adjustments
357
358 if (m_bautosize) {
359 // Reduce the font size if necessary to eliminate horizontal scroll bars.
360 wxSize szv = m_pQueryTextCtl->GetVirtualSize();
361 if (szv.x > m_pQueryTextCtl->GetSize().x) {
362 while ((szv.x > m_pQueryTextCtl->GetSize().x) &&
363 (m_adjustedFontSize > 8)) { // fluff
364 m_adjustedFontSize--;
365
366 RenderHTMLQuery(td);
367 m_pQueryTextCtl->Refresh();
368 m_pQueryTextCtl->Update();
369 Layout();
370 szv = m_pQueryTextCtl->GetVirtualSize();
371 }
372
373 m_adjustedFontSize--;
374 }
375 target_x = szv.x * 12 /
376 10; // Making the winfow a bit wider than absolutely nesessary
377 // gives a little better results in real world
378 } else {
379 wxSize szv = m_pQueryTextCtl->GetVirtualSize();
380 int csz = g_Platform->getDisplaySize().x * 8 / 10;
381 if ((szv.x) < csz) {
382 if (szv.x > m_pQueryTextCtl->GetSize().x) target_x = szv.x; // * 11/10;
383 }
384 target_x = szv.x * 12 /
385 10; // Making the winfow a bit wider than absolutely nesessary
386 // gives a little better results in real world
387 }
388
389#ifdef __ANDROID__
390 // Now adjust the font size used for the control buttons.
391 // This adjustment makes sure that the two horizontal buttons are not wider
392 // than the platform display allows. This may be a problem on phones,
393 // but probably never on normal computer displays. some platforms also don't
394 // support this at all
395
396 if (m_createWptBtn && m_createTrkBtn) {
397 wxSize psz = g_Platform->getDisplaySize();
398
399 wxScreenDC dc;
400 wxFont *tFont = FontMgr::Get().FindOrCreateFont(
401 m_control_font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
402 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
403 dc.SetFont(*tFont);
404
405 wxSize tsz = dc.GetTextExtent(m_createWptBtn->GetLabel() +
406 m_createTrkBtn->GetLabel());
407
408 float totalButtonWidth = tsz.x;
409
410 if (totalButtonWidth * 1.5 > psz.x) {
411 float delta = (float)totalButtonWidth * 2. / psz.x;
412
413 float font_size = m_control_font_size / delta;
414
415 wxFont *fp_font = FontMgr::Get().FindOrCreateFont(
416 font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
417 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
418
419 m_createWptBtn->SetFont(*fp_font);
420 m_createTrkBtn->SetFont(*fp_font);
421
422 m_control_font_size = font_size;
423 }
424 }
425#endif
426
427 // Height adjustments
428 // Try to avoid vertical scroll bar if possible.
429
430 // Estimate the control button area height
431 int yb = 0;
432 if (m_createWptBtn) yb = m_createWptBtn->GetSize().y * 4;
433
434 wxSize szyv = m_pQueryTextCtl->GetVirtualSize();
435 int csz = g_Platform->getDisplaySize().y * 85 / 100;
436 if ((szyv.y + yb) < csz) {
437 if (szyv.y > m_pQueryTextCtl->GetSize().y) target_y = szyv.y * 12 / 10 + yb;
438 } else {
439 target_y = csz;
440 }
441 SetSize(target_x, target_y);
442
443 wxSize nowSize = GetSize();
444
445 if (nowSize != origSize) {
446 if (m_bautoCentre) Centre();
447 }
448}
449
450void AISTargetQueryDialog::RenderHTMLQuery(AisTargetData *td) {
451 int font_size = m_adjustedFontSize;
452 wxFont *fp_font = FontMgr::Get().FindOrCreateFont(
453 font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
454 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
455
456 SetFont(*fp_font);
457
458 int sizes[7];
459 for (int i = -2; i < 5; i++) {
460 sizes[i + 2] = fp_font->GetPointSize() + i + (i > 0 ? i : 0);
461 }
462
463 wxString html;
464 wxColor bg = GetBackgroundColour();
465 wxColor fg = GetForegroundColour();
466
467 html.Printf(
468 "<html><body bgcolor=#%02x%02x%02x><font "
469 "color=#%02x%02x%02x><center>",
470 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
471
472 html << td->BuildQueryResult();
473
474 html << "</center></font></body></html>";
475
476 m_pQueryTextCtl->SetFonts(fp_font->GetFaceName(), fp_font->GetFaceName(),
477 sizes);
478
479 wxCharBuffer buf = html.ToUTF8();
480 if (buf.data()) // string OK?
481 m_pQueryTextCtl->SetPage(html);
482}
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetQueryDialog.
AISTargetQueryDialog * g_pais_query_dialog_active
Global instance.
Generic Chart canvas base.
Dialog for querying detailed information about an AIS target.
AISTargetQueryDialog()
Constructors.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
void Init()
Initialise our variables.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
Definition FontMgr.cpp:449
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Definition FontMgr.cpp:200
Main application frame.
Definition ocpn_frame.h:138
Provides platform-specific support utilities for OpenCPN.
wxSize getDisplaySize()
Get the display size in logical pixels.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:70
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
Represents a single point in a track.
Definition track.h:56
Represents a track, which is a series of connected track points.
Definition track.h:114
Class NavObj_dB.