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