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