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