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