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