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 RenameFilterChoiceDlg : public wxSingleChoiceDialog {
134public:
135 RenameFilterChoiceDlg(wxWindow*)
136 : wxSingleChoiceDialog(wxTheApp->GetTopWindow(),
137 _("Rename filter (name):"), _("Rename filter"),
138 GetUserFilters()) {}
139};
140
141class BadFilterNameDlg : public wxMessageDialog {
142public:
143 BadFilterNameDlg(wxWindow* parent)
144 : wxMessageDialog(parent, _(kFilterExists)) {}
145};
146
151class MsgTypePanel : public wxPanel {
152public:
153 MsgTypePanel(wxWindow* parent, NavmsgFilter& filter,
154 std::function<void()> on_update)
155 : wxPanel(parent, wxID_ANY),
156 m_filter(filter),
157 m_on_update(std::move(on_update)),
158 kIncludeBtnId(wxWindow::NewControlId()),
159 kExcludeBtnId(wxWindow::NewControlId()),
160 kEditBtnId(wxWindow::NewControlId()),
161 kListboxId(wxWindow::NewControlId()),
162 kSummaryId(wxWindow::NewControlId()),
163 kSetBtnId(wxWindow::NewControlId()),
164 kClearBtnId(wxWindow::NewControlId()) {
165 auto flags = wxSizerFlags(0).Border();
166 auto vbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Message Types"));
167 auto hbox = new wxBoxSizer(wxHORIZONTAL);
168
169 auto radiobox = new wxBoxSizer(wxVERTICAL);
170 radiobox->Add(new wxRadioButton(this, kIncludeBtnId, _("Include messages"),
171 wxDefaultPosition, wxDefaultSize,
172 wxRB_GROUP));
173 radiobox->Add(
174 new wxRadioButton(this, kExcludeBtnId, _("Exclude messages")));
175 radiobox->Add(1, 1, 1); // Expanding space, align buttons to bottom
176 radiobox->Add(new wxButton(this, kSetBtnId, _("Check all")), flags);
177 radiobox->Add(new wxButton(this, kClearBtnId, _("Clear all")), flags);
178 hbox->Add(radiobox, flags.Expand());
179
180 hbox->Add(1, 1, 1); // Expanding space, keep button/summary right aligned
181 wxArrayString choices;
182 auto msg_types = GetActiveMessages();
183 for (const auto& msg_type : msg_types) choices.Add(msg_type);
184 auto listbox = new wxCheckListBox(this, kListboxId, wxDefaultPosition,
185 wxDefaultSize, choices, 1);
186 hbox->Add(new wxStaticText(this, kSummaryId, ""), flags);
187 hbox->Add(listbox, flags);
188
189 auto edit_box = new wxBoxSizer(wxVERTICAL);
190 auto edit_btn = new EditButton(this, kEditBtnId, [&] { OnEditClick(); });
191 edit_box->Add(edit_btn, wxSizerFlags());
192 hbox->Add(edit_box, flags.Expand());
193
194 wxWindow* btn = GetWindowById<wxWindow>(kSetBtnId);
195 btn->Hide();
196 btn->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { SetAllItems(true); });
197 btn = GetWindowById<wxWindow>(kClearBtnId);
198 btn->Hide();
199 btn->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { SetAllItems(false); });
200
201 vbox->Add(hbox, flags.Expand());
202 SetSizer(vbox);
203 ImportFromFilter();
204 listbox->Hide();
205 GetWindowById<wxStaticText>(kSummaryId)->SetLabel(GetSummary());
206 Fit();
207
208 listbox->Bind(wxEVT_CHECKLISTBOX,
209 [&](wxCommandEvent& ev) { OnItemCheck(ev.GetInt()); });
210 }
211
212private:
213 std::string GetListboxItem(wxCheckListBox* listbox, unsigned i) const {
214 return listbox->GetString(i).ToStdString();
215 }
216
217 void SetAllItems(bool value) {
218 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
219 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
220 listbox->Check(i, value);
221 }
222 ExportToFilter();
223 }
224
225 std::string GetSummary() {
226 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
227
228 if (m_filter.exclude_msg.empty() && m_filter.include_msg.empty())
229 return _("All");
230 bool excluded = !m_filter.exclude_msg.empty();
231 size_t checked =
232 excluded ? m_filter.exclude_msg.size() : m_filter.include_msg.size();
233 size_t all = listbox->GetCount();
234 if (all == checked) return _("All");
235
236 std::stringstream ss;
237 ss << "[" << checked << _(" of ") << all << "]";
238 return ss.str();
239 }
240
245 void OnEditClick() {
246 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
247 auto summary = GetWindowById<wxStaticText>(kSummaryId);
248 auto edit_button = GetWindowById<EditButton>(kEditBtnId);
249 bool is_editing = listbox->IsShown();
250 listbox->Show(!is_editing);
251 summary->Show(is_editing);
252 summary->SetLabel(GetSummary());
253 edit_button->SetIcon(!is_editing);
254 GetWindowById<wxWindow>(kSetBtnId)->Show(!is_editing);
255 GetWindowById<wxWindow>(kClearBtnId)->Show(!is_editing);
256 GetParent()->Fit();
257 ExportToFilter();
258 }
259
264 void OnItemCheck(int ix) {
265 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
266 int checked = 0;
267 for (unsigned i = 0; i < listbox->GetCount(); i += 1)
268 if (listbox->IsChecked(i)) checked += 1;
269 if (checked == 0) {
270 // Refuse to create a filter with no interfaces.
271 listbox->Check(ix);
272 return;
273 }
274 ExportToFilter();
275 }
276
278 void ImportFromFilter() {
279 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
280 auto exclude_btn = GetWindowById<wxRadioButton>(kExcludeBtnId);
281 auto include_btn = GetWindowById<wxRadioButton>(kIncludeBtnId);
282
283 exclude_btn->SetValue(m_filter.exclude_msg.size() > 0);
284 if (include_btn->GetValue()) {
285 if (m_filter.include_msg.empty()) {
286 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
287 } else {
288 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
289 std::string item = GetListboxItem(listbox, i);
290 if (m_filter.include_msg.count(item)) listbox->Check(i);
291 }
292 }
293 } else {
294 if (m_filter.exclude_msg.empty()) {
295 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
296 } else {
297 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
298 std::string item = GetListboxItem(listbox, i);
299 if (m_filter.exclude_msg.count(item)) listbox->Check(i);
300 }
301 }
302 }
303 }
304
306 void ExportToFilter() {
307 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
308 auto include_btn = GetWindowById<wxRadioButton>(kIncludeBtnId);
309 m_filter.include_msg.clear();
310 m_filter.exclude_msg.clear();
311 auto& the_set =
312 include_btn->GetValue() ? m_filter.include_msg : m_filter.exclude_msg;
313 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
314 if (!listbox->IsChecked(i)) continue;
315 std::string item = GetListboxItem(listbox, i);
316 the_set.insert(item);
317 }
318 if (the_set.size() == listbox->GetCount()) {
319 m_filter.include_msg.clear();
320 m_filter.exclude_msg.clear();
321 }
322 m_on_update();
323 }
324
325 NavmsgFilter& m_filter;
326 std::function<void()> m_on_update;
327 const int kIncludeBtnId;
328 const int kExcludeBtnId;
329 const int kEditBtnId;
330 const int kListboxId;
331 const int kSummaryId;
332 const int kSetBtnId;
333 const int kClearBtnId;
334};
335
344template <typename T>
345class SetPanel : public wxPanel {
346public:
347 SetPanel(wxWindow* parent, std::set<T>& set, std::function<void()> on_update,
348 const std::string& label, std::function<wxArrayString()> get_choices)
349 : wxPanel(),
350 m_set(set),
351 m_on_update(std::move(on_update)),
352 kEditBtnId(wxWindow::NewControlId()),
353 kListboxId(wxWindow::NewControlId()),
354 kListLabelId(wxWindow::NewControlId()) {
355 wxPanel::Create(parent, wxID_ANY);
356 auto flags = wxSizerFlags(0).Border();
357 auto vbox = new wxBoxSizer(wxVERTICAL);
358 auto hbox = new wxBoxSizer(wxHORIZONTAL);
359 hbox->Add(new wxStaticText(this, wxID_ANY, label), flags);
360
361 // Pre-compute required size of wxCheckListBox
362 // to avoid sizer errors on MacOS
363 wxArrayString array = get_choices();
364 int max_char = 0;
365 for (auto string : array) max_char = wxMax(max_char, string.Length());
366 int hsize = (max_char + 8) * wxWindow::GetCharWidth();
367
368 hbox->Add(1, 1, 1);
369 auto listbox = new wxCheckListBox(this, kListboxId, wxDefaultPosition,
370 wxSize(hsize, -1), get_choices());
371 hbox->Add(listbox, flags);
372 auto list_label = new wxStaticText(this, kListLabelId, "");
373 hbox->Add(list_label, flags);
374 auto edit_btn = new EditButton(this, kEditBtnId, [&] { OnEditClick(); });
375 hbox->Add(edit_btn, flags);
376 vbox->Add(hbox, flags.Expand());
377 SetSizer(vbox);
378
379 ImportFromFilter();
380 list_label->SetLabel(GetListLabel());
381
382 listbox->Hide();
383 list_label->Show();
384
385 // Execute a round-trip of OnEditClick() to force MacOS sizers to populate
386 // the listbox.
387 OnEditClick();
388 Layout();
389 OnEditClick();
390
391 listbox->Bind(wxEVT_CHECKLISTBOX,
392 [&](wxCommandEvent& ev) { OnItemCheck(ev.GetInt()); });
393 }
394
395private:
397 T GetListboxItem(wxCheckListBox* listbox, unsigned i) const {
398 if constexpr (std::is_same<T, std::string>::value)
399 return listbox->GetString(i).ToStdString();
400 else if constexpr (std::is_same<T, NavAddr::Bus>::value)
401 return NavAddr::StringToBus(listbox->GetString(i).ToStdString());
402 else if constexpr (std::is_same<T, NavmsgStatus::Direction>::value)
403 return StringToDirection(listbox->GetString(i).ToStdString());
404 else if constexpr (std::is_same<T, NavmsgStatus::Accepted>::value)
406 listbox->GetString(i).ToStdString());
407 else
408 assert(false && "bad type...");
409 }
410
412 std::string GetListLabel() {
413 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
414 if (m_set.empty() || m_set.size() == listbox->GetCount()) return _("All");
415 std::stringstream ss;
416 ss << "[" << m_set.size() << _(" of ") << listbox->GetCount() << "]";
417 return ss.str();
418 }
419
424 void OnEditClick() {
425 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
426 listbox->Layout();
427 auto list_label = GetWindowById<wxStaticText>(kListLabelId);
428 auto edit_button = GetWindowById<EditButton>(kEditBtnId);
429 bool is_editing = listbox->IsShown();
430 listbox->Show(!is_editing);
431 list_label->Show(is_editing);
432 list_label->SetLabel(GetListLabel());
433 edit_button->SetIcon(!is_editing);
434 GetParent()->Fit();
435 }
436
441 void OnItemCheck(int ix) {
442 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
443 auto list_label = GetWindowById<wxStaticText>(kListLabelId);
444 int checked = 0;
445 for (unsigned i = 0; i < listbox->GetCount(); i += 1)
446 if (listbox->IsChecked(i)) checked += 1;
447 if (checked == 0) {
448 listbox->Check(ix);
449 return;
450 }
451 list_label->SetLabel(GetListLabel());
452 ExportToFilter();
453 }
454
456 void ImportFromFilter() {
457 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
458 if (m_set.empty()) {
459 for (unsigned i = 0; i < listbox->GetCount(); i++) listbox->Check(i);
460 } else {
461 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
462 T item = GetListboxItem(listbox, i);
463 if (m_set.count(item) > 0) listbox->Check(i);
464 }
465 }
466 }
467
469 void ExportToFilter() {
470 auto listbox = GetWindowById<wxCheckListBox>(kListboxId);
471 m_set.clear();
472 for (unsigned i = 0; i < listbox->GetCount(); i += 1) {
473 if (!listbox->IsChecked(i)) continue;
474 T item = GetListboxItem(listbox, i);
475 m_set.insert(item);
476 }
477 if (m_set.size() == listbox->GetCount()) m_set.clear();
478 m_on_update();
479 }
480
481 std::set<T>& m_set;
482 std::function<void()> m_on_update;
483 const int kEditBtnId;
484 const int kListboxId;
485 const int kListLabelId;
486};
487
489class IfacePanel : public SetPanel<std::string> {
490public:
491 IfacePanel(wxWindow* parent, NavmsgFilter& filter,
492 std::function<void()> on_update)
493 : SetPanel<std::string>(parent, filter.interfaces, std::move(on_update),
494 _("Use interfaces"),
495 [&]() { return IfacePanel::GetChoices(); }) {}
496
497private:
498 wxArrayString GetChoices() const {
499 wxArrayString choices;
500 for (auto& driver : CommDriverRegistry::GetInstance().GetDrivers())
501 choices.Add(driver->iface);
502 choices.Add("Internal");
503 return choices;
504 }
505};
506
511class BusPanel : public SetPanel<NavAddr::Bus> {
512public:
513 BusPanel(wxWindow* parent, NavmsgFilter& filter,
514 std::function<void()> on_update)
515 : SetPanel<NavAddr::Bus>(parent, filter.buses, std::move(on_update),
516 _("Use message buses"),
517 [&]() { return BusPanel::GetChoices(); }) {}
518
519private:
520 wxArrayString GetChoices() const {
521 static const char* choices[] = {"nmea0183", "nmea2000", "SignalK", "Onenet",
522 "Plugin"};
523 return {5, choices};
524 }
525};
526
531class DirectionPanel : public SetPanel<NavmsgStatus::Direction> {
532public:
533 DirectionPanel(wxWindow* parent, NavmsgFilter& filter,
534 std::function<void()> on_update)
536 parent, filter.directions, std::move(on_update),
537 _("Use directions"), [&] { return DirectionPanel::GetChoices(); }) {
538 }
539
540private:
541 wxArrayString GetChoices() const {
542 static const char* choices[] = {"Input", "Handled", "Output", "Internal"};
543 return {4, choices};
544 }
545};
546
547class AcceptedPanel : public SetPanel<NavmsgStatus::Accepted> {
548public:
549 AcceptedPanel(wxWindow* parent, NavmsgFilter& filter,
550 std::function<void()> on_update)
552 parent, filter.accepted, std::move(on_update),
553 _("Use Accepted states"),
554 [&]() { return AcceptedPanel::GetChoices(); }) {}
555
556private:
557 wxArrayString GetChoices() const {
558 static const char* choices[] = {"Ok", "FilteredNoOutput",
559 "FilteredDropped"};
560 return {3, choices};
561 }
562};
563
564class EditFilterFrame : public wxFrame {
565 class Buttons : public wxPanel {
566 public:
567 Buttons(wxWindow* parent) : wxPanel(parent, wxID_ANY) {
568 auto vbox = new wxBoxSizer(wxVERTICAL);
569 auto buttons = new wxStdDialogButtonSizer();
570 buttons->AddButton(new wxButton(this, wxID_CLOSE));
571 buttons->AddButton(new wxButton(this, wxID_APPLY));
572 vbox->Add(buttons, wxSizerFlags().Expand());
573 buttons->Realize();
574 SetSizer(vbox);
575 Layout();
576 }
577 };
578
579public:
580 EditFilterFrame(wxWindow* parent, const std::string& name,
581 std::function<void(const std::string&)> on_update,
582 std::function<void(const std::string&)> on_apply)
583 : wxFrame(parent, wxID_ANY,
584 [name] { return _("Edit filter: ") + name; }()),
585 m_on_update(std::move(on_update)),
586 m_on_apply(std::move(on_apply)),
587 m_name(name) {
588 SetName(kEditFilterFrameName + name);
589 m_filter = filters_on_disk::Read(m_name);
590
591 auto flags = wxSizerFlags().Border().Expand();
592 auto vbox = new wxBoxSizer(wxVERTICAL);
593 SetSizer(vbox);
594 vbox->Add(new IfacePanel(this, m_filter, [&] { Update(); }), flags);
595 vbox->Add(new wxStaticLine(this), flags.Expand());
596 auto buspanel = new BusPanel(this, m_filter, [&] { Update(); });
597 vbox->Add(buspanel, flags);
598 vbox->Add(new wxStaticLine(this), flags.Expand());
599 vbox->Add(new DirectionPanel(this, m_filter, [&] { Update(); }), flags);
600 vbox->Add(new wxStaticLine(this), flags.Expand());
601 vbox->Add(new AcceptedPanel(this, m_filter, [&] { Update(); }), flags);
602 vbox->Add(new MsgTypePanel(this, m_filter, [&] { Update(); }), flags);
603 vbox->Add(new Buttons(this), flags);
604 Fit();
605 Hide();
606
607 Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent&) { Destroy(); });
608 Bind(wxEVT_BUTTON, [&](wxCommandEvent& evt) { OnButtonEvent(evt); });
609 }
610
611private:
612 void Update() {
613 filters_on_disk::Write(m_filter, m_name);
614 m_on_update(m_name);
615 }
616
617 void OnButtonEvent(wxCommandEvent& evt) {
618 if (evt.GetId() == wxID_CLOSE) {
619 Destroy();
620 evt.Skip();
621 } else if (evt.GetId() == wxID_APPLY) {
622 m_on_apply(m_name);
623 evt.Skip();
624 }
625 }
626
627 std::function<void(const std::string&)> m_on_update;
628 std::function<void(const std::string&)> m_on_apply;
629 std::string m_name;
630 NavmsgFilter m_filter;
631};
632
633void CreateFilterDlg(wxWindow* parent) {
634 NewFilterDlg dlg(parent);
635 dlg.ShowModal();
636 auto name = dlg.GetValue().ToStdString();
637 if (name.empty()) {
638 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(), _("Illegal name"));
639 msg_dlg.ShowModal();
640 return;
641 }
642 if (filters_on_disk::Exists(name)) {
643 BadFilterNameDlg(wxTheApp->GetTopWindow()).ShowModal();
644 return;
645 }
646 NavmsgFilter filter;
647 filter.m_name = name;
648 filters_on_disk::Write(filter, name);
649 FilterEvents::GetInstance().filter_list_change.Notify();
650}
651
652void RemoveFilterDlg(wxWindow* parent) {
653 if (GetUserFilters().empty()) {
654 wxMessageDialog dlg(wxTheApp->GetTopWindow(), _("No filters created"));
655 dlg.ShowModal();
656 return;
657 }
658 DeleteFilterDlg dlg(parent);
659 int sts = dlg.ShowModal();
660 if (sts != wxID_OK) return;
661
662 fs::path path(dlg.GetStringSelection().ToStdString());
663 if (filters_on_disk::Remove(path.stem().string())) {
664 FilterEvents::GetInstance().filter_list_change.Notify();
665 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(), _("Filter removed"));
666 msg_dlg.ShowModal();
667 } else {
668 wxMessageDialog msg_dlg(wxTheApp->GetTopWindow(),
669 _("Cannot remove filter"));
670 msg_dlg.ShowModal();
671 }
672}
673
674void RenameFilterDlg(wxWindow* parent) {
675 if (GetUserFilters().empty()) {
676 wxMessageDialog dlg(wxTheApp->GetTopWindow(), _("No filters to rename"));
677 dlg.ShowModal();
678 return;
679 }
680 RenameFilterChoiceDlg dlg(parent);
681 int sts = dlg.ShowModal();
682 if (sts != wxID_OK) return;
683
684 fs::path old_name(dlg.GetStringSelection().ToStdString());
685 wxString caption = wxString(_("Renaming ")) + old_name.string();
686 auto new_name_dlg = new wxTextEntryDialog(parent, _("New name:"), caption);
687 int result = new_name_dlg->ShowModal();
688 if (result != wxID_OK) return;
689 filters_on_disk::Rename(old_name.string(),
690 new_name_dlg->GetValue().ToStdString());
691}
692
693void EditOneFilterDlg(wxWindow* parent, const std::string& filter) {
694 std::string window_name = kEditFilterFrameName + filter;
695 wxWindow* frame = wxWindow::FindWindowByName(window_name);
696 if (frame) {
697 frame->Raise();
698 return;
699 }
700 auto on_update = [](const std::string& _name) {
701 FilterEvents::GetInstance().filter_update.Notify(_name);
702 };
703 auto on_apply = [](const std::string& _name) {
704 FilterEvents::GetInstance().filter_apply.Notify(_name);
705 };
706 new EditFilterFrame(parent, filter, on_update, on_apply);
707 frame = wxWindow::FindWindowByName(window_name);
708 assert(frame && "Cannot create EditFilter frame");
709 frame->Show();
710}
711
712void EditFilterDlg(wxWindow* parent) {
713 if (GetUserFilters().empty()) {
714 wxMessageDialog dlg(wxTheApp->GetTopWindow(), _("No filters created"));
715 dlg.ShowModal();
716 return;
717 }
718 SelectFilterDlg dlg(parent);
719 int sts = dlg.ShowModal();
720 if (sts != wxID_OK) return;
721
722 EditOneFilterDlg(parent, dlg.GetStringSelection().ToStdString());
723};
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 Rename(const std::string &old_name, const std::string &new_name)
Rename old_name on disk to new.
bool Write(const NavmsgFilter &filter, const std::string &name)
Write contents for given filter to disk.
Data Monitor filter storage routines.