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