OpenCPN Partial API docs
Loading...
Searching...
No Matches
filter_dlg.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2025 Alec Leamas *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
23#include <functional>
24#include <memory>
25#include <string>
26
27#include <wx/app.h>
28#include <wx/arrstr.h>
29#include <wx/button.h>
30#include <wx/checkbox.h>
31#include <wx/checklst.h>
32#include <wx/choicdlg.h>
33#include <wx/frame.h>
34#include <wx/log.h>
35#include <wx/msgdlg.h>
36#include <wx/panel.h>
37#include <wx/radiobox.h>
38#include <wx/radiobut.h>
39#include <wx/sizer.h>
40#include <wx/statline.h>
41#include <wx/stattext.h>
42#include <wx/textdlg.h>
43#include <wx/wrapsizer.h>
44
45#ifndef ocpnUSE_wxBitmapBundle
46#include <wx/sstream.h>
47#include <wxSVG/svg.h>
48#endif
49
53#include "filter_dlg.h"
54#include "std_filesystem.h"
55#include "svg_icons.h"
56#include "edit_button.h"
57
58// Make _() return const char* instead of wxString;
59#undef _
60#if wxCHECK_VERSION(3, 2, 0)
61#define _(s) wxGetTranslation(wxASCII_STR(s)).ToStdString().c_str()
62#else
63#define _(s) wxGetTranslation((s)).ToStdString().c_str()
64#endif
65
66static const std::string kEditFilterFrameName("EditFilterFrame::");
67
68static const char* const kFilterExists =
69 R"( Filter already exists. Please use Edit to update
70or Remove to delete it prior to create.)";
71
72static const std::unordered_map<NavmsgStatus::Direction, std::string>
73 kStringByDirection = {{NavmsgStatus::Direction::kInput, "Input"},
74 {NavmsgStatus::Direction::kHandled, "Handled"},
75 {NavmsgStatus::Direction::kOutput, "Output"},
76 {NavmsgStatus::Direction::kInternal, "Internal"}};
77
79template <typename T>
80T* GetWindowById(int id) {
81 return dynamic_cast<T*>(wxWindow::FindWindowById(id));
82};
83
84static NavmsgStatus::Direction StringToDirection(const std::string& s) {
85 for (const auto& it : kStringByDirection)
86 if (it.second == s) return it.first;
87 return NavmsgStatus::Direction::kNone;
88}
89
90static wxArrayString GetUserFilters() {
91 auto std_filters = filters_on_disk::List(false);
92 wxArrayString wx_filters;
93 for (auto& f : std_filters) wx_filters.Add(f);
94 return wx_filters;
95}
96
98static std::vector<std::string> GetActiveMessages() {
99 auto v = NavMsgBus::GetInstance().GetActiveMessages();
100 std::vector<std::string> result;
101 for (const auto& m : NavMsgBus::GetInstance().GetActiveMessages()) {
102 size_t pos = m.find("::");
103 if (pos == std::string::npos) {
104 result.push_back(m);
105 } else {
106 result.push_back(m.substr(pos + 2));
107 }
108 }
109 return result;
110}
111
112class NewFilterDlg : public wxTextEntryDialog {
113public:
114 NewFilterDlg(wxWindow*)
115 : wxTextEntryDialog(wxTheApp->GetTopWindow(), _("New filter name")) {}
116};
117
118class DeleteFilterDlg : public wxSingleChoiceDialog {
119public:
120 DeleteFilterDlg(wxWindow*)
121 : wxSingleChoiceDialog(wxTheApp->GetTopWindow(),
122 _("Remove filter (name):"), _("Remove filter"),
123 GetUserFilters()) {}
124};
125
126class SelectFilterDlg : public wxSingleChoiceDialog {
127public:
128 SelectFilterDlg(wxWindow*)
129 : wxSingleChoiceDialog(wxTheApp->GetTopWindow(), _("Edit filter (name):"),
130 _("Edit filter"), GetUserFilters()) {}
131};
132
133class BadFilterNameDlg : public wxMessageDialog {
134public:
135 BadFilterNameDlg(wxWindow* parent)
136 : wxMessageDialog(parent, _(kFilterExists)) {}
137};
138
143class MsgTypePanel : public wxPanel {
144public:
145 MsgTypePanel(wxWindow* parent, NavmsgFilter& filter,
146 std::function<void()> on_update)
147 : wxPanel(parent, wxID_ANY),
148 m_filter(filter),
149 m_on_update(std::move(on_update)),
150 kIncludeBtnId(wxWindow::NewControlId()),
151 kExcludeBtnId(wxWindow::NewControlId()),
152 kEditBtnId(wxWindow::NewControlId()),
153 kListboxId(wxWindow::NewControlId()),
154 kSummaryId(wxWindow::NewControlId()),
155 kSetBtnId(wxWindow::NewControlId()),
156 kClearBtnId(wxWindow::NewControlId()) {
157 auto flags = wxSizerFlags(0).Border();
158 auto vbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Message Types"));
159 auto hbox = new wxBoxSizer(wxHORIZONTAL);
160
161 auto radiobox = new wxBoxSizer(wxVERTICAL);
162 radiobox->Add(new wxRadioButton(this, kIncludeBtnId, _("Include messages"),
163 wxDefaultPosition, wxDefaultSize,
164 wxRB_GROUP));
165 radiobox->Add(
166 new wxRadioButton(this, kExcludeBtnId, _("Exclude messages")));
167 radiobox->Add(1, 1, 1); // Expanding space, align buttons to bottom
168 radiobox->Add(new wxButton(this, kSetBtnId, _("Check all")), flags);
169 radiobox->Add(new wxButton(this, kClearBtnId, _("Clear all")), flags);
170 hbox->Add(radiobox, flags.Expand());
171
172 hbox->Add(1, 1, 1); // Expanding space, keep button/summary right aligned
173 wxArrayString choices;
174 auto msg_types = GetActiveMessages();
175 for (const auto& msg_type : msg_types) choices.Add(msg_type);
176 auto listbox = new wxCheckListBox(this, kListboxId, wxDefaultPosition,
177 wxDefaultSize, choices, 1);
178 hbox->Add(new wxStaticText(this, kSummaryId, ""), flags);
179 hbox->Add(listbox, flags);
180
181 auto edit_box = new wxBoxSizer(wxVERTICAL);
182 auto edit_btn = new EditButton(this, kEditBtnId, [&] { OnEditClick(); });
183 edit_box->Add(edit_btn, wxSizerFlags());
184 hbox->Add(edit_box, flags.Expand());
185
186 wxWindow* btn = GetWindowById<wxWindow>(kSetBtnId);
187 btn->Hide();
188 btn->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { SetAllItems(true); });
189 btn = GetWindowById<wxWindow>(kClearBtnId);
190 btn->Hide();
191 btn->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { SetAllItems(false); });
192
193 vbox->Add(hbox, flags.Expand());
194 SetSizer(vbox);
195 ImportFromFilter();
196 listbox->Hide();
197 GetWindowById<wxStaticText>(kSummaryId)->SetLabel(GetSummary());
198 Fit();
199
200 listbox->Bind(wxEVT_CHECKLISTBOX,
201 [&](wxCommandEvent& ev) { OnItemCheck(ev.GetInt()); });
202 }
203
204private:
205 std::string GetListboxItem(wxCheckListBox* listbox, unsigned i) const {
206 return listbox->GetString(i).ToStdString();
207 }
208
209 void SetAllItems(bool value) {
210 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
211 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
212 listbox->Check(i, value);
213 }
214 ExportToFilter();
215 }
216
217 std::string GetSummary() {
218 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
219
220 if (m_filter.exclude_msg.empty() && m_filter.include_msg.empty())
221 return _("All");
222 bool excluded = !m_filter.exclude_msg.empty();
223 size_t checked =
224 excluded ? m_filter.exclude_msg.size() : m_filter.include_msg.size();
225 size_t all = listbox->GetCount();
226 if (all == checked) return _("All");
227
228 std::stringstream ss;
229 ss << "[" << checked << _(" of ") << all << "]";
230 return ss.str();
231 }
232
237 void OnEditClick() {
238 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
239 auto summary = GetWindowById<wxStaticText>(kSummaryId);
240 auto edit_button = GetWindowById<EditButton>(kEditBtnId);
241 bool is_editing = listbox->IsShown();
242 listbox->Show(!is_editing);
243 summary->Show(is_editing);
244 summary->SetLabel(GetSummary());
245 edit_button->SetIcon(!is_editing);
246 GetWindowById<wxWindow>(kSetBtnId)->Show(!is_editing);
247 GetWindowById<wxWindow>(kClearBtnId)->Show(!is_editing);
248 GetParent()->Fit();
249 ExportToFilter();
250 }
251
256 void OnItemCheck(int ix) {
257 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
258 int checked = 0;
259 for (unsigned i = 0; i < listbox->GetCount(); i += 1)
260 if (listbox->IsChecked(i)) checked += 1;
261 if (checked == 0) {
262 // Refuse to create a filter with no interfaces.
263 listbox->Check(ix);
264 return;
265 }
266 ExportToFilter();
267 }
268
270 void ImportFromFilter() {
271 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
272 auto exclude_btn = GetWindowById<wxRadioButton>(kExcludeBtnId);
273 auto include_btn = GetWindowById<wxRadioButton>(kIncludeBtnId);
274
275 exclude_btn->SetValue(m_filter.exclude_msg.size() > 0);
276 if (include_btn->GetValue()) {
277 if (m_filter.include_msg.empty()) {
278 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
279 } else {
280 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
281 std::string item = GetListboxItem(listbox, i);
282 if (m_filter.include_msg.count(item)) listbox->Check(i);
283 }
284 }
285 } else {
286 if (m_filter.exclude_msg.empty()) {
287 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
288 } else {
289 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
290 std::string item = GetListboxItem(listbox, i);
291 if (m_filter.exclude_msg.count(item)) listbox->Check(i);
292 }
293 }
294 }
295 }
296
298 void ExportToFilter() {
299 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
300 auto include_btn = GetWindowById<wxRadioButton>(kIncludeBtnId);
301 m_filter.include_msg.clear();
302 m_filter.exclude_msg.clear();
303 auto& the_set =
304 include_btn->GetValue() ? m_filter.include_msg : m_filter.exclude_msg;
305 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
306 if (!listbox->IsChecked(i)) continue;
307 std::string item = GetListboxItem(listbox, i);
308 the_set.insert(item);
309 }
310 if (the_set.size() == listbox->GetCount()) {
311 m_filter.include_msg.clear();
312 m_filter.exclude_msg.clear();
313 }
314 m_on_update();
315 }
316
317 NavmsgFilter& m_filter;
318 std::function<void()> m_on_update;
319 const int kIncludeBtnId;
320 const int kExcludeBtnId;
321 const int kEditBtnId;
322 const int kListboxId;
323 const int kSummaryId;
324 const int kSetBtnId;
325 const int kClearBtnId;
326};
327
336template <typename T>
337class SetPanel : public wxPanel {
338public:
339 SetPanel(wxWindow* parent, std::set<T>& set, std::function<void()> on_update,
340 const std::string& label, std::function<wxArrayString()> get_choices)
341 : wxPanel(),
342 m_set(set),
343 m_on_update(std::move(on_update)),
344 kEditBtnId(wxWindow::NewControlId()),
345 kListboxId(wxWindow::NewControlId()),
346 kListLabelId(wxWindow::NewControlId()) {
347 wxPanel::Create(parent, wxID_ANY);
348 auto flags = wxSizerFlags(0).Border();
349 auto vbox = new wxBoxSizer(wxVERTICAL);
350 auto hbox = new wxBoxSizer(wxHORIZONTAL);
351 hbox->Add(new wxStaticText(this, wxID_ANY, label), flags);
352
353 // Pre-compute required size of wxCheckListBox
354 // to avoid sizer errors on MacOS
355 wxArrayString array = get_choices();
356 int max_char = 0;
357 for (auto string : array) max_char = wxMax(max_char, string.Length());
358 int hsize = (max_char + 8) * wxWindow::GetCharWidth();
359
360 hbox->Add(1, 1, 1);
361 auto listbox = new wxCheckListBox(this, kListboxId, wxDefaultPosition,
362 wxSize(hsize, -1), get_choices());
363 hbox->Add(listbox, flags);
364 auto list_label = new wxStaticText(this, kListLabelId, "");
365 hbox->Add(list_label, flags);
366 auto edit_btn = new EditButton(this, kEditBtnId, [&] { OnEditClick(); });
367 hbox->Add(edit_btn, flags);
368 vbox->Add(hbox, flags.Expand());
369 SetSizer(vbox);
370
371 ImportFromFilter();
372 list_label->SetLabel(GetListLabel());
373
374 listbox->Hide();
375 list_label->Show();
376
377 // Execute a round-trip of OnEditClick() to force MacOS sizers to populate
378 // the listbox.
379 OnEditClick();
380 Layout();
381 OnEditClick();
382
383 listbox->Bind(wxEVT_CHECKLISTBOX,
384 [&](wxCommandEvent& ev) { OnItemCheck(ev.GetInt()); });
385 }
386
387private:
389 T GetListboxItem(wxCheckListBox* listbox, unsigned i) const {
390 if constexpr (std::is_same<T, std::string>::value)
391 return listbox->GetString(i).ToStdString();
392 else if constexpr (std::is_same<T, NavAddr::Bus>::value)
393 return NavAddr::StringToBus(listbox->GetString(i).ToStdString());
394 else if constexpr (std::is_same<T, NavmsgStatus::Direction>::value)
395 return StringToDirection(listbox->GetString(i).ToStdString());
396 else if constexpr (std::is_same<T, NavmsgStatus::Accepted>::value)
398 listbox->GetString(i).ToStdString());
399 else
400 assert(false && "bad type...");
401 }
402
404 std::string GetListLabel() {
405 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
406 if (m_set.empty() || m_set.size() == listbox->GetCount()) return _("All");
407 std::stringstream ss;
408 ss << "[" << m_set.size() << _(" of ") << listbox->GetCount() << "]";
409 return ss.str();
410 }
411
416 void OnEditClick() {
417 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
418 listbox->Layout();
419 auto list_label = GetWindowById<wxStaticText>(kListLabelId);
420 auto edit_button = GetWindowById<EditButton>(kEditBtnId);
421 bool is_editing = listbox->IsShown();
422 listbox->Show(!is_editing);
423 list_label->Show(is_editing);
424 list_label->SetLabel(GetListLabel());
425 edit_button->SetIcon(!is_editing);
426 GetParent()->Fit();
427 }
428
433 void OnItemCheck(int ix) {
434 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
435 auto list_label = GetWindowById<wxStaticText>(kListLabelId);
436 int checked = 0;
437 for (unsigned i = 0; i < listbox->GetCount(); i += 1)
438 if (listbox->IsChecked(i)) checked += 1;
439 if (checked == 0) {
440 listbox->Check(ix);
441 return;
442 }
443 list_label->SetLabel(GetListLabel());
444 ExportToFilter();
445 }
446
448 void ImportFromFilter() {
449 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
450 if (m_set.empty()) {
451 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
452 } else {
453 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
454 T item = GetListboxItem(listbox, i);
455 if (m_set.count(item) > 0) listbox->Check(i);
456 }
457 }
458 }
459
461 void ExportToFilter() {
462 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
463 m_set.clear();
464 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
465 if (!listbox->IsChecked(i)) continue;
466 T item = GetListboxItem(listbox, i);
467 m_set.insert(item);
468 }
469 if (m_set.size() == listbox->GetCount()) m_set.clear();
470 m_on_update();
471 }
472
473 std::set<T>& m_set;
474 std::function<void()> m_on_update;
475 const int kEditBtnId;
476 const int kListboxId;
477 const int kListLabelId;
478};
479
481class IfacePanel : public SetPanel<std::string> {
482public:
483 IfacePanel(wxWindow* parent, NavmsgFilter& filter,
484 std::function<void()> on_update)
485 : SetPanel<std::string>(parent, filter.interfaces, std::move(on_update),
486 _("Use interfaces"),
487 [&]() { return IfacePanel::GetChoices(); }) {}
488
489private:
490 wxArrayString GetChoices() const {
491 wxArrayString choices;
492 for (auto& driver : CommDriverRegistry::GetInstance().GetDrivers())
493 choices.Add(driver->iface);
494 choices.Add("Internal");
495 return choices;
496 }
497};
498
503class BusPanel : public SetPanel<NavAddr::Bus> {
504public:
505 BusPanel(wxWindow* parent, NavmsgFilter& filter,
506 std::function<void()> on_update)
507 : SetPanel<NavAddr::Bus>(parent, filter.buses, std::move(on_update),
508 _("Use message buses"),
509 [&]() { return BusPanel::GetChoices(); }) {}
510
511private:
512 wxArrayString GetChoices() const {
513 static const char* choices[] = {"nmea0183", "nmea2000", "SignalK", "Onenet",
514 "Plugin"};
515 return {5, choices};
516 }
517};
518
523class DirectionPanel : public SetPanel<NavmsgStatus::Direction> {
524public:
525 DirectionPanel(wxWindow* parent, NavmsgFilter& filter,
526 std::function<void()> on_update)
528 parent, filter.directions, std::move(on_update),
529 _("Use directions"), [&] { return DirectionPanel::GetChoices(); }) {
530 }
531
532private:
533 wxArrayString GetChoices() const {
534 static const char* choices[] = {"Input", "Handled", "Output", "Internal"};
535 return {4, choices};
536 }
537};
538
539class AcceptedPanel : public SetPanel<NavmsgStatus::Accepted> {
540public:
541 AcceptedPanel(wxWindow* parent, NavmsgFilter& filter,
542 std::function<void()> on_update)
544 parent, filter.accepted, std::move(on_update),
545 _("Use Accepted states"),
546 [&]() { return AcceptedPanel::GetChoices(); }) {}
547
548private:
549 wxArrayString GetChoices() const {
550 static const char* choices[] = {"Ok", "FilteredNoOutput",
551 "FilteredDropped"};
552 return {3, choices};
553 }
554};
555
556class EditFilterFrame : public wxFrame {
557 class Buttons : public wxPanel {
558 public:
559 Buttons(wxWindow* parent) : wxPanel(parent, wxID_ANY) {
560 auto vbox = new wxBoxSizer(wxVERTICAL);
561 auto buttons = new wxStdDialogButtonSizer();
562 buttons->AddButton(new wxButton(this, wxID_CLOSE));
563 buttons->AddButton(new wxButton(this, wxID_APPLY));
564 vbox->Add(buttons, wxSizerFlags().Expand());
565 buttons->Realize();
566 SetSizer(vbox);
567 Layout();
568 }
569 };
570
571public:
572 EditFilterFrame(wxWindow* parent, const std::string& name,
573 std::function<void(const std::string&)> on_update,
574 std::function<void(const std::string&)> on_apply)
575 : wxFrame(parent, wxID_ANY,
576 [name] { return _("Edit filter: ") + name; }()),
577 m_on_update(std::move(on_update)),
578 m_on_apply(std::move(on_apply)),
579 m_name(name) {
580 SetName(kEditFilterFrameName + name);
581 m_filter = filters_on_disk::Read(m_name);
582
583 auto flags = wxSizerFlags().Border().Expand();
584 auto vbox = new wxBoxSizer(wxVERTICAL);
585 SetSizer(vbox);
586 vbox->Add(new IfacePanel(this, m_filter, [&] { Update(); }), flags);
587 vbox->Add(new wxStaticLine(this), flags.Expand());
588 auto buspanel = new BusPanel(this, m_filter, [&] { Update(); });
589 vbox->Add(buspanel, flags);
590 vbox->Add(new wxStaticLine(this), flags.Expand());
591 vbox->Add(new DirectionPanel(this, m_filter, [&] { Update(); }), flags);
592 vbox->Add(new wxStaticLine(this), flags.Expand());
593 vbox->Add(new AcceptedPanel(this, m_filter, [&] { Update(); }), flags);
594 vbox->Add(new MsgTypePanel(this, m_filter, [&] { Update(); }), flags);
595 vbox->Add(new Buttons(this), flags);
596 Fit();
597 Hide();
598
599 Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent&) { Destroy(); });
600 Bind(wxEVT_BUTTON, [&](wxCommandEvent& evt) { OnButtonEvent(evt); });
601 }
602
603private:
604 void Update() {
605 filters_on_disk::Write(m_filter, m_name);
606 m_on_update(m_name);
607 }
608
609 void OnButtonEvent(wxCommandEvent& evt) {
610 if (evt.GetId() == wxID_CLOSE) {
611 Destroy();
612 evt.Skip();
613 } else if (evt.GetId() == wxID_APPLY) {
614 m_on_apply(m_name);
615 evt.Skip();
616 }
617 }
618
619 std::function<void(const std::string&)> m_on_update;
620 std::function<void(const std::string&)> m_on_apply;
621 std::string m_name;
622 NavmsgFilter m_filter;
623};
624
625void CreateFilterDlg(wxWindow* parent) {
626 NewFilterDlg dlg(parent);
627 dlg.ShowModal();
628 auto name = dlg.GetValue().ToStdString();
629 if (name.empty()) {
630 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(), _("Illegal name"));
631 msg_dlg.ShowModal();
632 return;
633 }
634 if (filters_on_disk::Exists(name)) {
635 BadFilterNameDlg(wxTheApp->GetTopWindow()).ShowModal();
636 return;
637 }
638 NavmsgFilter filter;
639 filter.m_name = name;
640 filters_on_disk::Write(filter, name);
641 FilterEvents::GetInstance().filter_list_change.Notify();
642}
643
644void RemoveFilterDlg(wxWindow* parent) {
645 if (GetUserFilters().empty()) {
646 wxMessageDialog dlg(wxTheApp->GetTopWindow(), _("No filters created"));
647 dlg.ShowModal();
648 return;
649 }
650 DeleteFilterDlg dlg(parent);
651 int sts = dlg.ShowModal();
652 if (sts != wxID_OK) return;
653
654 fs::path path(dlg.GetStringSelection().ToStdString());
655 if (filters_on_disk::Remove(path.stem().string())) {
656 FilterEvents::GetInstance().filter_list_change.Notify();
657 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(), _("Filter removed"));
658 msg_dlg.ShowModal();
659 } else {
660 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(),
661 _("Cannot remove filter"));
662 msg_dlg.ShowModal();
663 }
664}
665
666void EditOneFilterDlg(wxWindow* parent, const std::string& filter) {
667 std::string window_name = kEditFilterFrameName + filter;
668 wxWindow* frame = wxWindow::FindWindowByName(window_name);
669 if (frame) {
670 frame->Raise();
671 return;
672 }
673 auto on_update = [](const std::string& _name) {
674 FilterEvents::GetInstance().filter_update.Notify(_name);
675 };
676 auto on_apply = [](const std::string& _name) {
677 FilterEvents::GetInstance().filter_apply.Notify(_name);
678 };
679 new EditFilterFrame(parent, filter, on_update, on_apply);
680 frame = wxWindow::FindWindowByName(window_name);
681 assert(frame && "Cannot create EditFilter frame");
682 frame->Show();
683}
684
685void EditFilterDlg(wxWindow* parent) {
686 if (GetUserFilters().empty()) {
687 wxMessageDialog dlg(wxTheApp->GetTopWindow(), _("No filters created"));
688 dlg.ShowModal();
689 return;
690 }
691 SelectFilterDlg dlg(parent);
692 int sts = dlg.ShowModal();
693 if (sts != wxID_OK) return;
694
695 EditOneFilterDlg(parent, dlg.GetStringSelection().ToStdString());
696};
The bus panel, filter w r t message types (nmea2000, nmea1083, etc.).
const std::vector< DriverPtr > & GetDrivers() const
Direction panel, set up filter w r t direction (input, output, etc..) Bound to filter....
Two state button showing either an edit.
Definition edit_button.h:35
void Notify() override
Notify all listeners, no data supplied.
EventVar filter_update
Notified with filter name when filter is updated on disk.
Definition filter_dlg.h:46
EventVar filter_list_change
Notified without data when user creates or removes a filter.
Definition filter_dlg.h:43
EventVar filter_apply
Notified with filter name when applied by user.
Definition filter_dlg.h:49
Interfaces filtering panel, bound to filter.interfaces.
Message type filter setup GUI bound to filter.include_msg and filter.exclude_msg.
The raw message layer, a singleton.
const std::set< std::string > & GetActiveMessages()
Return list of message types sent or received.
static Accepted StringToAccepted(const std::string &s)
Return Accepted value corresponding to argument s.
Common base for displaying a filter set bound to the set ctor parameter.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
T * GetWindowById(int id)
Return window with given id (which must exist) cast to T*.
Dialogs handing user defined filters.
std::vector< std::string > List(bool include_system)
Return list of filters, possibly including also the system ones.
bool Write(const NavmsgFilter &filter, const std::string &name)
Write contents for given filter to disk.
Filter storage routines.