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 }
999 UpdateAISTargetList();
1000 }
1001}
1002
1003void AISTargetListDialog::OnHideAllTracks(wxCommandEvent &event) {
1004 if (m_pdecoder) {
1005 for (const auto &it : m_pdecoder->GetTargetList()) {
1006 auto pAISTarget = it.second;
1007 if (NULL != pAISTarget) {
1008 pAISTarget->b_show_track = false;
1009
1010 // Check for any persistently tracked target, force b_show_track ON
1011 std::map<int, Track *>::iterator it;
1012 it = g_pAIS->m_persistent_tracks.find(pAISTarget->MMSI);
1013 if (it != g_pAIS->m_persistent_tracks.end())
1014 pAISTarget->b_show_track = true;
1015 }
1016 }
1017 UpdateAISTargetList();
1018 }
1019}
1020
1021void AISTargetListDialog::OnToggleTrack(wxCommandEvent &event) {
1022 long selItemID = -1;
1023 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1024 wxLIST_STATE_SELECTED);
1025 if (selItemID == -1) return;
1026
1027 std::shared_ptr<AisTargetData> pAISTarget = NULL;
1028 if (m_pdecoder)
1029 pAISTarget =
1030 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
1031
1032 if (pAISTarget) {
1033 pAISTarget->b_show_track = !pAISTarget->b_show_track;
1034 UpdateAISTargetList();
1035 }
1036}
1037
1038void AISTargetListDialog::OnCopyMMSI(wxCommandEvent &event) {
1039 long selItemID = -1;
1040 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1041 wxLIST_STATE_SELECTED);
1042 if (selItemID == -1) return;
1043 CopyMMSItoClipBoard((int)m_pMMSI_array->Item(selItemID));
1044}
1045
1046void AISTargetListDialog::CenterToTarget(bool close) {
1047 long selItemID = -1;
1048 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1049 wxLIST_STATE_SELECTED);
1050 if (selItemID == -1) return;
1051
1052 std::shared_ptr<AisTargetData> pAISTarget = NULL;
1053 if (m_pdecoder)
1054 pAISTarget =
1055 m_pdecoder->Get_Target_Data_From_MMSI(m_pMMSI_array->Item(selItemID));
1056
1057 if (pAISTarget) {
1058 double scale = gFrame->GetFocusCanvas()->GetVPScale();
1059 if (!close) {
1060 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), pAISTarget->Lat,
1061 pAISTarget->Lon, scale);
1062 } else {
1063 // Set a resonable (1:5000) chart scale to see the target.
1064 if (scale < 0.7) { // Don't zoom if already close.
1065 ChartCanvas *cc = gFrame->GetFocusCanvas();
1066 double factor = cc->GetScaleValue() / 5000.0;
1067 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), pAISTarget->Lat,
1068 pAISTarget->Lon, scale * factor);
1069 }
1070 DoTargetQuery(pAISTarget->MMSI);
1071 // Close AIS target list
1072 Shutdown();
1073 }
1074 }
1075}
1076
1077void AISTargetListDialog::CopyMMSItoClipBoard(int mmsi) {
1078 // Write MMSI # as text to the clipboard
1079 if (wxTheClipboard->Open()) {
1080 wxTheClipboard->SetData(
1081 new wxTextDataObject(wxString::Format(wxT("%09d"), mmsi)));
1082 wxTheClipboard->Close();
1083 }
1084}
1085void AISTargetListDialog::OnLimitRange(wxCommandEvent &event) {
1086 g_AisTargetList_range = m_pSpinCtrlRange->GetValue();
1087 UpdateAISTargetList();
1088}
1089
1090std::shared_ptr<AisTargetData> AISTargetListDialog::GetpTarget(
1091 unsigned int list_item) {
1092 if (m_pdecoder)
1093 return m_pdecoder->Get_Target_Data_From_MMSI(
1094 m_pMMSI_array->Item(list_item));
1095 else
1096 return NULL;
1097}
1098
1099void AISTargetListDialog::UpdateAISTargetList(void) {
1100 if (m_pListCtrlAISTargets && !m_pListCtrlAISTargets->IsVirtual())
1101 return UpdateNVAISTargetList();
1102
1103 if (m_pdecoder && m_pListCtrlAISTargets) {
1104 // Capture the MMSI of the curently selected list item
1105 long selItemID = -1;
1106 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1107 wxLIST_STATE_SELECTED);
1108
1109 int selMMSI = -1;
1110 if (selItemID != -1) selMMSI = m_pMMSI_array->Item(selItemID);
1111
1112 const auto &current_targets = m_pdecoder->GetTargetList();
1113 wxListItem item;
1114
1115 int index = 0;
1116 m_pMMSI_array->Clear();
1117
1118 for (auto it = current_targets.begin(); it != current_targets.end();
1119 ++it, ++index) {
1120 auto pAISTarget = it->second;
1121 item.SetId(index);
1122
1123 if (NULL != pAISTarget) {
1124 bool b_add = false;
1125 if ((pAISTarget->b_positionOnceValid) &&
1126 (pAISTarget->Range_NM <= g_AisTargetList_range))
1127 b_add = true;
1128 else if (!pAISTarget->b_positionOnceValid)
1129 b_add = true;
1130
1131 // Do not show any "lost" targets in the list.
1132 if (pAISTarget->b_lost) b_add = false;
1133
1134 if (b_add) {
1135 m_pMMSI_array->Add(pAISTarget->MMSI);
1136 }
1137 }
1138 }
1139
1140 g_bsort_once = false;
1141
1142 m_pListCtrlAISTargets->SetItemCount(m_pMMSI_array->GetCount());
1143
1144 g_AisTargetList_count = m_pMMSI_array->GetCount();
1145
1146 if ((g_AisTargetList_count > 1000) && !m_bautosort_force)
1147 g_bAisTargetList_autosort = false;
1148
1149 m_pCBAutosort->SetValue(g_bAisTargetList_autosort);
1150
1151 // Restore selected item
1152 long item_sel = 0;
1153 if ((selItemID != -1) && (selMMSI != -1)) {
1154 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1155 if (m_pMMSI_array->Item(i) == selMMSI) {
1156 item_sel = i;
1157 break;
1158 }
1159 }
1160 }
1161
1162 if (m_pMMSI_array->GetCount())
1163 m_pListCtrlAISTargets->SetItemState(
1164 item_sel, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1165 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1166 else
1167 m_pListCtrlAISTargets->DeleteAllItems();
1168
1169 wxString count;
1170 count.Printf(_T("%lu"), (unsigned long)m_pMMSI_array->GetCount());
1171 m_pTextTargetCount->ChangeValue(count);
1172
1173#ifdef __WXMSW__
1174 m_pListCtrlAISTargets->Refresh(false);
1175#endif
1176 }
1177}
1178
1179void AISTargetListDialog::UpdateNVAISTargetList(void) {
1180 if (m_pdecoder) {
1181 // Capture the MMSI of the curently selected list item
1182 long selItemID = -1;
1183 selItemID = m_pListCtrlAISTargets->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1184 wxLIST_STATE_SELECTED);
1185
1186 int selMMSI = -1;
1187 if (selItemID != -1) selMMSI = m_pMMSI_array->Item(selItemID);
1188
1189 const auto &current_targets = m_pdecoder->GetTargetList();
1190 wxListItem item;
1191
1192 int index = 0;
1193 m_pMMSI_array->Clear();
1194
1195 for (auto it = current_targets.begin(); it != current_targets.end();
1196 ++it, ++index) {
1197 auto pAISTarget = it->second;
1198 item.SetId(index);
1199
1200 if (NULL != pAISTarget) {
1201 bool b_add = false;
1202 if ((pAISTarget->b_positionOnceValid) &&
1203 (pAISTarget->Range_NM <= g_AisTargetList_range))
1204 b_add = true;
1205 else if (!pAISTarget->b_positionOnceValid)
1206 b_add = true;
1207
1208 if (b_add) {
1209 m_pMMSI_array->Add(pAISTarget->MMSI);
1210 }
1211 }
1212 }
1213
1214 g_bsort_once = false;
1215
1216 g_AisTargetList_count = m_pMMSI_array->GetCount();
1217
1218 m_pListCtrlAISTargets->DeleteAllItems();
1219
1220 for (int i = 0; i < g_AisTargetList_count; i++) {
1221 wxListItem item;
1222 item.SetId(i);
1223 m_pListCtrlAISTargets->InsertItem(item);
1224 for (int j = 0; j < tlTCPA + 1; j++) {
1225 item.SetColumn(j);
1226 item.SetText(m_pListCtrlAISTargets->OnGetItemText(i, j));
1227 m_pListCtrlAISTargets->SetItem(item);
1228 }
1229 }
1230
1231 if ((g_AisTargetList_count > 1000) && !m_bautosort_force)
1232 g_bAisTargetList_autosort = false;
1233
1234 m_pCBAutosort->SetValue(g_bAisTargetList_autosort);
1235
1236 // Restore selected item
1237 long item_sel = 0;
1238 if ((selItemID != -1) && (selMMSI != -1)) {
1239 for (unsigned int i = 0; i < m_pMMSI_array->GetCount(); i++) {
1240 if (m_pMMSI_array->Item(i) == selMMSI) {
1241 item_sel = i;
1242 break;
1243 }
1244 }
1245 }
1246
1247 if (m_pMMSI_array->GetCount())
1248 m_pListCtrlAISTargets->SetItemState(
1249 item_sel, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1250 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1251 else
1252 m_pListCtrlAISTargets->DeleteAllItems();
1253
1254 wxString count;
1255 count.Printf(_T("%lu"), (unsigned long)m_pMMSI_array->GetCount());
1256 m_pTextTargetCount->ChangeValue(count);
1257
1258#ifdef __WXMSW__
1259 m_pListCtrlAISTargets->Refresh(false);
1260#endif
1261 }
1262}
1263
1264void AISTargetListDialog::OnRightClickContext(wxCommandEvent &event) {
1265 wxAuiPaneInfo &pane = m_pAuiManager->GetPane(_T("AISTargetList"));
1266 if (pane.IsDocked()) {
1267 wxMenu *popup = new wxMenu();
1268 popup->Append(ID_RCLK_UNDOCK, _("Undock Target List"));
1269 popup->Connect(wxEVT_COMMAND_MENU_SELECTED,
1270 wxCommandEventHandler(AISTargetListDialog::OnContextUndock),
1271 NULL, this);
1272
1273 PopupMenu(popup);
1274 delete popup;
1275 }
1276}
1277
1278void AISTargetListDialog::OnContextUndock(wxCommandEvent &event) {
1279 wxAuiPaneInfo &pane = m_pAuiManager->GetPane(_T("AISTargetList"));
1280 pane.Float();
1281 m_pAuiManager->Update();
1282}
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:151
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:54
Class NavObj_dB.