1 /* additional_toolbar.cpp
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 <ui/qt/widgets/additional_toolbar.h>
15 #include <ui/qt/widgets/apply_line_edit.h>
16 #include <ui/qt/utils/qt_ui_utils.h>
17 #include <ui/qt/utils/variant_pointer.h>
18 #include <ui/qt/wireshark_application.h>
19
20 #include <QLabel>
21 #include <QLineEdit>
22 #include <QHBoxLayout>
23 #include <QComboBox>
24 #include <QWidget>
25 #include <QCheckBox>
26 #include <QPushButton>
27 #include <QStandardItem>
28 #include <QStandardItemModel>
29 #include <QLayoutItem>
30
31 const char * AdditionalToolbarWidgetAction::propertyName = "additional_toolbar_item";
32
AdditionalToolBar(ext_toolbar_t * exttoolbar,QWidget * parent)33 AdditionalToolBar::AdditionalToolBar(ext_toolbar_t * exttoolbar, QWidget * parent)
34 : QToolBar(parent),
35 toolbar(exttoolbar)
36 { }
37
~AdditionalToolBar()38 AdditionalToolBar::~AdditionalToolBar()
39 { }
40
create(QWidget * parent,ext_toolbar_t * toolbar)41 AdditionalToolBar * AdditionalToolBar::create(QWidget * parent, ext_toolbar_t * toolbar)
42 {
43 if (g_list_length(toolbar->children) == 0)
44 return NULL;
45
46 AdditionalToolBar * result = new AdditionalToolBar(toolbar, parent);
47 result->setMovable(false);
48 result->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
49 result->layout()->setContentsMargins(0, 0, 0, 0);
50 result->layout()->setSpacing(4);
51
52 GList * walker = toolbar->children;
53 bool spacerNeeded = true;
54
55 while (walker && walker->data)
56 {
57 ext_toolbar_t * item = gxx_list_data(ext_toolbar_t *, walker);
58 if (item->type == EXT_TOOLBAR_ITEM)
59 {
60 if (item->item_type == EXT_TOOLBAR_STRING)
61 spacerNeeded = false;
62
63 QAction * newAction = new AdditionalToolbarWidgetAction(item, result);
64 if (newAction)
65 {
66 result->addAction(newAction);
67 /* Necessary, because enable state is reset upon adding the action */
68 result->actions()[result->actions().count() - 1]->setEnabled(!item->capture_only);
69 }
70 }
71
72 walker = gxx_list_next (walker);
73 }
74
75 if (result->children().count() == 0)
76 return Q_NULLPTR;
77
78 if (spacerNeeded)
79 {
80 QWidget * empty = new QWidget();
81 empty->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
82 result->addWidget(empty);
83
84 }
85
86 return result;
87 }
88
menuName()89 QString AdditionalToolBar::menuName()
90 {
91 return (toolbar && toolbar->name) ? QString(toolbar->name) : QString();
92 }
93
AdditionalToolbarWidgetAction(QObject * parent)94 AdditionalToolbarWidgetAction::AdditionalToolbarWidgetAction(QObject * parent)
95 : QWidgetAction(parent),
96 toolbar_item(0)
97 { }
98
AdditionalToolbarWidgetAction(ext_toolbar_t * item,QObject * parent)99 AdditionalToolbarWidgetAction::AdditionalToolbarWidgetAction(ext_toolbar_t * item, QObject * parent)
100 : QWidgetAction(parent),
101 toolbar_item(item)
102 {
103 connect(wsApp, &WiresharkApplication::captureActive, this, &AdditionalToolbarWidgetAction::captureActive);
104 }
105
AdditionalToolbarWidgetAction(const AdditionalToolbarWidgetAction & copy_object)106 AdditionalToolbarWidgetAction::AdditionalToolbarWidgetAction(const AdditionalToolbarWidgetAction & copy_object)
107 : QWidgetAction(copy_object.parent()),
108 toolbar_item(copy_object.toolbar_item)
109 {
110 connect(wsApp, &WiresharkApplication::captureActive, this, &AdditionalToolbarWidgetAction::captureActive);
111 }
112
113
captureActive(int activeCaptures)114 void AdditionalToolbarWidgetAction::captureActive(int activeCaptures)
115 {
116 if (toolbar_item && toolbar_item->capture_only)
117 {
118 setEnabled(activeCaptures != 0);
119 }
120 }
121
122 /* Exists, so a default deconstructor does not call delete on toolbar_item */
~AdditionalToolbarWidgetAction()123 AdditionalToolbarWidgetAction::~AdditionalToolbarWidgetAction() { }
124
createWidget(QWidget * parent)125 QWidget * AdditionalToolbarWidgetAction::createWidget(QWidget * parent)
126 {
127 QWidget * barItem = 0;
128
129 if (toolbar_item->type != EXT_TOOLBAR_ITEM)
130 return barItem;
131
132 switch (toolbar_item->item_type)
133 {
134 case EXT_TOOLBAR_BUTTON:
135 barItem = createButton(toolbar_item, parent);
136 break;
137 case EXT_TOOLBAR_BOOLEAN:
138 barItem = createBoolean(toolbar_item, parent);
139 break;
140 case EXT_TOOLBAR_STRING:
141 barItem = createTextEditor(toolbar_item, parent);
142 break;
143 case EXT_TOOLBAR_SELECTOR:
144 barItem = createSelector(toolbar_item, parent);
145 break;
146 }
147
148 if (! barItem)
149 return 0;
150
151 barItem->setToolTip(toolbar_item->tooltip);
152 barItem->setProperty(propertyName, VariantPointer<ext_toolbar_t>::asQVariant(toolbar_item));
153
154 #ifdef Q_OS_MAC
155 barItem->setAttribute(Qt::WA_MacSmallSize, true);
156 #endif
157
158 return barItem;
159 }
160
161 static void
toolbar_button_cb(gpointer item,gpointer item_data,gpointer user_data)162 toolbar_button_cb(gpointer item, gpointer item_data, gpointer user_data)
163 {
164 if (! item || ! item_data || ! user_data)
165 return;
166
167 QPushButton * widget = (QPushButton *)(item_data);
168 ext_toolbar_update_t * update_entry = (ext_toolbar_update_t *)user_data;
169
170 if (widget)
171 {
172 if (update_entry->type == EXT_TOOLBAR_UPDATE_VALUE)
173 widget->setText((gchar *)update_entry->user_data);
174 else if (update_entry->type == EXT_TOOLBAR_SET_ACTIVE)
175 {
176 bool enableState = GPOINTER_TO_INT(update_entry->user_data) == 1;
177 widget->setEnabled(enableState);
178 }
179
180 }
181 }
182
createButton(ext_toolbar_t * item,QWidget * parent)183 QWidget * AdditionalToolbarWidgetAction::createButton(ext_toolbar_t * item, QWidget * parent)
184 {
185 if (! item || item->type != EXT_TOOLBAR_ITEM || item->item_type != EXT_TOOLBAR_BUTTON)
186 return 0;
187
188 QPushButton * button = new QPushButton(item->name, parent);
189 button->setText(item->name);
190 connect(button, &QPushButton::clicked, this, &AdditionalToolbarWidgetAction::onButtonClicked);
191
192 ext_toolbar_register_update_cb(item, (ext_toolbar_action_cb)&toolbar_button_cb, (void *)button);
193
194 return button;
195 }
196
197 static void
toolbar_boolean_cb(gpointer item,gpointer item_data,gpointer user_data)198 toolbar_boolean_cb(gpointer item, gpointer item_data, gpointer user_data)
199 {
200 if (! item || ! item_data || ! user_data)
201 return;
202
203 QCheckBox * widget = (QCheckBox *)(item_data);
204
205 ext_toolbar_update_t * update_entry = (ext_toolbar_update_t *)user_data;
206
207 if (update_entry->type == EXT_TOOLBAR_UPDATE_VALUE)
208 {
209 bool oldState = false;
210 if (update_entry->silent)
211 oldState = widget->blockSignals(true);
212
213 widget->setCheckState(GPOINTER_TO_INT(update_entry->user_data) == 1 ? Qt::Checked : Qt::Unchecked);
214
215 if (update_entry->silent)
216 widget->blockSignals(oldState);
217 }
218 else if (update_entry->type == EXT_TOOLBAR_SET_ACTIVE)
219 {
220 bool enableState = GPOINTER_TO_INT(update_entry->user_data) == 1;
221 widget->setEnabled(enableState);
222 }
223 }
224
createBoolean(ext_toolbar_t * item,QWidget * parent)225 QWidget * AdditionalToolbarWidgetAction::createBoolean(ext_toolbar_t * item, QWidget * parent)
226 {
227 if (! item || item->type != EXT_TOOLBAR_ITEM || item->item_type != EXT_TOOLBAR_BOOLEAN)
228 return 0;
229
230 QString defValue = toolbar_item->defvalue;
231
232 QCheckBox * checkbox = new QCheckBox(item->name, parent);
233 checkbox->setText(item->name);
234 setCheckable(true);
235 checkbox->setCheckState(defValue.compare("true", Qt::CaseInsensitive) == 0 ? Qt::Checked : Qt::Unchecked);
236 connect(checkbox, &QCheckBox::stateChanged, this, &AdditionalToolbarWidgetAction::onCheckBoxChecked);
237
238 ext_toolbar_register_update_cb(item, (ext_toolbar_action_cb)&toolbar_boolean_cb, (void *)checkbox);
239
240 return checkbox;
241 }
242
createLabelFrame(ext_toolbar_t * item,QWidget * parent)243 QWidget * AdditionalToolbarWidgetAction::createLabelFrame(ext_toolbar_t * item, QWidget * parent)
244 {
245 if (! item)
246 return new QWidget();
247
248 QWidget * frame = new QWidget(parent);
249
250 QHBoxLayout * frameLayout = new QHBoxLayout(frame);
251 frameLayout->setContentsMargins(0, 0, 0, 0);
252 frameLayout->setSpacing(0);
253
254 QLabel * strLabel = new QLabel(item->name, frame);
255 strLabel->setToolTip(item->tooltip);
256
257 #ifdef Q_OS_MAC
258 frame->setAttribute(Qt::WA_MacSmallSize, true);
259 strLabel->setAttribute(Qt::WA_MacSmallSize, true);
260 #endif
261
262 frameLayout->addWidget(strLabel);
263
264 frame->setLayout(frameLayout);
265
266 return frame;
267 }
268
269 static void
toolbar_string_cb(gpointer item,gpointer item_data,gpointer user_data)270 toolbar_string_cb(gpointer item, gpointer item_data, gpointer user_data)
271 {
272 if (! item || ! item_data || ! user_data)
273 return;
274
275 ApplyLineEdit * edit = (ApplyLineEdit *)(item_data);
276
277 ext_toolbar_update_t * update_entry = (ext_toolbar_update_t *)user_data;
278
279 if (update_entry->type == EXT_TOOLBAR_UPDATE_VALUE)
280 {
281 bool oldState = false;
282 if (update_entry->silent)
283 oldState = edit->blockSignals(true);
284
285 edit->setText((gchar *)update_entry->user_data);
286
287 if (update_entry->silent)
288 edit->blockSignals(oldState);
289 }
290 else if (update_entry->type == EXT_TOOLBAR_SET_ACTIVE)
291 {
292 bool enableState = GPOINTER_TO_INT(update_entry->user_data) == 1;
293 edit->setEnabled(enableState);
294 }
295 }
296
createTextEditor(ext_toolbar_t * item,QWidget * parent)297 QWidget * AdditionalToolbarWidgetAction::createTextEditor(ext_toolbar_t * item, QWidget * parent)
298 {
299 if (! item || item->type != EXT_TOOLBAR_ITEM || item->item_type != EXT_TOOLBAR_STRING)
300 return 0;
301
302 QWidget * frame = createLabelFrame(toolbar_item, parent);
303
304 ApplyLineEdit * strEdit = new ApplyLineEdit(toolbar_item->defvalue, frame);
305 strEdit->setToolTip(toolbar_item->tooltip);
306 strEdit->setRegEx(toolbar_item->regex);
307 strEdit->setEmptyAllowed(toolbar_item->is_required);
308 strEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
309
310 #ifdef Q_OS_MAC
311 strEdit->setAttribute(Qt::WA_MacSmallSize, true);
312 #endif
313
314 frame->layout()->addWidget(strEdit);
315
316 connect(strEdit, &ApplyLineEdit::textApplied, this, &AdditionalToolbarWidgetAction::sendTextToCallback);
317
318 ext_toolbar_register_update_cb(item, (ext_toolbar_action_cb)&toolbar_string_cb, (void *)strEdit);
319
320 return frame;
321 }
322
323 static void
toolbar_selector_cb(gpointer item,gpointer item_data,gpointer user_data)324 toolbar_selector_cb(gpointer item, gpointer item_data, gpointer user_data)
325 {
326 if (! item || ! item_data || ! user_data)
327 return;
328
329 QComboBox * comboBox = (QComboBox *)(item_data);
330 ext_toolbar_update_t * update_entry = (ext_toolbar_update_t *)user_data;
331
332 bool oldState = false;
333
334 if (update_entry->silent)
335 oldState = comboBox->blockSignals(true);
336
337 QStandardItemModel * sourceModel = (QStandardItemModel *)comboBox->model();
338
339 if (update_entry->type == EXT_TOOLBAR_SET_ACTIVE)
340 {
341 bool enableState = GPOINTER_TO_INT(update_entry->user_data) == 1;
342 comboBox->setEnabled(enableState);
343 }
344 else if (update_entry->type != EXT_TOOLBAR_UPDATE_DATA_REMOVE && ! update_entry->user_data)
345 return;
346
347 if (update_entry->type == EXT_TOOLBAR_UPDATE_VALUE)
348 {
349 QString data = QString((gchar *)update_entry->user_data);
350
351 for (int i = 0; i < sourceModel->rowCount(); i++)
352 {
353 QStandardItem * dataValue = ((QStandardItemModel *)sourceModel)->item(i, 0);
354 ext_toolbar_value_t * tbValue = VariantPointer<ext_toolbar_value_t>::asPtr(dataValue->data(Qt::UserRole));
355 if (tbValue && data.compare(QString(tbValue->value)) == 0)
356 {
357 comboBox->setCurrentIndex(i);
358 break;
359 }
360 }
361 }
362 else if (update_entry->type == EXT_TOOLBAR_UPDATE_DATA)
363 {
364 GList * walker = (GList *)update_entry->user_data;
365 if (g_list_length(walker) == 0)
366 return;
367
368 sourceModel->clear();
369
370 while (walker && walker->data)
371 {
372 ext_toolbar_value_t * listvalue = gxx_list_data(ext_toolbar_value_t *, walker);
373
374 QStandardItem * si = new QStandardItem(listvalue->display);
375 si->setData(VariantPointer<ext_toolbar_value_t>::asQVariant(listvalue), Qt::UserRole);
376 sourceModel->appendRow(si);
377
378 walker = gxx_list_next(walker);
379 }
380 }
381 else if (update_entry->type == EXT_TOOLBAR_UPDATE_DATABYINDEX ||
382 update_entry->type == EXT_TOOLBAR_UPDATE_DATA_ADD ||
383 update_entry->type == EXT_TOOLBAR_UPDATE_DATA_REMOVE)
384 {
385 if (! update_entry->data_index)
386 return;
387
388 gchar * idx = (gchar *)update_entry->data_index;
389 gchar * display = (gchar *)update_entry->user_data;
390
391 if (update_entry->type == EXT_TOOLBAR_UPDATE_DATABYINDEX)
392 {
393 for (int i = 0; i < sourceModel->rowCount(); i++)
394 {
395 QStandardItem * dataValue = sourceModel->item(i, 0);
396 ext_toolbar_value_t * entry = VariantPointer<ext_toolbar_value_t>::asPtr(dataValue->data(Qt::UserRole));
397 if (entry && g_strcmp0(entry->value, idx) == 0)
398 {
399 g_free(entry->display);
400 entry->display = g_strdup(display);
401 dataValue->setData(VariantPointer<ext_toolbar_value_t>::asQVariant(entry), Qt::UserRole);
402 dataValue->setText(display);
403 break;
404 }
405 }
406 }
407 else if (update_entry->type == EXT_TOOLBAR_UPDATE_DATA_ADD)
408 {
409 ext_toolbar_value_t * listvalue = g_new0(ext_toolbar_value_t, 1);
410 listvalue->display = g_strdup(display);
411 listvalue->value = g_strdup(idx);
412
413 QStandardItem * si = new QStandardItem(listvalue->display);
414 si->setData(VariantPointer<ext_toolbar_value_t>::asQVariant(listvalue), Qt::UserRole);
415 sourceModel->appendRow(si);
416 }
417 else if (update_entry->type == EXT_TOOLBAR_UPDATE_DATA_REMOVE)
418 {
419 QList<QStandardItem *> entryList = sourceModel->findItems(display);
420 /* Search for index if display did not find anything */
421 if (entryList.size() == 0)
422 entryList = sourceModel->findItems(idx);
423
424 foreach(QStandardItem *entry, entryList)
425 {
426 QModelIndex index = sourceModel->indexFromItem(entry);
427 if (index.isValid())
428 sourceModel->removeRow(index.row());
429 }
430 }
431 }
432
433 if (update_entry->silent)
434 comboBox->blockSignals(oldState);
435
436 }
437
createSelector(ext_toolbar_t * item,QWidget * parent)438 QWidget * AdditionalToolbarWidgetAction::createSelector(ext_toolbar_t * item, QWidget * parent)
439 {
440 if (! item || item->type != EXT_TOOLBAR_ITEM || item->item_type != EXT_TOOLBAR_SELECTOR)
441 return 0;
442
443 if (g_list_length(item->values) == 0)
444 return 0;
445
446 QWidget * frame = createLabelFrame(item, parent);
447
448 QComboBox * myBox = new QComboBox(parent);
449 myBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
450
451 QStandardItemModel * sourceModel = new QStandardItemModel();
452
453 GList * walker = item->values;
454 int selIndex = 0;
455 while (walker && walker->data)
456 {
457 ext_toolbar_value_t * listvalue = gxx_list_data(ext_toolbar_value_t *, walker);
458
459 QStandardItem * si = new QStandardItem(listvalue->display);
460 si->setData(VariantPointer<ext_toolbar_value_t>::asQVariant(listvalue), Qt::UserRole);
461 sourceModel->appendRow(si);
462
463 if (listvalue->is_default)
464 selIndex = sourceModel->rowCount();
465
466 walker = gxx_list_next(walker);
467 }
468
469 myBox->setModel(sourceModel);
470 myBox->setCurrentIndex(selIndex);
471
472 #ifdef Q_OS_MAC
473 myBox->setAttribute(Qt::WA_MacSmallSize, true);
474 #endif
475
476 frame->layout()->addWidget(myBox);
477
478 connect(myBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
479 this, &AdditionalToolbarWidgetAction::onSelectionInWidgetChanged);
480
481 ext_toolbar_register_update_cb(item, (ext_toolbar_action_cb)&toolbar_selector_cb, (void *)myBox);
482
483 return frame;
484 }
485
extractToolbarItemFromObject(QObject * object)486 ext_toolbar_t * AdditionalToolbarWidgetAction::extractToolbarItemFromObject(QObject * object)
487 {
488 QWidget * widget = dynamic_cast<QWidget *>(object);
489 if (! widget)
490 return 0;
491
492 QVariant propValue = widget->property(propertyName);
493
494 /* If property is invalid, look if our parent has this property */
495 if (! propValue.isValid())
496 {
497 QWidget * frame = dynamic_cast<QWidget *>(widget->parent());
498 if (! frame)
499 return 0;
500
501 propValue = frame->property(propertyName);
502 }
503
504 if (! propValue.isValid())
505 return 0;
506
507 return VariantPointer<ext_toolbar_t>::asPtr(propValue);
508 }
509
onButtonClicked()510 void AdditionalToolbarWidgetAction::onButtonClicked()
511 {
512 ext_toolbar_t * item = extractToolbarItemFromObject(sender());
513 if (! item)
514 return;
515
516 item->callback(item, 0, item->user_data);
517 }
518
onCheckBoxChecked(int checkState)519 void AdditionalToolbarWidgetAction::onCheckBoxChecked(int checkState)
520 {
521 ext_toolbar_t * item = extractToolbarItemFromObject(sender());
522 if (! item)
523 return;
524
525 gboolean value = checkState == Qt::Checked ? true : false;
526
527 item->callback(item, &value, item->user_data);
528 }
529
sendTextToCallback()530 void AdditionalToolbarWidgetAction::sendTextToCallback()
531 {
532 ext_toolbar_t * item = extractToolbarItemFromObject(sender());
533 if (! item)
534 return;
535
536 if (item->item_type != EXT_TOOLBAR_STRING)
537 return;
538
539 ApplyLineEdit * editor = dynamic_cast<ApplyLineEdit *>(sender());
540 if (! editor)
541 {
542 /* Called from button, searching for acompanying line edit */
543 QWidget * parent = dynamic_cast<QWidget *>(sender()->parent());
544 if (parent)
545 {
546 QList<ApplyLineEdit *> children = parent->findChildren<ApplyLineEdit *>();
547 if (children.count() >= 0)
548 editor = children.at(0);
549 }
550 }
551
552 if (editor)
553 item->callback(item, qstring_strdup(editor->text()), item->user_data);
554 }
555
onSelectionInWidgetChanged(int idx)556 void AdditionalToolbarWidgetAction::onSelectionInWidgetChanged(int idx)
557 {
558 QComboBox * editor = dynamic_cast<QComboBox *>(sender());
559 ext_toolbar_t * item = extractToolbarItemFromObject(editor);
560 if (! item || item->item_type != EXT_TOOLBAR_SELECTOR)
561 return;
562
563 QStandardItemModel * sourceModel = (QStandardItemModel *) editor->model();
564 if (sourceModel->rowCount() <= idx)
565 return;
566
567 QModelIndex mdIdx = sourceModel->index(idx, 0);
568 QVariant dataSet = sourceModel->data(mdIdx, Qt::UserRole);
569 if (dataSet.isValid())
570 {
571 ext_toolbar_value_t * value_entry = VariantPointer<ext_toolbar_value_t>::asPtr(dataSet);
572 item->callback(item, value_entry, item->user_data);
573 }
574 }
575