replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[metze/wireshark/wip.git] / ui / qt / protocol_preferences_menu.cpp
1 /* protocol_preferences_menu.h
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include "config.h"
11
12 #include <glib.h>
13
14 #include <epan/prefs.h>
15 #include <epan/prefs-int.h>
16 #include <epan/proto.h>
17
18 #include <ui/preference_utils.h>
19 #include <wsutil/utf8_entities.h>
20
21 #include "protocol_preferences_menu.h"
22
23 #include <ui/qt/models/enabled_protocols_model.h>
24 #include <ui/qt/utils/qt_ui_utils.h>
25 #include "uat_dialog.h"
26 #include "wireshark_application.h"
27
28 // To do:
29 // - Elide really long items?
30 // - Handle PREF_SAVE_FILENAME, PREF_OPEN_FILENAME and PREF_DIRNAME.
31 // - Handle color prefs.
32
33 class BoolPreferenceAction : public QAction
34 {
35 public:
36     BoolPreferenceAction(pref_t *pref) :
37         QAction(NULL),
38         pref_(pref)
39     {
40         setText(prefs_get_title(pref_));
41         setCheckable(true);
42         setChecked(prefs_get_bool_value(pref_, pref_current));
43     }
44
45     unsigned int setBoolValue() {
46         return prefs_set_bool_value(pref_, isChecked(), pref_current);
47     }
48
49 private:
50     pref_t *pref_;
51 };
52
53 class EnumPreferenceAction : public QAction
54 {
55 public:
56     EnumPreferenceAction(pref_t *pref, const char *title, int enumval, QActionGroup *ag) :
57         QAction(NULL),
58         pref_(pref),
59         enumval_(enumval)
60     {
61         setText(title);
62         setActionGroup(ag);
63         setCheckable(true);
64     }
65
66     unsigned int setEnumValue() {
67         return prefs_set_enum_value(pref_, enumval_, pref_current);
68     }
69
70 private:
71     pref_t *pref_;
72     int enumval_;
73 };
74
75 class UatPreferenceAction : public QAction
76 {
77 public:
78     UatPreferenceAction(pref_t *pref) :
79         QAction(NULL),
80         pref_(pref)
81     {
82         setText(QString("%1" UTF8_HORIZONTAL_ELLIPSIS).arg(prefs_get_title(pref_)));
83     }
84
85     void showUatDialog() {
86         UatDialog uat_dlg(parentWidget(), prefs_get_uat_value(pref_));
87         uat_dlg.exec();
88         // Emitting PacketDissectionChanged directly from a QDialog can cause
89         // problems on macOS.
90         wsApp->flushAppSignals();
91     }
92
93 private:
94     pref_t *pref_;
95 };
96
97 // Preference requires an external editor (PreferenceEditorFrame)
98 class EditorPreferenceAction : public QAction
99 {
100 public:
101     EditorPreferenceAction(pref_t *pref) :
102         QAction(NULL),
103         pref_(pref)
104     {
105         QString title = prefs_get_title(pref_);
106
107         title.append(QString(": %1" UTF8_HORIZONTAL_ELLIPSIS).arg(gchar_free_to_qstring(prefs_pref_to_str(pref_, pref_current))));
108
109         setText(title);
110     }
111     pref_t *pref() { return pref_; }
112
113 private:
114     pref_t *pref_;
115 };
116
117 extern "C" {
118 // Preference callback
119
120 static guint
121 add_prefs_menu_item(pref_t *pref, gpointer menu_ptr)
122 {
123     ProtocolPreferencesMenu *pp_menu = static_cast<ProtocolPreferencesMenu *>(menu_ptr);
124     if (!pp_menu) return 1;
125
126     pp_menu->addMenuItem(pref);
127
128     return 0;
129 }
130 }
131
132
133 ProtocolPreferencesMenu::ProtocolPreferencesMenu()
134 {
135     setTitle(tr("Protocol Preferences"));
136     setModule(NULL);
137 }
138
139 void ProtocolPreferencesMenu::setModule(const QString module_name)
140 {
141     QAction *action;
142     int proto_id = -1;
143
144     if (!module_name.isEmpty()) {
145         proto_id = proto_get_id_by_filter_name(module_name.toUtf8().constData());
146     }
147
148     clear();
149     module_name_.clear();
150     module_ = NULL;
151
152     protocol_ = find_protocol_by_id(proto_id);
153     const QString long_name = proto_get_protocol_long_name(protocol_);
154     const QString short_name = proto_get_protocol_short_name(protocol_);
155     if (module_name.isEmpty() || proto_id < 0 || !protocol_) {
156         action = addAction(tr("No protocol preferences available"));
157         action->setDisabled(true);
158         return;
159     }
160
161     QAction *disable_action = new QAction(tr("Disable %1" UTF8_HORIZONTAL_ELLIPSIS).arg(short_name), this);
162     connect(disable_action, SIGNAL(triggered(bool)), this, SLOT(disableProtocolTriggered()));
163     disable_action->setDisabled(!proto_can_toggle_protocol(proto_id));
164
165     module_ = prefs_find_module(module_name.toUtf8().constData());
166     if (!module_ || !prefs_is_registered_protocol(module_name.toUtf8().constData())) {
167         action = addAction(tr("%1 has no preferences").arg(long_name));
168         action->setDisabled(true);
169         addSeparator();
170         addAction(disable_action);
171         return;
172     }
173
174     module_name_ = module_name;
175
176     action = addAction(tr("Open %1 preferences" UTF8_HORIZONTAL_ELLIPSIS).arg(long_name));
177     action->setData(QString(module_name));
178     connect(action, SIGNAL(triggered(bool)), this, SLOT(modulePreferencesTriggered()));
179     addSeparator();
180
181     prefs_pref_foreach(module_, add_prefs_menu_item, this);
182
183     if (!actions().last()->isSeparator()) {
184         addSeparator();
185     }
186     addAction(disable_action);
187 }
188
189 void ProtocolPreferencesMenu::addMenuItem(preference *pref)
190 {
191     switch (prefs_get_type(pref)) {
192     case PREF_BOOL:
193     {
194         BoolPreferenceAction *bpa = new BoolPreferenceAction(pref);
195         addAction(bpa);
196         connect(bpa, SIGNAL(triggered(bool)), this, SLOT(boolPreferenceTriggered()));
197         break;
198     }
199     case PREF_ENUM:
200     {
201         QActionGroup *ag = new QActionGroup(this);
202         QMenu *enum_menu = addMenu(prefs_get_title(pref));
203         for (const enum_val_t *enum_valp = prefs_get_enumvals(pref); enum_valp->name; enum_valp++) {
204             EnumPreferenceAction *epa = new EnumPreferenceAction(pref, enum_valp->description, enum_valp->value, ag);
205             if (prefs_get_enum_value(pref, pref_current) == enum_valp->value) {
206                 epa->setChecked(true);
207             }
208             enum_menu->addAction(epa);
209             connect(epa, SIGNAL(triggered(bool)), this, SLOT(enumPreferenceTriggered()));
210         }
211         break;
212     }
213     case PREF_UINT:
214     case PREF_STRING:
215     case PREF_RANGE:
216     case PREF_DECODE_AS_UINT:
217     case PREF_DECODE_AS_RANGE:
218     {
219         EditorPreferenceAction *epa = new EditorPreferenceAction(pref);
220         addAction(epa);
221         connect(epa, SIGNAL(triggered(bool)), this, SLOT(editorPreferenceTriggered()));
222         break;
223     }
224     case PREF_UAT:
225     {
226         UatPreferenceAction *upa = new UatPreferenceAction(pref);
227         addAction(upa);
228         connect(upa, SIGNAL(triggered(bool)), this, SLOT(uatPreferenceTriggered()));
229         break;
230     }
231     case PREF_CUSTOM:
232     case PREF_STATIC_TEXT:
233     case PREF_OBSOLETE:
234         break;
235     default:
236         // A type we currently don't handle (e.g. PREF_SAVE_FILENAME). Just open
237         // the prefs dialog.
238         QString title = QString("%1" UTF8_HORIZONTAL_ELLIPSIS).arg(prefs_get_title(pref));
239         QAction *mpa = addAction(title);
240         connect(mpa, SIGNAL(triggered(bool)), this, SLOT(modulePreferencesTriggered()));
241         break;
242     }
243 }
244
245 void ProtocolPreferencesMenu::disableProtocolTriggered()
246 {
247     EnabledProtocolsModel::disableProtocol(protocol_);
248 }
249
250 void ProtocolPreferencesMenu::modulePreferencesTriggered()
251 {
252     if (!module_name_.isEmpty()) {
253         emit showProtocolPreferences(module_name_);
254     }
255 }
256
257 void ProtocolPreferencesMenu::editorPreferenceTriggered()
258 {
259     EditorPreferenceAction *epa = static_cast<EditorPreferenceAction *>(QObject::sender());
260     if (!epa) return;
261
262     if (epa->pref() && module_) {
263         emit editProtocolPreference(epa->pref(), module_);
264     }
265 }
266
267 void ProtocolPreferencesMenu::boolPreferenceTriggered()
268 {
269     BoolPreferenceAction *bpa = static_cast<BoolPreferenceAction *>(QObject::sender());
270     if (!bpa) return;
271
272     module_->prefs_changed_flags |= bpa->setBoolValue();
273
274     prefs_apply(module_);
275     if (!prefs.gui_use_pref_save) {
276         prefs_main_write();
277     }
278
279     /* Protocol preference changes almost always affect dissection,
280        so don't bother checking flags */
281     wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
282 }
283
284 void ProtocolPreferencesMenu::enumPreferenceTriggered()
285 {
286     EnumPreferenceAction *epa = static_cast<EnumPreferenceAction *>(QObject::sender());
287     if (!epa) return;
288
289     unsigned int changed_flags = epa->setEnumValue();
290     if (changed_flags) { // Changed
291         module_->prefs_changed_flags |= changed_flags;
292         prefs_apply(module_);
293         if (!prefs.gui_use_pref_save) {
294             prefs_main_write();
295         }
296
297         /* Protocol preference changes almost always affect dissection,
298            so don't bother checking flags */
299         wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
300     }
301 }
302
303 void ProtocolPreferencesMenu::uatPreferenceTriggered()
304 {
305     UatPreferenceAction *upa = static_cast<UatPreferenceAction *>(QObject::sender());
306     if (!upa) return;
307
308     upa->showUatDialog();
309 }
310
311 /*
312  * Editor modelines
313  *
314  * Local Variables:
315  * c-basic-offset: 4
316  * tab-width: 8
317  * indent-tabs-mode: nil
318  * End:
319  *
320  * ex: set shiftwidth=4 tabstop=8 expandtab:
321  * :indentSize=4:tabSize=8:noTabs=true:
322  */