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