1 /* preference_editor_frame.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/decode_as.h>
17
18 #include <ui/preference_utils.h>
19 #include <ui/simple_dialog.h>
20
21 #include "preference_editor_frame.h"
22 #include <ui_preference_editor_frame.h>
23
24 #include <ui/qt/utils/qt_ui_utils.h>
25 #include <ui/qt/widgets/wireshark_file_dialog.h>
26 #include <wsutil/utf8_entities.h>
27
28 #include "wireshark_application.h"
29
30 #include <QPushButton>
31 #include <QKeyEvent>
32
PreferenceEditorFrame(QWidget * parent)33 PreferenceEditorFrame::PreferenceEditorFrame(QWidget *parent) :
34 AccordionFrame(parent),
35 ui(new Ui::PreferenceEditorFrame),
36 module_(NULL),
37 pref_(NULL),
38 new_uint_(0),
39 new_str_(""),
40 new_range_(NULL)
41 {
42 ui->setupUi(this);
43
44 #ifdef Q_OS_MAC
45 foreach (QWidget *w, findChildren<QWidget *>()) {
46 w->setAttribute(Qt::WA_MacSmallSize, true);
47 }
48 #endif
49
50 connect(ui->preferenceBrowseButton, &QPushButton::clicked, this, &PreferenceEditorFrame::browsePushButtonClicked);
51 }
52
~PreferenceEditorFrame()53 PreferenceEditorFrame::~PreferenceEditorFrame()
54 {
55 delete ui;
56 }
57
editPreference(preference * pref,pref_module * module)58 void PreferenceEditorFrame::editPreference(preference *pref, pref_module *module)
59 {
60 pref_ = pref;
61 module_ = module;
62
63 if (!pref || !module) {
64 hide();
65 return;
66 }
67
68 ui->modulePreferencesToolButton->setText(tr("Open %1 preferences…").arg(module_->title));
69
70 pref_stash(pref_, NULL);
71 ui->preferenceTitleLabel->setText(QString("%1:").arg(prefs_get_title(pref)));
72
73 // Convert the pref description from plain text to rich text.
74 QString description = html_escape(prefs_get_description(pref));
75 description.replace('\n', "<br>");
76 QString tooltip = QString("<span>%1</span>").arg(description);
77 ui->preferenceTitleLabel->setToolTip(tooltip);
78 ui->preferenceLineEdit->setToolTip(tooltip);
79
80 ui->preferenceLineEdit->clear();
81 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Empty);
82 disconnect(ui->preferenceLineEdit, 0, 0, 0);
83
84 bool show = false;
85 bool browse_button = false;
86
87 switch (prefs_get_type(pref_)) {
88 case PREF_UINT:
89 case PREF_DECODE_AS_UINT:
90 connect(ui->preferenceLineEdit, SIGNAL(textChanged(QString)),
91 this, SLOT(uintLineEditTextEdited(QString)));
92 show = true;
93 break;
94 case PREF_SAVE_FILENAME:
95 case PREF_OPEN_FILENAME:
96 case PREF_DIRNAME:
97 browse_button = true;
98 // Fallthrough
99 case PREF_STRING:
100 connect(ui->preferenceLineEdit, SIGNAL(textChanged(QString)),
101 this, SLOT(stringLineEditTextEdited(QString)));
102 show = true;
103 break;
104 case PREF_RANGE:
105 case PREF_DECODE_AS_RANGE:
106 connect(ui->preferenceLineEdit, SIGNAL(textChanged(QString)),
107 this, SLOT(rangeLineEditTextEdited(QString)));
108 show = true;
109 break;
110 default:
111 break;
112 }
113
114 if (show) {
115 ui->preferenceLineEdit->setText(gchar_free_to_qstring(prefs_pref_to_str(pref_, pref_stashed)).remove(QRegExp("\n\t")));
116 ui->preferenceBrowseButton->setHidden(!browse_button);
117 animatedShow();
118 }
119 }
120
uintLineEditTextEdited(const QString & new_str)121 void PreferenceEditorFrame::uintLineEditTextEdited(const QString &new_str)
122 {
123 if (new_str.isEmpty()) {
124 new_uint_ = prefs_get_uint_value_real(pref_, pref_stashed);
125 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Empty);
126 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
127 return;
128 }
129
130 bool ok;
131 uint new_uint = new_str.toUInt(&ok, 0);
132 if (ok) {
133 new_uint_ = new_uint;
134 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
135 } else {
136 new_uint_ = prefs_get_uint_value_real(pref_, pref_stashed);
137 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
138 }
139 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
140 }
141
stringLineEditTextEdited(const QString & new_str)142 void PreferenceEditorFrame::stringLineEditTextEdited(const QString &new_str)
143 {
144 new_str_ = new_str;
145 }
146
browsePushButtonClicked()147 void PreferenceEditorFrame::browsePushButtonClicked()
148 {
149 QString caption = wsApp->windowTitleString(prefs_get_title(pref_));
150 QString dir = prefs_get_string_value(pref_, pref_stashed);
151 QString filename;
152
153 switch (prefs_get_type(pref_)) {
154 case PREF_SAVE_FILENAME:
155 filename = WiresharkFileDialog::getSaveFileName(this, caption, dir);
156 break;
157 case PREF_OPEN_FILENAME:
158 filename = WiresharkFileDialog::getOpenFileName(this, caption, dir);
159 break;
160 case PREF_DIRNAME:
161 filename = WiresharkFileDialog::getExistingDirectory(this, caption, dir);
162 break;
163 }
164
165 if (!filename.isEmpty()) {
166 ui->preferenceLineEdit->setText(filename);
167 }
168 }
169
rangeLineEditTextEdited(const QString & new_str)170 void PreferenceEditorFrame::rangeLineEditTextEdited(const QString &new_str)
171 {
172 range_t *new_range = NULL;
173
174 convert_ret_t ret = range_convert_str(NULL, &new_range, new_str.toUtf8().constData(), prefs_get_max_value(pref_));
175 wmem_free(NULL, new_range_);
176 new_range_ = new_range;
177
178 if (ret == CVT_NO_ERROR) {
179 if (new_str.isEmpty()) {
180 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Empty);
181 } else {
182 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
183 }
184 } else {
185 ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
186 }
187 }
188
showEvent(QShowEvent * event)189 void PreferenceEditorFrame::showEvent(QShowEvent *event)
190 {
191 ui->preferenceLineEdit->setFocus();
192 ui->preferenceLineEdit->selectAll();
193
194 AccordionFrame::showEvent(event);
195 }
196
on_modulePreferencesToolButton_clicked()197 void PreferenceEditorFrame::on_modulePreferencesToolButton_clicked()
198 {
199 if (module_) {
200 emit showProtocolPreferences(module_->name);
201 }
202 on_buttonBox_rejected();
203 }
204
on_preferenceLineEdit_returnPressed()205 void PreferenceEditorFrame::on_preferenceLineEdit_returnPressed()
206 {
207 if (ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) {
208 on_buttonBox_accepted();
209 }
210 }
211
on_buttonBox_accepted()212 void PreferenceEditorFrame::on_buttonBox_accepted()
213 {
214 unsigned int changed_flags = 0;
215 unsigned int apply = 0;
216 switch(prefs_get_type(pref_)) {
217 case PREF_UINT:
218 case PREF_DECODE_AS_UINT:
219 apply = prefs_set_uint_value(pref_, new_uint_, pref_stashed);
220 break;
221 case PREF_STRING:
222 case PREF_SAVE_FILENAME:
223 case PREF_OPEN_FILENAME:
224 case PREF_DIRNAME:
225 apply = prefs_set_string_value(pref_, new_str_.toStdString().c_str(), pref_stashed);
226 break;
227 case PREF_RANGE:
228 case PREF_DECODE_AS_RANGE:
229 apply = prefs_set_range_value(pref_, new_range_, pref_stashed);
230 break;
231 default:
232 break;
233 }
234
235 if (apply && module_) {
236 changed_flags = module_->prefs_changed_flags;
237 pref_unstash_data_t unstashed_data;
238
239 unstashed_data.module = module_;
240 unstashed_data.handle_decode_as = TRUE;
241
242 pref_unstash(pref_, &unstashed_data);
243 prefs_apply(module_);
244 prefs_main_write();
245
246 gchar* err = NULL;
247 if (save_decode_as_entries(&err) < 0)
248 {
249 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err);
250 g_free(err);
251 }
252 }
253 on_buttonBox_rejected();
254 // Emit signals once UI is hidden
255 if (apply) {
256 if (changed_flags & PREF_EFFECT_FIELDS) {
257 wsApp->emitAppSignal(WiresharkApplication::FieldsChanged);
258 }
259 wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
260 wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
261 }
262 }
263
on_buttonBox_rejected()264 void PreferenceEditorFrame::on_buttonBox_rejected()
265 {
266 pref_ = NULL;
267 module_ = NULL;
268 wmem_free(NULL, new_range_);
269 new_range_ = NULL;
270 animatedHide();
271 }
272
keyPressEvent(QKeyEvent * event)273 void PreferenceEditorFrame::keyPressEvent(QKeyEvent *event)
274 {
275 if (event->modifiers() == Qt::NoModifier) {
276 if (event->key() == Qt::Key_Escape) {
277 on_buttonBox_rejected();
278 } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
279 if (ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) {
280 on_buttonBox_accepted();
281 } else if (ui->preferenceLineEdit->syntaxState() == SyntaxLineEdit::Invalid) {
282 wsApp->pushStatus(WiresharkApplication::FilterSyntax, tr("Invalid value."));
283 }
284 }
285 }
286
287 AccordionFrame::keyPressEvent(event);
288 }
289