OpenCPN Partial API docs
Loading...
Searching...
No Matches
ais_target_list_dlg.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2010 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 "gl_headers.h" // Must be included before anything using GL stuff
26
27#include <wx/textctrl.h>
28#include <wx/sizer.h>
29#include <wx/tokenzr.h>
30#include <wx/clipbrd.h>
31
32#ifdef __ANDROID__
33#include "androidUTIL.h"
34#endif
35
36#include "model/ais_decoder.h"
39#include "model/route_point.h"
40#include "model/select.h"
41
42#include "ais.h"
43#include "ais_target_list_dlg.h"
44#include "chcanv.h"
45#include "ocpn_frame.h"
46#include "ocpn_list_ctrl.h"
47#include "ocpn_platform.h"
48#include "routemanagerdialog.h"
49#include "styles.h"
50#include "model/navobj_db.h"
51
52extern ocpnStyle::StyleManager *g_StyleManager;
53extern MyConfig *pConfig;
54extern AISTargetListDialog *g_pAISTargetList;
55extern MyFrame *gFrame;
56extern wxString g_default_wp_icon;
57extern RouteManagerDialog *pRouteManagerDialog;
58
59AISTargetListDialog *g_pAISTargetList;
60
61static int g_AisTargetList_count;
62static AisDecoder *s_p_sort_decoder;
63static bool g_bAisTargetList_autosort;
64
65IMPLEMENT_CLASS(AISTargetListDialog, wxPanel)
66
67BEGIN_EVENT_TABLE(AISTargetListDialog, wxPanel)
68EVT_CLOSE(AISTargetListDialog::OnClose)
69END_EVENT_TABLE()
70
71static bool g_bsort_once;
72
73static int ItemCompare(AisTargetData *pAISTarget1, AisTargetData *pAISTarget2) {
74 wxString s1, s2;
75 double n1 = 0.;
76 double n2 = 0.;
77 bool b_cmptype_num = false;
78
79 // Don't sort unless requested
80 if (!g_bAisTargetList_autosort && !g_bsort_once) return 0;
81
82 AisTargetData *t1 = pAISTarget1;
83 AisTargetData *t2 = pAISTarget2;
84
85 if (t1->Class == AIS_SART) {
86 if (t2->Class == AIS_DSC)
87 return 0;
88 else
89 return -1;
90 }
91
92 if (t2->Class == AIS_SART) {
93 if (t1->Class == AIS_DSC)
94 return 0;
95 else
96 return 1;
97 }
98
99 switch (g_AisTargetList_sortColumn) {
100 case tlTRK:
101 n1 = t1->b_show_track;
102 n2 = t2->b_show_track;
103 b_cmptype_num = true;
104 break;
105
106 case tlNAME:
107 s1 = trimAISField(t1->ShipName);
108 if ((!t1->b_nameValid && (t1->Class == AIS_BASE)) ||
109 (t1->Class == AIS_SART))
110 s1 = "-";
111
112 s2 = trimAISField(t2->ShipName);
113 if ((!t2->b_nameValid && (t2->Class == AIS_BASE)) ||
114 (t2->Class == AIS_SART))
115 s2 = "-";
116 break;
117
118 case tlCALL:
119 s1 = trimAISField(t1->CallSign);
120 s2 = trimAISField(t2->CallSign);
121 break;
122
123 case tlMMSI:
124 n1 = t1->MMSI;
125 n2 = t2->MMSI;
126 b_cmptype_num = true;
127 break;
128
129 case tlCLASS:
130 s1 = t1->Get_class_string(true);
131 s2 = t2->Get_class_string(true);
132 break;
133
134 case tlTYPE:
135 s1 = t1->Get_vessel_type_string(false);
136 if ((t1->Class == AIS_BASE) ||
137 (t1->Class == AIS_SART || (t1->Class == AIS_METEO)))
138 s1 = "-";
139
140 s2 = t2->Get_vessel_type_string(false);
141 if ((t1->Class == AIS_BASE) || (t1->Class == AIS_SART) ||
142 (t1->Class == AIS_METEO))
143 s2 = "-";
144 break;
145
146 case tlFLAG:
147 s1 = t1->GetCountryCode(true);
148 s2 = t2->GetCountryCode(true);
149 break;
150 case tlNAVSTATUS: {
151 if ((t1->NavStatus <= 15) && (t1->NavStatus >= 0)) {
152 if (t1->Class == AIS_SART) {
153 if (t1->NavStatus == RESERVED_14)
154 s1 = _("Active");
155 else if (t1->NavStatus == UNDEFINED)
156 s1 = _("Testing");
157 } else
158 s1 = ais_get_status(t1->NavStatus);
159 } else
160 s1 = _("-");
161
162 if ((t1->Class == AIS_ATON) || (t1->Class == AIS_BASE) ||
163 (t1->Class == AIS_CLASS_B) || (t1->Class == AIS_METEO))
164 s1 = "-";
165
166 if ((t2->NavStatus <= 15) && (t2->NavStatus >= 0)) {
167 if (t2->Class == AIS_SART) {
168 if (t2->NavStatus == RESERVED_14)
169 s2 = _("Active");
170 else if (t2->NavStatus == UNDEFINED)
171 s2 = _("Testing");
172 } else
173 s2 = ais_get_status(t2->NavStatus);
174 } else
175 s2 = _("-");
176
177 if ((t2->Class == AIS_ATON) || (t2->Class == AIS_BASE) ||
178 (t2->Class == AIS_CLASS_B) || (t2->Class == AIS_METEO))
179 s2 = "-";
180
181 break;
182 }
183
184 case tlBRG: {
185 int brg1 = wxRound(t1->Brg);
186 if (brg1 == 360)
187 n1 = 0.;
188 else
189 n1 = brg1;
190
191 int brg2 = wxRound(t2->Brg);
192 if (brg2 == 360)
193 n2 = 0.;
194 else
195 n2 = brg2;
196
197 b_cmptype_num = true;
198 break;
199 }
200
201 case tlCOG: {
202 if ((t1->COG >= 360.0) || (t1->Class == AIS_ATON) ||
203 (t1->Class == AIS_BASE) || (t1->Class == AIS_METEO))
204 n1 = -1.0;
205 else {
206 int crs = wxRound(t1->COG);
207 if (crs == 360)
208 n1 = 0.;
209 else
210 n1 = crs;
211 }
212
213 if ((t2->COG >= 360.0) || (t2->Class == AIS_ATON) ||
214 (t2->Class == AIS_BASE) || (t2->Class == AIS_METEO))
215 n2 = -1.0;
216 else {
217 int crs = wxRound(t2->COG);
218 if (crs == 360)
219 n2 = 0.;
220 else
221 n2 = crs;
222 }
223
224 b_cmptype_num = true;
225 break;
226 }
227
228 case tlSOG: {
229 if ((t1->SOG > 100.) || (t1->Class == AIS_ATON) ||
230 (t1->Class == AIS_BASE) || (t1->Class == AIS_METEO))
231 n1 = -1.0;
232 else
233 n1 = t1->SOG;
234
235 if ((t2->SOG > 100.) || (t2->Class == AIS_ATON) ||
236 (t2->Class == AIS_BASE) || (t2->Class == AIS_METEO))
237 n2 = -1.0;
238 else
239 n2 = t2->SOG;
240
241 b_cmptype_num = true;
242 break;
243 }
244 case tlCPA: {
245 if ((!t1->bCPA_Valid) || (t1->Class == AIS_ATON) ||
246 (t1->Class == AIS_BASE) || (t1->Class == AIS_METEO))
247 n1 = 99999.0;
248 else
249 n1 = t1->CPA;
250
251 if ((!t2->bCPA_Valid) || (t2->Class == AIS_ATON) ||
252 (t2->Class == AIS_BASE))
253 n2 = 99999.0;
254 else
255 n2 = t2->CPA;
256
257 b_cmptype_num = true;
258 break;
259 }
260 case tlTCPA: {
261 if ((!t1->bCPA_Valid) || (t1->Class == AIS_ATON) ||
262 (t1->Class == AIS_BASE) || (t1->Class == AIS_METEO))
263 n1 = 99999.0;
264 else
265 n1 = t1->TCPA;
266
267 if ((!t2->bCPA_Valid) || (t2->Class == AIS_ATON) ||
268 (t2->Class == AIS_BASE) || (t2->Class == AIS_METEO))
269 n2 = 99999.0;
270 else
271 n2 = t2->TCPA;
272
273 b_cmptype_num = true;
274 break;
275 }
276 case tlRNG: {
277 n1 = t1->Range_NM;
278 n2 = t2->Range_NM;
279 b_cmptype_num = true;
280 break;
281 }
282
283 default:
284 break;
285 }
286
287 if (!b_cmptype_num) {
288 if (g_bAisTargetList_sortReverse) return s2.Cmp(s1);
289 return s1.Cmp(s2);
290 } else {
291 // If numeric sort values are equal, secondary sort is on Range_NM
292 if (g_bAisTargetList_sortReverse) {
293 if (n2 > n1)
294 return 1;
295 else if (n2 < n1)
296 return -1;
297 else
298 return (t1->Range_NM > t2->Range_NM); // 0;
299 } else {
300 if (n2 > n1)
301 return -1;
302 else if (n2 < n1)
303 return 1;
304 else
305 return (t1->Range_NM > t2->Range_NM); // 0;
306 }
307 }
308}
309
310static int ArrayItemCompareMMSI(int MMSI1, int MMSI2) {
311 if (s_p_sort_decoder) {
312 std::shared_ptr<AisTargetData> pAISTarget1 =
313 s_p_sort_decoder->Get_Target_Data_From_MMSI(MMSI1);
314 std::shared_ptr<AisTargetData> pAISTarget2 =
315 s_p_sort_decoder->Get_Target_Data_From_MMSI(MMSI2);
316
317 if (pAISTarget1 && pAISTarget2)
318 return ItemCompare(pAISTarget1.get(), pAISTarget2.get());
319 else
320 return 0;
321 } else
322 return 0;
323}
324
325AISTargetListDialog::AISTargetListDialog(wxWindow *parent, wxAuiManager *auimgr,
326 AisDecoder *pdecoder)
327 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, -1 /*780, 250*/),
328 wxBORDER_NONE) {
329 m_pparent = parent;
330 m_pAuiManager = auimgr;
331 m_pdecoder = pdecoder;
332 g_bsort_once = false;
333 m_bautosort_force = false;
334
335 wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
336 SetFont(*qFont);
337
338 s_p_sort_decoder = pdecoder;
339 m_pMMSI_array = new ArrayOfMMSI(ArrayItemCompareMMSI);
340
341 CreateControls();
342
343 // Set default color for panel, respecting Dark mode if enabled
344 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
345 SetColorScheme();
346
347 UpdateButtons();
348
349 if (m_pAuiManager) {
350 wxAuiPaneInfo paneproto = wxAuiPaneInfo()
351 .Name("AISTargetList")
352 .CaptionVisible(true)
353 .Float()
354 .FloatingPosition(50, 50)
355 .FloatingSize(400, 200)
356 .BestSize(700, GetCharHeight() * 10);
357
358 // Force and/or override any perspective information that is not
359 // applicable
360 paneproto.Caption(wxGetTranslation(_("AIS target list")));
361 paneproto.Name("AISTargetList");
362 paneproto.DestroyOnClose(true);
363 paneproto.TopDockable(false)
364 .BottomDockable(true)
365 .LeftDockable(false)
366 .RightDockable(false);
367 paneproto.Show(true);
368
369 m_pAuiManager->AddPane(this, paneproto);
370
371 wxAuiPaneInfo &pane = m_pAuiManager->GetPane("AISTargetList");
372
373 if (g_AisTargetList_perspective.IsEmpty()) {
374 if (!g_btouch) RecalculateSize();
375 } else {
376 m_pAuiManager->LoadPaneInfo(g_AisTargetList_perspective, pane);
377 m_pAuiManager->Update();
378 }
379
380 pane = m_pAuiManager->GetPane("AISTargetList"); // Refresh the reference
381
382 // Some special setup for touch screens
383 if (g_btouch) {
384 pane.Float();
385 pane.Dockable(false);
386
387 wxSize screen_size = gFrame->GetClientSize();
388 pane.FloatingSize(screen_size.x * 8 / 10, screen_size.y * 8 / 10);
389 pane.FloatingPosition(screen_size.x * 1 / 10, screen_size.y * 1 / 10);
390 m_pAuiManager->Update();
391 }
392
393 bool b_reset_pos = false;
394 if ((pane.floating_size.x != -1) && (pane.floating_size.y != -1)) {
395#ifdef __WXMSW__
396 // Support MultiMonitor setups which an allow negative window positions.
397 // If the requested window title bar does not intersect any installed
398 // monitor, then default to simple primary monitor positioning.
399 RECT frame_title_rect;
400 frame_title_rect.left = pane.floating_pos.x;
401 frame_title_rect.top = pane.floating_pos.y;
402 frame_title_rect.right = pane.floating_pos.x + pane.floating_size.x;
403 frame_title_rect.bottom = pane.floating_pos.y + 30;
404
405 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
406 b_reset_pos = true;
407#else
408
409 // Make sure drag bar (title bar) of window intersects wxClient Area of
410 // screen, with a little slop...
411 wxRect window_title_rect; // conservative estimate
412 window_title_rect.x = pane.floating_pos.x;
413 window_title_rect.y = pane.floating_pos.y;
414 window_title_rect.width = pane.floating_size.x;
415 window_title_rect.height = 30;
416
417 wxRect ClientRect = wxGetClientDisplayRect();
418 ClientRect.Deflate(
419 60, 60); // Prevent the new window from being too close to the edge
420 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos = true;
421
422#endif
423
424 if (b_reset_pos) {
425 pane.FloatingPosition(50, 50);
426 m_pAuiManager->Update();
427 }
428 }
429
430 // If the list got accidentally dropped on top of the chart bar, move it
431 // away....
432 if (pane.IsDocked() && (pane.dock_row == 0)) {
433 pane.Float();
434 pane.Row(1);
435 pane.Position(0);
436 m_pAuiManager->Update();
437 }
438
439 pane.Show(true);
440 m_pAuiManager->Update();
441
442 g_AisTargetList_perspective = m_pAuiManager->SavePaneInfo(pane);
443 pConfig->UpdateSettings();
444
445 m_pAuiManager->Connect(
446 wxEVT_AUI_PANE_CLOSE,
447 wxAuiManagerEventHandler(AISTargetListDialog::OnPaneClose), NULL, this);
448
449 } else {
450 // Make an estimate of the default dialog size
451 // for the case when the AUI Perspective for this dialog is undefined
452 wxSize esize;
453 esize.x = 700;
454 esize.y = GetCharHeight() * 10; // 18;
455 SetSize(esize);
456 }
457
458 // Connect Events
459 Connect(wxEVT_CONTEXT_MENU,
460 wxCommandEventHandler(AISTargetListDialog::OnRightClickContext), NULL,
461 this);
462}
463
464AISTargetListDialog::~AISTargetListDialog() {
465 Disconnect_decoder();
466 g_pAISTargetList = NULL;
467}
468
469void AISTargetListDialog::RecalculateSize() {
470 // Make an estimate of the dialog size
471
472 wxSize esize;
473 esize.x = GetCharWidth() * 110;
474 esize.y = GetCharHeight() * 40;
475
476 wxSize dsize = gFrame->GetClientSize();
477 esize.y = wxMin(esize.y, dsize.y - (4 * GetCharHeight()));
478 esize.x = wxMin(esize.x, dsize.x - (2 * GetCharHeight()));
479 SetClientSize(esize);
480
481 wxSize fsize = GetSize();
482 fsize.y = wxMin(fsize.y, dsize.y - (2 * GetCharHeight()));
483 fsize.x = wxMin(fsize.x, dsize.x - (2 * GetCharHeight()));
484 SetSize(fsize);
485
486 if (m_pAuiManager) {
487 wxAuiPaneInfo &pane = m_pAuiManager->GetPane("AISTargetList");
488
489 if (pane.IsOk()) {
490 pane.FloatingSize(fsize.x, fsize.y);
491 wxPoint pos = gFrame->GetScreenPosition();
492 pane.FloatingPosition(pos.x + (dsize.x - fsize.x) / 2,
493 pos.y + (dsize.y - fsize.y) / 2);
494 }
495
496 m_pAuiManager->Update();
497 }
498}
499
500void AISTargetListDialog::CreateControls() {
501 wxBoxSizer *topSizer = new wxBoxSizer(wxHORIZONTAL);
502 SetSizer(topSizer);
503#ifdef __ANDROID__
504 this->GetHandle()->setStyleSheet(getQtStyleSheet());
505#endif
506
507 // Parse the global column width string as read from config file
508 wxStringTokenizer tkz(g_AisTargetList_column_spec, ";");
509 wxString s_width = tkz.GetNextToken();
510 int width;
511 long lwidth;
512
513 long flags = wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES |
514 wxBORDER_SUNKEN;
515#ifndef __WXQT__
516 flags |= wxLC_VIRTUAL;
517#endif
518
519 m_pListCtrlAISTargets = new OCPNListCtrl(
520 this, ID_AIS_TARGET_LIST, wxDefaultPosition, wxDefaultSize, flags);
521
522 wxImageList *imglist = new wxImageList(16, 16, true, 2);
523
524 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
525 imglist->Add(style->GetIcon("sort_asc"));
526 imglist->Add(style->GetIcon("sort_desc"));
527
528 m_pListCtrlAISTargets->AssignImageList(imglist, wxIMAGE_LIST_SMALL);
529 m_pListCtrlAISTargets->Connect(
530 wxEVT_COMMAND_LIST_ITEM_SELECTED,
531 wxListEventHandler(AISTargetListDialog::OnTargetSelected), NULL, this);
532 m_pListCtrlAISTargets->Connect(
533 wxEVT_COMMAND_LIST_ITEM_DESELECTED,
534 wxListEventHandler(AISTargetListDialog::OnTargetSelected), NULL, this);
535 m_pListCtrlAISTargets->Connect(
536 wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
537 wxListEventHandler(AISTargetListDialog::OnTargetDefaultAction), NULL,
538 this);
539 m_pListCtrlAISTargets->Connect(
540 wxEVT_COMMAND_LIST_COL_CLICK,
541 wxListEventHandler(AISTargetListDialog::OnTargetListColumnClicked), NULL,
542 this);
543
544 int dx = GetCharWidth();
545
546 width = dx * 4;
547 if (s_width.ToLong(&lwidth)) {
548 width = wxMax(dx * 2, lwidth);
549 width = wxMin(width, dx * 30);
550 }
551 m_pListCtrlAISTargets->InsertColumn(tlTRK, _("Trk"), wxLIST_FORMAT_LEFT,
552 width);
553 s_width = tkz.GetNextToken();
554
555 width = dx * 12;
556 if (s_width.ToLong(&lwidth)) {
557 width = wxMax(dx * 2, lwidth);
558 width = wxMin(width, dx * 30);
559 }
560 m_pListCtrlAISTargets->InsertColumn(tlNAME, _("Name"), wxLIST_FORMAT_LEFT,
561 width);
562 s_width = tkz.GetNextToken();
563
564 width = dx * 7;
565 if (s_width.ToLong(&lwidth)) {
566 width = wxMax(dx * 2, lwidth);
567 width = wxMin(width, dx * 30);
568 }
569 m_pListCtrlAISTargets->InsertColumn(tlCALL, _("Call"), wxLIST_FORMAT_LEFT,
570 width);
571 s_width = tkz.GetNextToken();
572
573 width = dx * 10;
574 if (s_width.ToLong(&lwidth)) {
575 width = wxMax(dx * 2, lwidth);
576 width = wxMin(width, dx * 30);
577 }
578 m_pListCtrlAISTargets->InsertColumn(tlMMSI, _("MMSI"), wxLIST_FORMAT_LEFT,
579 width);
580 s_width = tkz.GetNextToken();
581
582 width = dx * 7;
583 if (s_width.ToLong(&lwidth)) {
584 width = wxMax(dx * 2, lwidth);
585 width = wxMin(width, dx * 30);
586 }
587 m_pListCtrlAISTargets->InsertColumn(tlCLASS, _("Class"), wxLIST_FORMAT_CENTER,
588 width);
589 s_width = tkz.GetNextToken();
590
591 width = dx * 10;
592 if (s_width.ToLong(&lwidth)) {
593 width = wxMax(dx * 2, lwidth);
594 width = wxMin(width, dx * 30);
595 }
596 m_pListCtrlAISTargets->InsertColumn(tlTYPE, _("Type"), wxLIST_FORMAT_LEFT,
597 width);
598 s_width = tkz.GetNextToken();
599
600 width = dx * 12;
601 if (s_width.ToLong(&lwidth)) {
602 width = wxMax(dx * 2, lwidth);
603 width = wxMin(width, dx * 30);
604 }
605 m_pListCtrlAISTargets->InsertColumn(tlNAVSTATUS, _("Flag"),
606 wxLIST_FORMAT_LEFT, width);
607 s_width = tkz.GetNextToken();
608
609 width = dx * 12;
610 if (s_width.ToLong(&lwidth)) {
611 width = wxMax(dx * 2, lwidth);
612 width = wxMin(width, dx * 30);
613 }
614 m_pListCtrlAISTargets->InsertColumn(tlNAVSTATUS, _("Nav Status"),
615 wxLIST_FORMAT_LEFT, width);
616 s_width = tkz.GetNextToken();
617
618 width = dx * 6;
619 if (s_width.ToLong(&lwidth)) {
620 width = wxMax(dx * 2, lwidth);
621 width = wxMin(width, dx * 30);
622 }
623 m_pListCtrlAISTargets->InsertColumn(tlBRG, _("Brg"), wxLIST_FORMAT_RIGHT,
624 width);
625 s_width = tkz.GetNextToken();
626
627 width = dx * 8;
628 if (s_width.ToLong(&lwidth)) {
629 width = wxMax(dx * 2, lwidth);
630 width = wxMin(width, dx * 30);
631 }
632 m_pListCtrlAISTargets->InsertColumn(tlRNG, _("Range"), wxLIST_FORMAT_RIGHT,
633 width);
634 s_width = tkz.GetNextToken();
635
636 width = dx * 6;
637 if (s_width.ToLong(&lwidth)) {
638 width = wxMax(dx * 2, lwidth);
639 width = wxMin(width, dx * 30);
640 }
641 m_pListCtrlAISTargets->InsertColumn(tlCOG, _("CoG"), wxLIST_FORMAT_RIGHT,
642 width);
643 s_width = tkz.GetNextToken();
644
645 width = dx * 6;
646 if (s_width.ToLong(&lwidth)) {
647 width = wxMax(dx * 2, lwidth);
648 width = wxMin(width, dx * 30);
649 }
650 m_pListCtrlAISTargets->InsertColumn(tlSOG, _("SoG"), wxLIST_FORMAT_RIGHT,
651 width);
652
653 width = dx * 7;
654 if (s_width.ToLong(&lwidth)) {
655 width = wxMax(dx * 2, lwidth);
656 width = wxMin(width, dx * 30);
657 }
658 m_pListCtrlAISTargets->InsertColumn(tlCPA, _("CPA"), wxLIST_FORMAT_RIGHT,
659 width);
660
661 width = dx * 8;
662 if (s_width.ToLong(&lwidth)) {
663 width = wxMax(dx * 2, lwidth);
664 width = wxMin(width, dx * 30);
665 }
666 m_pListCtrlAISTargets->InsertColumn(tlTCPA, _("TCPA"), wxLIST_FORMAT_RIGHT,
667 width);
668 wxListItem item;
669 item.SetMask(wxLIST_MASK_IMAGE);
670 item.SetImage(g_bAisTargetList_sortReverse ? 1 : 0);
671 g_AisTargetList_sortColumn = wxMax(g_AisTargetList_sortColumn, 0);
672 m_pListCtrlAISTargets->SetColumn(g_AisTargetList_sortColumn, item);
673
674#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
675 wxStringTokenizer tkz_order(g_AisTargetList_column_order, ";");
676 wxString s_order = tkz_order.GetNextToken();
677 int i_columns = m_pListCtrlAISTargets->GetColumnCount();
678 wxArrayInt a_order(i_columns);
679 for (int i = 0; i < i_columns; i++) {
680 long l_order = (long)i;
681 s_order.ToLong(&l_order);
682 if (l_order < 0 || l_order > i_columns) {
683 l_order = i;
684 }
685 a_order[i] = l_order;
686 s_order = tkz_order.GetNextToken();
687 }
688
689 m_pListCtrlAISTargets->SetColumnsOrder(a_order);
690#endif
691
692 topSizer->Add(m_pListCtrlAISTargets, 1, wxEXPAND | wxALL, 0);
693
694 wxBoxSizer *boxSizer02 = new wxBoxSizer(wxVERTICAL);
695 boxSizer02->AddSpacer(22);
696 topSizer->Add(boxSizer02, 0, wxEXPAND | wxALL, 2);
697
698 wxScrolledWindow *winr =
699 new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
700 wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL);
701 winr->SetScrollRate(0, 5);
702
703 boxSizer02->Add(winr, 1, wxALL | wxEXPAND, 3);
704
705 wxBoxSizer *bsRouteButtonsInner = new wxBoxSizer(wxVERTICAL);
706 winr->SetSizer(bsRouteButtonsInner);
707
708 m_pButtonInfo = new wxButton(winr, wxID_ANY, _("Target info"),
709 wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW);
710 m_pButtonInfo->Connect(
711 wxEVT_COMMAND_BUTTON_CLICKED,
712 wxCommandEventHandler(AISTargetListDialog::OnTargetQuery), NULL, this);
713 bsRouteButtonsInner->Add(m_pButtonInfo, 0, wxEXPAND | wxALL, 2);
714 bsRouteButtonsInner->AddSpacer(5);
715
716 m_pButtonJumpTo =
717 new wxButton(winr, wxID_ANY, _("Center view"), wxDefaultPosition,
718 wxDefaultSize, wxBU_AUTODRAW);
719 m_pButtonJumpTo->Connect(
720 wxEVT_COMMAND_BUTTON_CLICKED,
721 wxCommandEventHandler(AISTargetListDialog::OnTargetScrollTo), NULL, this);
722 bsRouteButtonsInner->Add(m_pButtonJumpTo, 0, wxEXPAND | wxALL, 2);
723
724 m_pButtonJumpTo_Close =
725 new wxButton(winr, wxID_ANY, _("Center-Info-Close"), wxDefaultPosition,
726 wxDefaultSize, wxBU_AUTODRAW);
727 m_pButtonJumpTo_Close->Connect(
728 wxEVT_COMMAND_BUTTON_CLICKED,
729 wxCommandEventHandler(AISTargetListDialog::OnTargetScrollToClose), NULL,
730 this);
731 bsRouteButtonsInner->Add(m_pButtonJumpTo_Close, 0, wxEXPAND | wxALL, 2);
732
733 m_pButtonCreateWpt =
734 new wxButton(winr, wxID_ANY, _("Create WPT"), wxDefaultPosition,
735 wxDefaultSize, wxBU_AUTODRAW);
736 m_pButtonCreateWpt->Connect(
737 wxEVT_COMMAND_BUTTON_CLICKED,
738 wxCommandEventHandler(AISTargetListDialog::OnTargetCreateWpt), NULL,
739 this);
740 bsRouteButtonsInner->Add(m_pButtonCreateWpt, 0, wxEXPAND | wxALL, 0);
741
742 m_pButtonHideAllTracks =
743 new wxButton(winr, wxID_ANY, _("Hide All Tracks"), wxDefaultPosition,
744 wxDefaultSize, wxBU_AUTODRAW);
745 m_pButtonHideAllTracks->Connect(
746 wxEVT_COMMAND_BUTTON_CLICKED,
747 wxCommandEventHandler(AISTargetListDialog::OnHideAllTracks), NULL, this);
748 bsRouteButtonsInner->Add(m_pButtonHideAllTracks, 0, wxEXPAND | wxALL, 2);
749
750 m_pButtonShowAllTracks =
751 new wxButton(winr, wxID_ANY, _("Show All Tracks"), wxDefaultPosition,
752 wxDefaultSize, wxBU_AUTODRAW);
753 m_pButtonShowAllTracks->Connect(
754 wxEVT_COMMAND_BUTTON_CLICKED,
755 wxCommandEventHandler(AISTargetListDialog::OnShowAllTracks), NULL, this);
756 bsRouteButtonsInner->Add(m_pButtonShowAllTracks, 0, wxEXPAND | wxALL, 2);
757
758 m_pButtonToggleTrack =
759 new wxButton(winr, wxID_ANY, _("Toggle track"), wxDefaultPosition,
760 wxDefaultSize, wxBU_AUTODRAW);
761 m_pButtonToggleTrack->Connect(
762 wxEVT_COMMAND_BUTTON_CLICKED,
763 wxCommandEventHandler(AISTargetListDialog::OnToggleTrack), NULL, this);
764 bsRouteButtonsInner->Add(m_pButtonToggleTrack, 0, wxEXPAND | wxALL, 2);
765
766 m_pButtonCopyMMSI =
767 new wxButton(winr, wxID_ANY, _("Copy MMSI"), wxDefaultPosition,
768 wxDefaultSize, wxBU_AUTODRAW);
769 m_pButtonCopyMMSI->Connect(
770 wxEVT_COMMAND_BUTTON_CLICKED,
771 wxCommandEventHandler(AISTargetListDialog::OnCopyMMSI), NULL, this);
772 bsRouteButtonsInner->Add(m_pButtonCopyMMSI, 0, wxEXPAND | wxALL, 2);
773
774 m_pStaticTextFind = new wxStaticText(winr, wxID_ANY, _("Find target name"),
775 wxDefaultPosition, wxDefaultSize, 0);
776 bsRouteButtonsInner->Add(m_pStaticTextFind, 0, wxALL, 2);
777
778 m_pFindTargetName =
779 new wxTextCtrl(winr, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0);
780 m_pFindTargetName->SetMinSize(wxSize(15 * GetCharWidth(), -1));
781 m_pFindTargetName->Connect(
782 wxEVT_COMMAND_TEXT_UPDATED,
783 wxCommandEventHandler(AISTargetListDialog::OnEditFindTarget), NULL, this);
784 bsRouteButtonsInner->Add(m_pFindTargetName, 0, wxALL, 2);
785
786 m_pCBAutosort =
787 new wxCheckBox(winr, wxID_ANY, _("AutoSort"), wxDefaultPosition,
788 wxDefaultSize, wxBU_AUTODRAW);
789 m_pCBAutosort->Connect(
790 wxEVT_COMMAND_CHECKBOX_CLICKED,
791 wxCommandEventHandler(AISTargetListDialog::OnAutosortCB), NULL, this);
792 bsRouteButtonsInner->Add(m_pCBAutosort, 0, wxEXPAND | wxALL, 2);
793 g_bAisTargetList_autosort = true;
794 m_pCBAutosort->SetValue(g_bAisTargetList_autosort);
795
796 bsRouteButtonsInner->AddSpacer(10);
797
798 m_pStaticTextRange = new wxStaticText(winr, wxID_ANY, _("Limit range: NM"),
799 wxDefaultPosition, wxDefaultSize, 0);
800 bsRouteButtonsInner->Add(m_pStaticTextRange, 0, wxALL, 2);
801 bsRouteButtonsInner->AddSpacer(2);
802 m_pSpinCtrlRange = new wxSpinCtrl(
803 winr, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(50, -1),
804 wxSP_ARROW_KEYS, 1, 20000, g_AisTargetList_range);
805 m_pSpinCtrlRange->Connect(
806 wxEVT_COMMAND_SPINCTRL_UPDATED,
807 wxCommandEventHandler(AISTargetListDialog::OnLimitRange), NULL, this);
808 m_pSpinCtrlRange->Connect(
809 wxEVT_COMMAND_TEXT_UPDATED,
810 wxCommandEventHandler(AISTargetListDialog::OnLimitRange), NULL, this);
811 bsRouteButtonsInner->Add(m_pSpinCtrlRange, 0, wxEXPAND | wxALL, 0);
812
813 bsRouteButtonsInner->AddSpacer(10);
814 m_pStaticTextCount = new wxStaticText(winr, wxID_ANY, _("Target Count"),
815 wxDefaultPosition, wxDefaultSize, 0);
816 bsRouteButtonsInner->Add(m_pStaticTextCount, 0, wxALL, 2);
817
818 bsRouteButtonsInner->AddSpacer(2);
819 m_pTextTargetCount = new wxTextCtrl(winr, wxID_ANY, "", wxDefaultPosition,
820 wxDefaultSize, wxTE_READONLY);
821 m_pTextTargetCount->SetMinSize(wxSize(6 * GetCharWidth(), -1));
822 bsRouteButtonsInner->Add(m_pTextTargetCount, 0, wxALL, 2);
823
824 bsRouteButtonsInner->AddSpacer(10);
825 m_pButtonOK = new wxButton(winr, wxID_ANY, _("Close"), wxDefaultPosition,
826 wxDefaultSize, wxBU_AUTODRAW);
827 m_pButtonOK->Connect(
828 wxEVT_COMMAND_BUTTON_CLICKED,
829 wxCommandEventHandler(AISTargetListDialog::OnCloseButton), NULL, this);
830 bsRouteButtonsInner->Add(m_pButtonOK, 0, wxEXPAND | wxALL, 0);
831
832 topSizer->Layout();
833
834 // This is silly, but seems to be required for __WXMSW__ build
835 // If not done, the SECOND invocation of AISTargetList fails to expand the
836 // list to the full wxSizer size....
837 SetSize(GetSize().x, GetSize().y - 1);
838}
839
840void AISTargetListDialog::OnClose(wxCloseEvent &event) {
841 Disconnect_decoder();
842 Hide();
843 g_pAISTargetList = NULL;
844}
845
846void AISTargetListDialog::Disconnect_decoder() { m_pdecoder = NULL; }
847
848void AISTargetListDialog::SetColorScheme() { DimeControl(this); }
849
850void AISTargetListDialog::OnPaneClose(wxAuiManagerEvent &event) {
851 if (event.pane->name == "AISTargetList") {
852 g_AisTargetList_perspective = m_pAuiManager->SavePaneInfo(*event.pane);
853 }
854 event.Skip();
855}
856
857void AISTargetListDialog::OnCloseButton(wxCommandEvent &event) { Shutdown(); }
858
859void AISTargetListDialog::Shutdown() {
860 if (m_pAuiManager) {
861 wxAuiPaneInfo pane = m_pAuiManager->GetPane(this);
862 g_AisTargetList_perspective = m_pAuiManager->SavePaneInfo(pane);
863 m_pAuiManager->DetachPane(this);
864 Disconnect_decoder();
865 pane.Show(false);
866 m_pAuiManager->Update();
867#ifdef __ANDROID__
868 GetParent()->Refresh(true);
869#endif
870 Destroy();
871 }
872}
873
874void AISTargetListDialog::UpdateButtons() {
875 long item = -1;
876 item = m_pListCtrlAISTargets->GetNextItem(item, wxLIST_NEXT_ALL,
877 wxLIST_STATE_SELECTED);
878 bool enable = (item != -1);
879
880 m_pButtonInfo->Enable(enable);
881
882 if (m_pdecoder && item != -1) {
883 auto pAISTargetSel =
884 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(item));
885 if (pAISTargetSel && (!pAISTargetSel->b_positionOnceValid)) enable = false;
886 }
887 m_pButtonJumpTo->Enable(enable);
888 m_pButtonJumpTo_Close->Enable(enable);
889 m_pButtonCreateWpt->Enable(enable);
890 m_pButtonToggleTrack->Enable(enable);
891 m_pButtonCopyMMSI->Enable(enable);
892}
893
894void AISTargetListDialog::OnTargetSelected(wxListEvent &event) {
895 UpdateButtons();
896}
897
898void AISTargetListDialog::DoTargetQuery(int mmsi) {
899 ShowAISTargetQueryDialog(m_pparent, mmsi);
900}
901
902/*
903 ** When an item is activated in AIS TArget List then opens the AIS Target Query
904 *Dialog
905 */
906void AISTargetListDialog::OnTargetDefaultAction(wxListEvent &event) {
907 long mmsi_no;
908 if ((mmsi_no = event.GetData())) DoTargetQuery(mmsi_no);
909}
910
911void AISTargetListDialog::OnTargetQuery(wxCommandEvent &event) {
912 long selItemID = -1;
913 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
914 wxLIST_STATE_SELECTED);
915 if (selItemID == -1) return;
916
917 if (m_pdecoder) {
918 auto pAISTarget =
919 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
920 if (pAISTarget) DoTargetQuery(pAISTarget->MMSI);
921 }
922}
923
924void AISTargetListDialog::OnAutosortCB(wxCommandEvent &event) {
925 g_bAisTargetList_autosort = m_pCBAutosort->GetValue();
926
927 m_bautosort_force = g_bAisTargetList_autosort;
928
929 if (!g_bAisTargetList_autosort) {
930 wxListItem item;
931 item.SetMask(wxLIST_MASK_IMAGE);
932 item.SetImage(-1);
933 g_AisTargetList_sortColumn = wxMax(g_AisTargetList_sortColumn, 0);
934 m_pListCtrlAISTargets->SetColumn(g_AisTargetList_sortColumn, item);
935 } else {
936 wxListItem item;
937 item.SetMask(wxLIST_MASK_IMAGE);
938 item.SetImage(g_bAisTargetList_sortReverse ? 1 : 0);
939
940 if (g_AisTargetList_sortColumn >= 0) {
941 m_pListCtrlAISTargets->SetColumn(g_AisTargetList_sortColumn, item);
942 UpdateAISTargetList();
943 }
944 }
945}
946
947void AISTargetListDialog::OnTargetListColumnClicked(wxListEvent &event) {
948 int key = event.GetColumn();
949 wxListItem item;
950 item.SetMask(wxLIST_MASK_IMAGE);
951 if (key == g_AisTargetList_sortColumn)
952 g_bAisTargetList_sortReverse = !g_bAisTargetList_sortReverse;
953 else {
954 item.SetImage(-1);
955 m_pListCtrlAISTargets->SetColumn(g_AisTargetList_sortColumn, item);
956 g_bAisTargetList_sortReverse = false;
957 g_AisTargetList_sortColumn = key;
958 }
959 item.SetImage(g_bAisTargetList_sortReverse ? 1 : 0);
960
961 if (!g_bAisTargetList_autosort) g_bsort_once = true;
962
963 if (g_AisTargetList_sortColumn >= 0) {
964 m_pListCtrlAISTargets->SetColumn(g_AisTargetList_sortColumn, item);
965 UpdateAISTargetList();
966 }
967}
968
969void AISTargetListDialog::OnTargetScrollTo(wxCommandEvent &event) {
970 CenterToTarget(false);
971}
972
973void AISTargetListDialog::OnTargetScrollToClose(wxCommandEvent &event) {
974 CenterToTarget(true);
975}
976
977void AISTargetListDialog::OnTargetCreateWpt(wxCommandEvent &event) {
978 long selItemID = -1;
979 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
980 wxLIST_STATE_SELECTED);
981 if (selItemID == -1) return;
982
983 std::shared_ptr<AisTargetData> pAISTarget = NULL;
984 if (m_pdecoder)
985 pAISTarget =
986 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
987
988 if (pAISTarget) {
989 RoutePoint *pWP =
990 new RoutePoint(pAISTarget->Lat, pAISTarget->Lon, g_default_wp_icon,
991 wxEmptyString, wxEmptyString);
992 pWP->m_bIsolatedMark = true; // This is an isolated mark
993 pSelect->AddSelectableRoutePoint(pAISTarget->Lat, pAISTarget->Lon, pWP);
994 // pConfig->AddNewWayPoint(pWP, -1); // use auto next num
995 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
996
997 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
998 pRouteManagerDialog->UpdateWptListCtrl();
999 gFrame->GetPrimaryCanvas()->undo->BeforeUndoableAction(
1000 Undo_CreateWaypoint, pWP, Undo_HasParent, NULL);
1001 gFrame->GetPrimaryCanvas()->undo->AfterUndoableAction(NULL);
1002 Refresh(false);
1003 }
1004}
1005
1006void AISTargetListDialog::OnShowAllTracks(wxCommandEvent &event) {
1007 if (m_pdecoder) {
1008 for (const auto &it : m_pdecoder->GetTargetList()) {
1009 auto pAISTarget = it.second;
1010 if (NULL != pAISTarget) {
1011 pAISTarget->b_show_track = true;
1012
1013 // Check for any persistently tracked target, force b_show_track_old ON
1014 std::map<int, Track *>::iterator it;
1015 it = g_pAIS->m_persistent_tracks.find(pAISTarget->MMSI);
1016 if (it != g_pAIS->m_persistent_tracks.end()) {
1017 pAISTarget->b_show_track_old = true;
1018 }
1019 }
1020 }
1021 UpdateAISTargetList();
1022 }
1023}
1024
1025void AISTargetListDialog::OnHideAllTracks(wxCommandEvent &event) {
1026 if (m_pdecoder) {
1027 for (const auto &it : m_pdecoder->GetTargetList()) {
1028 auto pAISTarget = it.second;
1029 if (NULL != pAISTarget) {
1030 pAISTarget->b_show_track = false;
1031
1032 // Check for any persistently tracked target, force b_show_track ON
1033 std::map<int, Track *>::iterator it;
1034 it = g_pAIS->m_persistent_tracks.find(pAISTarget->MMSI);
1035 if (it != g_pAIS->m_persistent_tracks.end()) {
1036 pAISTarget->b_show_track = true;
1037 pAISTarget->b_show_track_old = false;
1038 }
1039 }
1040 }
1041 UpdateAISTargetList();
1042 }
1043}
1044
1045void AISTargetListDialog::OnToggleTrack(wxCommandEvent &event) {
1046 long selItemID = -1;
1047 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1048 wxLIST_STATE_SELECTED);
1049 if (selItemID == -1) return;
1050
1051 std::shared_ptr<AisTargetData> pAISTarget = NULL;
1052 if (m_pdecoder)
1053 pAISTarget =
1054 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
1055
1056 if (pAISTarget) {
1057 pAISTarget->b_show_track_old =
1058 pAISTarget->b_show_track; // Store current state before toggling
1059 pAISTarget->b_show_track = !pAISTarget->b_show_track; // Toggle visibility
1060 UpdateAISTargetList();
1061 }
1062}
1063
1064void AISTargetListDialog::OnCopyMMSI(wxCommandEvent &event) {
1065 long selItemID = -1;
1066 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1067 wxLIST_STATE_SELECTED);
1068 if (selItemID == -1) return;
1069 CopyMMSItoClipBoard((int)m_pMMSI_array->Item(selItemID));
1070}
1071
1072void AISTargetListDialog::OnEditFindTarget(wxCommandEvent &event) {
1073 wxString name = m_pFindTargetName->GetValue().MakeUpper();
1074 if (name.size() < 2 || name == " ") return;
1075 if (m_pdecoder) {
1076 bool found = false;
1077 long item_sel = 0;
1078
1079 // Loop to find the exact match of the searched target name.
1080 for (const auto &it : m_pdecoder->GetTargetList()) {
1081 auto pAISTarget = it.second;
1082 if (NULL != pAISTarget) {
1083 wxString s = pAISTarget->GetFullName();
1084 if (name == s) {
1085 found = true;
1086 int selMMSI = pAISTarget->MMSI;
1087 if (selMMSI != -1) {
1088 // Loop the display list to find position for the MMSI
1089 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1090 if (m_pMMSI_array->Item(i) == selMMSI) {
1091 item_sel = i;
1092 break;
1093 }
1094 }
1095 }
1096 break;
1097 }
1098 }
1099 }
1100 if (!found) {
1101 // Loop again to find parts of the searched target name.
1102 for (const auto &it : m_pdecoder->GetTargetList()) {
1103 auto pAISTarget = it.second;
1104 if (NULL != pAISTarget) {
1105 wxString s = pAISTarget->GetFullName();
1106 if (s.Find(name) != wxNOT_FOUND) {
1107 found = true;
1108 int selMMSI = pAISTarget->MMSI;
1109 if (selMMSI != -1) {
1110 // Loop the display list to find position for the MMSI
1111 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1112 if (m_pMMSI_array->Item(i) == selMMSI) {
1113 item_sel = i;
1114 break;
1115 }
1116 }
1117 }
1118 break;
1119 }
1120 }
1121 }
1122 }
1123 if (found) {
1124 if (m_pMMSI_array->GetCount())
1125 m_pListCtrlAISTargets->SetItemState(
1126 item_sel, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1127 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1128
1129 m_pListCtrlAISTargets->EnsureVisible(item_sel);
1130 UpdateAISTargetList();
1131 }
1132 }
1133}
1134
1135void AISTargetListDialog::CenterToTarget(bool close) {
1136 long selItemID = -1;
1137 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1138 wxLIST_STATE_SELECTED);
1139 if (selItemID == -1) return;
1140
1141 std::shared_ptr<AisTargetData> pAISTarget = NULL;
1142 if (m_pdecoder)
1143 pAISTarget =
1144 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
1145
1146 if (pAISTarget) {
1147 double scale = gFrame->GetFocusCanvas()->GetVPScale();
1148 if (!close) {
1149 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), pAISTarget->Lat,
1150 pAISTarget->Lon, scale);
1151 } else {
1152 // Set a resonable (1:5000) chart scale to see the target.
1153 double factor = 1.;
1154 if (scale < 0.7) { // Don't zoom if already close.
1155 ChartCanvas *cc = gFrame->GetFocusCanvas();
1156 factor = cc->GetScaleValue() / 5000.0;
1157 }
1158 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), pAISTarget->Lat,
1159 pAISTarget->Lon, scale * factor);
1160 DoTargetQuery(pAISTarget->MMSI);
1161 // Close AIS target list
1162 Shutdown();
1163 }
1164 }
1165}
1166
1167void AISTargetListDialog::CopyMMSItoClipBoard(int mmsi) {
1168 // Write MMSI # as text to the clipboard
1169 if (wxTheClipboard->Open()) {
1170 wxTheClipboard->SetData(
1171 new wxTextDataObject(wxString::Format("%09d", mmsi)));
1172 wxTheClipboard->Close();
1173 }
1174}
1175void AISTargetListDialog::OnLimitRange(wxCommandEvent &event) {
1176 g_AisTargetList_range = m_pSpinCtrlRange->GetValue();
1177 UpdateAISTargetList();
1178}
1179
1180std::shared_ptr<AisTargetData> AISTargetListDialog::GetpTarget(
1181 unsigned int list_item) {
1182 if (m_pdecoder)
1183 return m_pdecoder->Get_Target_Data_From_MMSI(
1184 m_pMMSI_array->Item(list_item));
1185 else
1186 return NULL;
1187}
1188
1189void AISTargetListDialog::UpdateAISTargetList() {
1190 if (m_pListCtrlAISTargets && !m_pListCtrlAISTargets->IsVirtual())
1191 return UpdateNVAISTargetList();
1192
1193 if (m_pdecoder && m_pListCtrlAISTargets) {
1194 // Capture the MMSI of the curently selected list item
1195 long selItemID = -1;
1196 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1197 wxLIST_STATE_SELECTED);
1198
1199 int selMMSI = -1;
1200 if (selItemID != -1) selMMSI = m_pMMSI_array->Item(selItemID);
1201
1202 const auto &current_targets = m_pdecoder->GetTargetList();
1203 wxListItem item;
1204
1205 int index = 0;
1206 m_pMMSI_array->Clear();
1207
1208 for (auto it = current_targets.begin(); it != current_targets.end();
1209 ++it, ++index) {
1210 auto pAISTarget = it->second;
1211 item.SetId(index);
1212
1213 if (NULL != pAISTarget) {
1214 bool b_add = false;
1215 if ((pAISTarget->b_positionOnceValid) &&
1216 (pAISTarget->Range_NM <= g_AisTargetList_range))
1217 b_add = true;
1218 else if (!pAISTarget->b_positionOnceValid)
1219 b_add = true;
1220
1221 // Do not show any "lost" targets in the list.
1222 if (pAISTarget->b_lost) b_add = false;
1223
1224 if (b_add) {
1225 m_pMMSI_array->Add(pAISTarget->MMSI);
1226 }
1227 }
1228 }
1229
1230 g_bsort_once = false;
1231
1232 m_pListCtrlAISTargets->SetItemCount(m_pMMSI_array->GetCount());
1233
1234 g_AisTargetList_count = m_pMMSI_array->GetCount();
1235
1236 if ((g_AisTargetList_count > 1000) && !m_bautosort_force)
1237 g_bAisTargetList_autosort = false;
1238
1239 m_pCBAutosort->SetValue(g_bAisTargetList_autosort);
1240
1241 // Restore selected item
1242 long item_sel = 0;
1243 if ((selItemID != -1) && (selMMSI != -1)) {
1244 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1245 if (m_pMMSI_array->Item(i) == selMMSI) {
1246 item_sel = i;
1247 break;
1248 }
1249 }
1250 }
1251
1252 if (m_pMMSI_array->GetCount())
1253 m_pListCtrlAISTargets->SetItemState(
1254 item_sel, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1255 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1256 else
1257 m_pListCtrlAISTargets->DeleteAllItems();
1258
1259 wxString count;
1260 count.Printf("%lu", (unsigned long)m_pMMSI_array->GetCount());
1261 m_pTextTargetCount->ChangeValue(count);
1262
1263#ifdef __WXMSW__
1264 m_pListCtrlAISTargets->Refresh(false);
1265#endif
1266 }
1267}
1268
1269void AISTargetListDialog::UpdateNVAISTargetList() {
1270 if (m_pdecoder) {
1271 // Capture the MMSI of the curently selected list item
1272 long selItemID = -1;
1273 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1274 wxLIST_STATE_SELECTED);
1275
1276 int selMMSI = -1;
1277 if (selItemID != -1) selMMSI = m_pMMSI_array->Item(selItemID);
1278
1279 const auto &current_targets = m_pdecoder->GetTargetList();
1280 wxListItem item;
1281
1282 int index = 0;
1283 m_pMMSI_array->Clear();
1284
1285 for (auto it = current_targets.begin(); it != current_targets.end();
1286 ++it, ++index) {
1287 auto pAISTarget = it->second;
1288 item.SetId(index);
1289
1290 if (NULL != pAISTarget) {
1291 bool b_add = false;
1292 if ((pAISTarget->b_positionOnceValid) &&
1293 (pAISTarget->Range_NM <= g_AisTargetList_range))
1294 b_add = true;
1295 else if (!pAISTarget->b_positionOnceValid)
1296 b_add = true;
1297
1298 if (b_add) {
1299 m_pMMSI_array->Add(pAISTarget->MMSI);
1300 }
1301 }
1302 }
1303
1304 g_bsort_once = false;
1305
1306 g_AisTargetList_count = m_pMMSI_array->GetCount();
1307
1308 m_pListCtrlAISTargets->DeleteAllItems();
1309
1310 for (int i = 0; i < g_AisTargetList_count; i++) {
1311 wxListItem item;
1312 item.SetId(i);
1313 m_pListCtrlAISTargets->InsertItem(item);
1314 for (int j = 0; j < tlTCPA + 1; j++) {
1315 item.SetColumn(j);
1316 item.SetText(m_pListCtrlAISTargets->OnGetItemText(i, j));
1317 m_pListCtrlAISTargets->SetItem(item);
1318 }
1319 }
1320
1321 if ((g_AisTargetList_count > 1000) && !m_bautosort_force)
1322 g_bAisTargetList_autosort = false;
1323
1324 m_pCBAutosort->SetValue(g_bAisTargetList_autosort);
1325
1326 // Restore selected item
1327 long item_sel = 0;
1328 if ((selItemID != -1) && (selMMSI != -1)) {
1329 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1330 if (m_pMMSI_array->Item(i) == selMMSI) {
1331 item_sel = i;
1332 break;
1333 }
1334 }
1335 }
1336
1337 if (m_pMMSI_array->GetCount())
1338 m_pListCtrlAISTargets->SetItemState(
1339 item_sel, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1340 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1341 else
1342 m_pListCtrlAISTargets->DeleteAllItems();
1343
1344 wxString count;
1345 count.Printf("%lu", (unsigned long)m_pMMSI_array->GetCount());
1346 m_pTextTargetCount->ChangeValue(count);
1347
1348#ifdef __WXMSW__
1349 m_pListCtrlAISTargets->Refresh(false);
1350#endif
1351 }
1352}
1353
1354void AISTargetListDialog::OnRightClickContext(wxCommandEvent &event) {
1355 wxAuiPaneInfo &pane = m_pAuiManager->GetPane("AISTargetList");
1356 if (pane.IsDocked()) {
1357 wxMenu *popup = new wxMenu();
1358 popup->Append(ID_RCLK_UNDOCK, _("Undock Target List"));
1359 popup->Connect(wxEVT_COMMAND_MENU_SELECTED,
1360 wxCommandEventHandler(AISTargetListDialog::OnContextUndock),
1361 NULL, this);
1362
1363 PopupMenu(popup);
1364 delete popup;
1365 }
1366}
1367
1368void AISTargetListDialog::OnContextUndock(wxCommandEvent &event) {
1369 wxAuiPaneInfo &pane = m_pAuiManager->GetPane("AISTargetList");
1370 pane.Float();
1371 m_pAuiManager->Update();
1372}
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
AIS target definitions.
Class AISTargetListDialog.
AISTargetListDialog * g_pAISTargetList
Global instance.
Generic Chart canvas base.
Dialog for displaying a list of AIS targets.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:472
Main application frame.
Definition ocpn_frame.h:139
A custom list control for displaying AIS target information.
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.
Platform independent GL includes.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:61
MySQL based storage for routes, tracks, etc.
OpenCPN top window.
AIS info display component.
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.
Chart Symbols.