nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* module_preferences_scroll_area.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21  
22 #include "module_preferences_scroll_area.h"
23 #include <ui_module_preferences_scroll_area.h>
24 #include "syntax_line_edit.h"
25 #include "qt_ui_utils.h"
26 #include "uat_dialog.h"
27 #include "wireshark_application.h"
28  
29 #include <epan/prefs-int.h>
30  
31 #include <wsutil/utf8_entities.h>
32  
33 #include <QAbstractButton>
34 #include <QButtonGroup>
35 #include <QCheckBox>
36 #include <QComboBox>
37 #include <QFileDialog>
38 #include <QHBoxLayout>
39 #include <QLabel>
40 #include <QLineEdit>
41 #include <QPushButton>
42 #include <QRadioButton>
43 #include <QScrollBar>
44 #include <QSpacerItem>
45 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
46 // Qt::escape
47 #include <QTextDocument>
48 #endif
49  
50 Q_DECLARE_METATYPE(pref_t *)
51  
52 const char *pref_prop_ = "pref_ptr";
53  
54 // Escape our ampersands so that Qt won't try to interpret them as
55 // mnemonics.
56 static const QString title_to_shortcut(const char *title) {
57 QString shortcut_str(title);
58 shortcut_str.replace('&', "&&");
59 return shortcut_str;
60 }
61  
62  
63 extern "C" {
64 // Callbacks prefs routines
65  
66 /* show a single preference on the GtkGrid of a preference page */
67 static guint
68 pref_show(pref_t *pref, gpointer layout_ptr)
69 {
70 QVBoxLayout *vb = static_cast<QVBoxLayout *>(layout_ptr);
71  
72 if (!pref || !vb) return 0;
73  
74 // Convert the pref description from plain text to rich text.
75 QString description;
76 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
77 description = Qt::escape(pref->description);
78 #else
79 description = QString(pref->description).toHtmlEscaped();
80 #endif
81 description.replace('\n', "<br>");
82 QString tooltip = QString("<span>%1</span>").arg(description);
83  
84 switch (pref->type) {
85 case PREF_UINT:
86 {
87 QHBoxLayout *hb = new QHBoxLayout();
88 QLabel *label = new QLabel(pref->title);
89 label->setToolTip(tooltip);
90 hb->addWidget(label);
91 QLineEdit *uint_le = new QLineEdit();
92 uint_le->setToolTip(tooltip);
93 uint_le->setProperty(pref_prop_, qVariantFromValue(pref));
94 uint_le->setMinimumWidth(uint_le->fontMetrics().height() * 8);
95 hb->addWidget(uint_le);
96 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
97 vb->addLayout(hb);
98 break;
99 }
100 case PREF_BOOL:
101 {
102 QCheckBox *bool_cb = new QCheckBox(title_to_shortcut(pref->title));
103 bool_cb->setToolTip(tooltip);
104 bool_cb->setProperty(pref_prop_, qVariantFromValue(pref));
105 vb->addWidget(bool_cb);
106 break;
107 }
108 case PREF_ENUM:
109 {
110 const enum_val_t *ev;
111 if (!pref->info.enum_info.enumvals) return 0;
112  
113 if (pref->info.enum_info.radio_buttons) {
114 QLabel *label = new QLabel(pref->title);
115 label->setToolTip(tooltip);
116 vb->addWidget(label);
117 QButtonGroup *enum_bg = new QButtonGroup(vb);
118 for (ev = pref->info.enum_info.enumvals; ev && ev->description; ev++) {
119 QRadioButton *enum_rb = new QRadioButton(title_to_shortcut(ev->description));
120 enum_rb->setToolTip(tooltip);
121 QStyleOption style_opt;
122 enum_rb->setProperty(pref_prop_, qVariantFromValue(pref));
123 enum_rb->setStyleSheet(QString(
124 "QRadioButton {"
125 " margin-left: %1px;"
126 "}"
127 )
128 .arg(enum_rb->style()->subElementRect(QStyle::SE_CheckBoxContents, &style_opt).left()));
129 enum_bg->addButton(enum_rb, ev->value);
130 vb->addWidget(enum_rb);
131 }
132 } else {
133 QHBoxLayout *hb = new QHBoxLayout();
134 QComboBox *enum_cb = new QComboBox();
135 enum_cb->setToolTip(tooltip);
136 enum_cb->setProperty(pref_prop_, qVariantFromValue(pref));
137 for (ev = pref->info.enum_info.enumvals; ev && ev->description; ev++) {
138 enum_cb->addItem(ev->description, QVariant(ev->value));
139 }
140 hb->addWidget(new QLabel(pref->title));
141 hb->addWidget(enum_cb);
142 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
143 vb->addLayout(hb);
144 }
145 break;
146 }
147 case PREF_STRING:
148 {
149 QHBoxLayout *hb = new QHBoxLayout();
150 QLabel *label = new QLabel(pref->title);
151 label->setToolTip(tooltip);
152 hb->addWidget(label);
153 QLineEdit *string_le = new QLineEdit();
154 string_le->setToolTip(tooltip);
155 string_le->setProperty(pref_prop_, qVariantFromValue(pref));
156 string_le->setMinimumWidth(string_le->fontMetrics().height() * 20);
157 hb->addWidget(string_le);
158 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
159 vb->addLayout(hb);
160 break;
161 }
162 case PREF_RANGE:
163 {
164 QHBoxLayout *hb = new QHBoxLayout();
165 QLabel *label = new QLabel(pref->title);
166 label->setToolTip(tooltip);
167 hb->addWidget(label);
168 SyntaxLineEdit *range_se = new SyntaxLineEdit();
169 range_se->setToolTip(tooltip);
170 range_se->setProperty(pref_prop_, qVariantFromValue(pref));
171 range_se->setMinimumWidth(range_se->fontMetrics().height() * 20);
172 hb->addWidget(range_se);
173 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
174 vb->addLayout(hb);
175 break;
176 }
177 case PREF_STATIC_TEXT:
178 {
179 QLabel *label = new QLabel(pref->title);
180 label->setToolTip(tooltip);
181 label->setWordWrap(true);
182 vb->addWidget(label);
183 break;
184 }
185 case PREF_UAT:
186 {
187 QHBoxLayout *hb = new QHBoxLayout();
188 QLabel *label = new QLabel(pref->title);
189 label->setToolTip(tooltip);
190 hb->addWidget(label);
191 QPushButton *uat_pb = new QPushButton(QObject::tr("Edit" UTF8_HORIZONTAL_ELLIPSIS));
192 uat_pb->setToolTip(tooltip);
193 uat_pb->setProperty(pref_prop_, qVariantFromValue(pref));
194 hb->addWidget(uat_pb);
195 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
196 vb->addLayout(hb);
197 break;
198 }
199 case PREF_FILENAME:
200 case PREF_DIRNAME:
201 {
202 QLabel *label = new QLabel(pref->title);
203 label->setToolTip(tooltip);
204 vb->addWidget(label);
205 QHBoxLayout *hb = new QHBoxLayout();
206 QLineEdit *path_le = new QLineEdit();
207 path_le->setToolTip(tooltip);
208 QStyleOption style_opt;
209 path_le->setProperty(pref_prop_, qVariantFromValue(pref));
210 path_le->setMinimumWidth(path_le->fontMetrics().height() * 20);
211 path_le->setStyleSheet(QString(
212 "QLineEdit {"
213 " margin-left: %1px;"
214 "}"
215 )
216 .arg(path_le->style()->subElementRect(QStyle::SE_CheckBoxContents, &style_opt).left()));
217 hb->addWidget(path_le);
218 QPushButton *path_pb = new QPushButton(QObject::tr("Browse" UTF8_HORIZONTAL_ELLIPSIS));
219 path_pb->setProperty(pref_prop_, qVariantFromValue(pref));
220 hb->addWidget(path_pb);
221 hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
222 vb->addLayout(hb);
223 break;
224 }
225 case PREF_COLOR:
226 {
227 // XXX - Not needed yet. When it is needed we can add a label + QFrame which pops up a
228 // color picker similar to the Font and Colors prefs.
229 break;
230 }
231 default:
232 break;
233 }
234 return 0;
235 }
236  
237 } // extern "C"
238  
239 ModulePreferencesScrollArea::ModulePreferencesScrollArea(module_t *module, QWidget *parent) :
240 QScrollArea(parent),
241 ui(new Ui::ModulePreferencesScrollArea),
242 module_(module)
243 {
244 ui->setupUi(this);
245  
246 if (!module) return;
247  
248 /* Show the preference's description at the top of the page */
249 QFont font;
250 font.setBold(TRUE);
251 QLabel *label = new QLabel(module->description);
252 label->setFont(font);
253 ui->verticalLayout->addWidget(label);
254  
255 /* Add items for each of the preferences */
256 prefs_pref_foreach(module, pref_show, (gpointer) ui->verticalLayout);
257  
258 foreach (QLineEdit *le, findChildren<QLineEdit *>()) {
259 pref_t *pref = le->property(pref_prop_).value<pref_t *>();
260 if (!pref) continue;
261  
262 switch (pref->type) {
263 case PREF_UINT:
264 connect(le, SIGNAL(textEdited(QString)), this, SLOT(uintLineEditTextEdited(QString)));
265 break;
266 case PREF_STRING:
267 case PREF_FILENAME:
268 case PREF_DIRNAME:
269 connect(le, SIGNAL(textEdited(QString)), this, SLOT(stringLineEditTextEdited(QString)));
270 break;
271 case PREF_RANGE:
272 connect(le, SIGNAL(textEdited(QString)), this, SLOT(rangeSyntaxLineEditTextEdited(QString)));
273 break;
274 default:
275 break;
276 }
277 }
278  
279 foreach (QCheckBox *cb, findChildren<QCheckBox *>()) {
280 pref_t *pref = cb->property(pref_prop_).value<pref_t *>();
281 if (!pref) continue;
282  
283 if (pref->type == PREF_BOOL) {
284 connect(cb, SIGNAL(toggled(bool)), this, SLOT(boolCheckBoxToggled(bool)));
285 }
286 }
287  
288 foreach (QRadioButton *rb, findChildren<QRadioButton *>()) {
289 pref_t *pref = rb->property(pref_prop_).value<pref_t *>();
290 if (!pref) continue;
291  
292 if (pref->type == PREF_ENUM && pref->info.enum_info.radio_buttons) {
293 connect(rb, SIGNAL(toggled(bool)), this, SLOT(enumRadioButtonToggled(bool)));
294 }
295 }
296  
297 foreach (QComboBox *combo, findChildren<QComboBox *>()) {
298 pref_t *pref = combo->property(pref_prop_).value<pref_t *>();
299 if (!pref) continue;
300  
301 if (pref->type == PREF_ENUM && !pref->info.enum_info.radio_buttons) {
302 connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(enumComboBoxCurrentIndexChanged(int)));
303 }
304 }
305  
306 foreach (QPushButton *pb, findChildren<QPushButton *>()) {
307 pref_t *pref = pb->property(pref_prop_).value<pref_t *>();
308 if (!pref) continue;
309  
310 if (pref->type == PREF_UAT) {
311 connect(pb, SIGNAL(pressed()), this, SLOT(uatPushButtonPressed()));
312 } else if (pref->type == PREF_FILENAME) {
313 connect(pb, SIGNAL(pressed()), this, SLOT(filenamePushButtonPressed()));
314 } else if (pref->type == PREF_DIRNAME) {
315 connect(pb, SIGNAL(pressed()), this, SLOT(dirnamePushButtonPressed()));
316 }
317 }
318  
319 ui->verticalLayout->addSpacerItem(new QSpacerItem(10, 1, QSizePolicy::Minimum, QSizePolicy::Expanding));
320 }
321  
322 ModulePreferencesScrollArea::~ModulePreferencesScrollArea()
323 {
324 delete ui;
325 }
326  
327 void ModulePreferencesScrollArea::showEvent(QShowEvent *)
328 {
329 updateWidgets();
330 }
331  
332 void ModulePreferencesScrollArea::resizeEvent(QResizeEvent *evt)
333 {
334 QScrollArea::resizeEvent(evt);
335  
336 if (verticalScrollBar()->isVisible()) {
337 setFrameStyle(QFrame::StyledPanel);
338 } else {
339 setFrameStyle(QFrame::NoFrame);
340 }
341 }
342  
343 void ModulePreferencesScrollArea::updateWidgets()
344 {
345 foreach (QLineEdit *le, findChildren<QLineEdit *>()) {
346 pref_t *pref = le->property(pref_prop_).value<pref_t *>();
347 if (!pref) continue;
348  
349 le->setText(gchar_free_to_qstring(prefs_pref_to_str(pref, pref_stashed)).remove(QRegExp("\n\t")));
350 }
351  
352 foreach (QCheckBox *cb, findChildren<QCheckBox *>()) {
353 pref_t *pref = cb->property(pref_prop_).value<pref_t *>();
354 if (!pref) continue;
355  
356 if (pref->type == PREF_BOOL) {
357 cb->setChecked(pref->stashed_val.boolval);
358 }
359 }
360  
361 foreach (QRadioButton *enum_rb, findChildren<QRadioButton *>()) {
362 pref_t *pref = enum_rb->property(pref_prop_).value<pref_t *>();
363 if (!pref) continue;
364  
365 QButtonGroup *enum_bg = enum_rb->group();
366 if (!enum_bg) continue;
367  
368 if (pref->type == PREF_ENUM && pref->info.enum_info.radio_buttons) {
369 if (pref->stashed_val.enumval == enum_bg->id(enum_rb)) {
370 enum_rb->setChecked(true);
371 }
372 }
373 }
374  
375 foreach (QComboBox *enum_cb, findChildren<QComboBox *>()) {
376 pref_t *pref = enum_cb->property(pref_prop_).value<pref_t *>();
377 if (!pref) continue;
378  
379 if (pref->type == PREF_ENUM && !pref->info.enum_info.radio_buttons) {
380 for (int i = 0; i < enum_cb->count(); i++) {
381 if (pref->stashed_val.enumval == enum_cb->itemData(i).toInt()) {
382 enum_cb->setCurrentIndex(i);
383 }
384 }
385 }
386 }
387 }
388  
389 void ModulePreferencesScrollArea::uintLineEditTextEdited(const QString &new_str)
390 {
391 QLineEdit *uint_le = qobject_cast<QLineEdit*>(sender());
392 if (!uint_le) return;
393  
394 pref_t *pref = uint_le->property(pref_prop_).value<pref_t *>();
395 if (!pref) return;
396  
397 bool ok;
398 uint new_uint = new_str.toUInt(&ok, 0);
399 if (ok) {
400 pref->stashed_val.uint = new_uint;
401 }
402 }
403  
404 void ModulePreferencesScrollArea::boolCheckBoxToggled(bool checked)
405 {
406 QCheckBox *bool_cb = qobject_cast<QCheckBox*>(sender());
407 if (!bool_cb) return;
408  
409 pref_t *pref = bool_cb->property(pref_prop_).value<pref_t *>();
410 if (!pref) return;
411  
412 pref->stashed_val.boolval = checked;
413 }
414  
415 void ModulePreferencesScrollArea::enumRadioButtonToggled(bool checked)
416 {
417 if (!checked) return;
418 QRadioButton *enum_rb = qobject_cast<QRadioButton*>(sender());
419 if (!enum_rb) return;
420  
421 QButtonGroup *enum_bg = enum_rb->group();
422 if (!enum_bg) return;
423  
424 pref_t *pref = enum_rb->property(pref_prop_).value<pref_t *>();
425 if (!pref) return;
426  
427 if (enum_bg->checkedId() >= 0) {
428 pref->stashed_val.enumval = enum_bg->checkedId();
429 }
430 }
431  
432 void ModulePreferencesScrollArea::enumComboBoxCurrentIndexChanged(int index)
433 {
434 QComboBox *enum_cb = qobject_cast<QComboBox*>(sender());
435 if (!enum_cb) return;
436  
437 pref_t *pref = enum_cb->property(pref_prop_).value<pref_t *>();
438 if (!pref) return;
439  
440 pref->stashed_val.enumval = enum_cb->itemData(index).toInt();
441 }
442  
443 void ModulePreferencesScrollArea::stringLineEditTextEdited(const QString &new_str)
444 {
445 QLineEdit *string_le = qobject_cast<QLineEdit*>(sender());
446 if (!string_le) return;
447  
448 pref_t *pref = string_le->property(pref_prop_).value<pref_t *>();
449 if (!pref) return;
450  
451 g_free((void *)pref->stashed_val.string);
452 pref->stashed_val.string = qstring_strdup(new_str);
453 }
454  
455 void ModulePreferencesScrollArea::rangeSyntaxLineEditTextEdited(const QString &new_str)
456 {
457 SyntaxLineEdit *range_se = qobject_cast<SyntaxLineEdit*>(sender());
458 if (!range_se) return;
459  
460 pref_t *pref = range_se->property(pref_prop_).value<pref_t *>();
461 if (!pref) return;
462  
463 range_t *newrange;
464 convert_ret_t ret = range_convert_str(&newrange, new_str.toUtf8().constData(), pref->info.max_value);
465  
466 if (ret == CVT_NO_ERROR) {
467 g_free(pref->stashed_val.range);
468 pref->stashed_val.range = newrange;
469  
470 if (new_str.isEmpty()) {
471 range_se->setSyntaxState(SyntaxLineEdit::Empty);
472 } else {
473 range_se->setSyntaxState(SyntaxLineEdit::Valid);
474 }
475 } else {
476 range_se->setSyntaxState(SyntaxLineEdit::Invalid);
477 }
478 }
479  
480 void ModulePreferencesScrollArea::uatPushButtonPressed()
481 {
482 QPushButton *uat_pb = qobject_cast<QPushButton*>(sender());
483 if (!uat_pb) return;
484  
485 pref_t *pref = uat_pb->property(pref_prop_).value<pref_t *>();
486 if (!pref) return;
487  
488 UatDialog uat_dlg(this, pref->varp.uat);
489 uat_dlg.exec();
490 }
491  
492 void ModulePreferencesScrollArea::filenamePushButtonPressed()
493 {
494 QPushButton *filename_pb = qobject_cast<QPushButton*>(sender());
495 if (!filename_pb) return;
496  
497 pref_t *pref = filename_pb->property(pref_prop_).value<pref_t *>();
498 if (!pref) return;
499  
500 QString filename = QFileDialog::getSaveFileName(this, wsApp->windowTitleString(pref->title),
501 pref->stashed_val.string, QString(), NULL,
502 QFileDialog::DontConfirmOverwrite);
503  
504 if (!filename.isEmpty()) {
505 g_free((void *)pref->stashed_val.string);
506 pref->stashed_val.string = qstring_strdup(QDir::toNativeSeparators(filename));
507 updateWidgets();
508 }
509 }
510  
511 void ModulePreferencesScrollArea::dirnamePushButtonPressed()
512 {
513 QPushButton *dirname_pb = qobject_cast<QPushButton*>(sender());
514 if (!dirname_pb) return;
515  
516 pref_t *pref = dirname_pb->property(pref_prop_).value<pref_t *>();
517 if (!pref) return;
518  
519 QString dirname = QFileDialog::getExistingDirectory(this, wsApp->windowTitleString(pref->title),
520 pref->stashed_val.string);
521  
522 if (!dirname.isEmpty()) {
523 g_free((void *)pref->stashed_val.string);
524 pref->stashed_val.string = qstring_strdup(QDir::toNativeSeparators(dirname));
525 updateWidgets();
526 }
527 }
528  
529 /*
530 * Editor modelines
531 *
532 * Local Variables:
533 * c-basic-offset: 4
534 * tab-width: 8
535 * indent-tabs-mode: nil
536 * End:
537 *
538 * ex: set shiftwidth=4 tabstop=8 expandtab:
539 * :indentSize=4:tabSize=8:noTabs=true:
540 */