1 /* capture_options_dialog.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 "capture_options_dialog.h"
15 #include <ui/qt/widgets/capture_filter_combo.h>
16 #include <ui_capture_options_dialog.h>
17 #include "compiled_filter_output.h"
18 #include "manage_interfaces_dialog.h"
19
20 #include "wireshark_application.h"
21
22 #ifdef HAVE_LIBPCAP
23
24 #include <QAbstractItemModel>
25 #include <QMessageBox>
26 #include <QTimer>
27
28 #include "ringbuffer.h"
29 #include "ui/capture_ui_utils.h"
30 #include "ui/capture_globals.h"
31 #include "ui/iface_lists.h"
32 #include "ui/last_open_dir.h"
33
34 #include "ui/ws_ui_util.h"
35 #include "ui/util.h"
36 #include <wsutil/utf8_entities.h>
37 #include "ui/preference_utils.h"
38
39 #include <cstdio>
40 #include <epan/prefs.h>
41 #include <epan/prefs-int.h>
42 #include <epan/addr_resolv.h>
43 #include <wsutil/filesystem.h>
44
45 #include <wiretap/wtap.h>
46
47 #include <ui/qt/utils/qt_ui_utils.h>
48 #include <ui/qt/models/sparkline_delegate.h>
49 #include "ui/qt/widgets/wireshark_file_dialog.h"
50
51 // To do:
52 // - Set a size hint for item delegates.
53 // - Make promiscuous and monitor mode checkboxes.
54 // - Fix InterfaceTreeDelegate method names.
55 // - You can edit filters via the main CaptureFilterCombo and via each
56 // individual interface row. We should probably do one or the other.
57
58 const int stat_update_interval_ = 1000; // ms
59
60 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
61 #define SHOW_BUFFER_COLUMN 1
62 #endif
63
64 #if defined(HAVE_PCAP_CREATE)
65 #define SHOW_MONITOR_COLUMN 1
66 #endif
67
68 /*
69 * Symbolic names for column indices.
70 */
71 enum
72 {
73 col_interface_ = 0,
74 col_traffic_,
75 col_link_,
76 col_pmode_,
77 col_snaplen_,
78 col_buffer_,
79 col_monitor_,
80 col_filter_,
81 col_num_columns_
82 };
83
find_device_by_if_name(const QString & interface_name)84 static interface_t *find_device_by_if_name(const QString &interface_name)
85 {
86 interface_t *device;
87 guint i;
88 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
89 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
90 if (!interface_name.compare(device->display_name) && !device->hidden && device->type != IF_PIPE) {
91 return device;
92 }
93 }
94 return NULL;
95 }
96
97 class InterfaceTreeWidgetItem : public QTreeWidgetItem
98 {
99 public:
InterfaceTreeWidgetItem(QTreeWidget * tree)100 InterfaceTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
101 bool operator< (const QTreeWidgetItem &other) const;
102 QVariant data(int column, int role) const;
103 void setData(int column, int role, const QVariant &value);
104 QList<int> points;
105
updateInterfaceColumns(interface_t * device)106 void updateInterfaceColumns(interface_t *device)
107 {
108 if (!device) return;
109
110 QString default_str = QObject::tr("default");
111
112 // XXX - this is duplicated in InterfaceTreeModel::data;
113 // it should be done in common code somewhere.
114 QString linkname;
115 if (device->active_dlt == -1)
116 linkname = "Unknown";
117 else {
118 linkname = QObject::tr("DLT %1").arg(device->active_dlt);
119 for (GList *list = device->links; list != NULL; list = gxx_list_next(list)) {
120 link_row *linkr = gxx_list_data(link_row *, list);
121 if (linkr->dlt == device->active_dlt) {
122 linkname = linkr->name;
123 break;
124 }
125 }
126 }
127 setText(col_link_, linkname);
128
129 if (device->if_info.type == IF_EXTCAP) {
130 /* extcap interfaces does not have this settings */
131 setApplicable(col_pmode_, false);
132
133 setApplicable(col_snaplen_, false);
134 #ifdef SHOW_BUFFER_COLUMN
135 setApplicable(col_buffer_, false);
136 #endif
137 } else {
138 setApplicable(col_pmode_, true);
139 setCheckState(col_pmode_, device->pmode ? Qt::Checked : Qt::Unchecked);
140
141 QString snaplen_string = device->has_snaplen ? QString::number(device->snaplen) : default_str;
142 setText(col_snaplen_, snaplen_string);
143 #ifdef SHOW_BUFFER_COLUMN
144 setText(col_buffer_, QString::number(device->buffer));
145 #endif
146 }
147 setText(col_filter_, device->cfilter);
148
149 #ifdef SHOW_MONITOR_COLUMN
150 if (device->monitor_mode_supported) {
151 setApplicable(col_monitor_, true);
152 setCheckState(col_monitor_, device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked);
153 } else {
154 setApplicable(col_monitor_, false);
155 }
156 #endif
157 }
158
setApplicable(int column,bool applicable=false)159 void setApplicable(int column, bool applicable = false) {
160 QPalette palette = wsApp->palette();
161
162 if (applicable) {
163 setText(column, QString());
164 } else {
165 setData(column, Qt::CheckStateRole, QVariant());
166 palette.setCurrentColorGroup(QPalette::Disabled);
167 setText(column, UTF8_EM_DASH);
168 }
169 setForeground(column, palette.text().color());
170 }
171
172 };
173
CaptureOptionsDialog(QWidget * parent)174 CaptureOptionsDialog::CaptureOptionsDialog(QWidget *parent) :
175 GeometryStateDialog(parent),
176 ui(new Ui::CaptureOptionsDialog)
177 {
178 ui->setupUi(this);
179 loadGeometry();
180 setWindowTitle(wsApp->windowTitleString(tr("Capture Options")));
181
182 stat_timer_ = NULL;
183 stat_cache_ = NULL;
184
185 ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start"));
186
187 // Start out with the list *not* sorted, so they show up in the order
188 // in which they were provided
189 ui->interfaceTree->sortByColumn(-1, Qt::AscendingOrder);
190 ui->interfaceTree->setItemDelegateForColumn(col_interface_, &interface_item_delegate_);
191 ui->interfaceTree->setItemDelegateForColumn(col_traffic_, new SparkLineDelegate(this));
192 ui->interfaceTree->setItemDelegateForColumn(col_link_, &interface_item_delegate_);
193
194 ui->interfaceTree->setItemDelegateForColumn(col_snaplen_, &interface_item_delegate_);
195 #ifdef SHOW_BUFFER_COLUMN
196 ui->interfaceTree->setItemDelegateForColumn(col_buffer_, &interface_item_delegate_);
197 #else
198 ui->interfaceTree->setColumnHidden(col_buffer_, true);
199 #endif
200 #ifndef SHOW_MONITOR_COLUMN
201 ui->interfaceTree->setColumnHidden(col_monitor_, true);
202 #endif
203 ui->interfaceTree->setItemDelegateForColumn(col_filter_, &interface_item_delegate_);
204
205 interface_item_delegate_.setTree(ui->interfaceTree);
206
207 ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
208
209 ui->rbCompressionNone->setChecked(true);
210
211 // Changes in interface selections or capture filters should be propagated
212 // to the main welcome screen where they will be applied to the global
213 // capture options.
214 connect(this, SIGNAL(interfacesChanged()), ui->captureFilterComboBox, SIGNAL(interfacesChanged()));
215 connect(ui->captureFilterComboBox, SIGNAL(captureFilterSyntaxChanged(bool)), this, SLOT(updateWidgets()));
216 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
217 this, SLOT(filterEdited()));
218 connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
219 this, SIGNAL(captureFilterTextEdited(QString)));
220 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
221 ui->captureFilterComboBox->lineEdit(), SLOT(setText(QString)));
222 connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
223 this, SIGNAL(captureFilterTextEdited(QString)));
224 connect(this, SIGNAL(ifsChanged()), this, SLOT(refreshInterfaceList()));
225 connect(wsApp, SIGNAL(localInterfaceListChanged()), this, SLOT(updateLocalInterfaces()));
226 connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
227
228 updateWidgets();
229 }
230
231 /* Update global device selections based on the TreeWidget selection. */
updateGlobalDeviceSelections()232 void CaptureOptionsDialog::updateGlobalDeviceSelections()
233 {
234 #ifdef HAVE_LIBPCAP
235 QTreeWidgetItemIterator iter(ui->interfaceTree);
236
237 global_capture_opts.num_selected = 0;
238
239 while (*iter) {
240 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
241 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
242 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
243 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
244 if ((*iter)->isSelected()) {
245 device->selected = TRUE;
246 global_capture_opts.num_selected++;
247 } else {
248 device->selected = FALSE;
249 }
250 break;
251 }
252 }
253 ++iter;
254 }
255 #endif
256 }
257
258 /* Update TreeWidget selection based on global device selections. */
updateFromGlobalDeviceSelections()259 void CaptureOptionsDialog::updateFromGlobalDeviceSelections()
260 {
261 #ifdef HAVE_LIBPCAP
262 QTreeWidgetItemIterator iter(ui->interfaceTree);
263
264 // Prevent recursive interface interfaceSelected signals
265 ui->interfaceTree->blockSignals(true);
266
267 while (*iter) {
268 QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value<QString>();
269 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
270 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
271 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
272 if ((bool)device->selected != (*iter)->isSelected()) {
273 (*iter)->setSelected(device->selected);
274 }
275 break;
276 }
277 }
278 ++iter;
279 }
280
281 ui->interfaceTree->blockSignals(false);
282 #endif
283 }
284
interfaceSelected()285 void CaptureOptionsDialog::interfaceSelected()
286 {
287 if (sender() == ui->interfaceTree) {
288 // Local changes, propagate our changes
289 updateGlobalDeviceSelections();
290 emit interfacesChanged();
291 } else {
292 // Changes from the welcome screen, adjust to its state.
293 updateFromGlobalDeviceSelections();
294 }
295
296 updateSelectedFilter();
297
298 updateWidgets();
299 }
300
filterEdited()301 void CaptureOptionsDialog::filterEdited()
302 {
303 QList<QTreeWidgetItem*> si = ui->interfaceTree->selectedItems();
304
305 foreach (QTreeWidgetItem *ti, si) {
306 ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text());
307 }
308
309 if (si.count() > 0) {
310 QModelIndex col_filter_idx = ui->interfaceTree->model()->index(ui->interfaceTree->indexOfTopLevelItem(si[0]), col_filter_);
311 ui->interfaceTree->scrollTo(col_filter_idx);
312 }
313 }
314
updateWidgets()315 void CaptureOptionsDialog::updateWidgets()
316 {
317 SyntaxLineEdit *sle = qobject_cast<SyntaxLineEdit *>(ui->captureFilterComboBox->lineEdit());
318 if (!sle) {
319 return;
320 }
321
322 bool can_capture = false;
323
324 if (ui->interfaceTree->selectedItems().count() > 0 && sle->syntaxState() != SyntaxLineEdit::Invalid) {
325 can_capture = true;
326 }
327
328 ui->compileBPF->setEnabled(can_capture);
329 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(can_capture);
330 }
331
~CaptureOptionsDialog()332 CaptureOptionsDialog::~CaptureOptionsDialog()
333 {
334 delete ui;
335 }
336
setTab(int idx)337 void CaptureOptionsDialog::setTab(int idx)
338 {
339 ui->tabWidget->setCurrentIndex(idx);
340 }
341
on_capturePromModeCheckBox_toggled(bool checked)342 void CaptureOptionsDialog::on_capturePromModeCheckBox_toggled(bool checked)
343 {
344 interface_t *device;
345 prefs.capture_prom_mode = checked;
346 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
347 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(ui->interfaceTree->topLevelItem(row));
348 if (!ti) continue;
349
350 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
351 device = getDeviceByName(device_name);
352 if (!device) continue;
353 device->pmode = checked;
354 ti->updateInterfaceColumns(device);
355 }
356 }
357
browseButtonClicked()358 void CaptureOptionsDialog::browseButtonClicked()
359 {
360 char *open_dir = NULL;
361
362 switch (prefs.gui_fileopen_style) {
363
364 case FO_STYLE_LAST_OPENED:
365 open_dir = get_last_open_dir();
366 break;
367
368 case FO_STYLE_SPECIFIED:
369 if (prefs.gui_fileopen_dir[0] != '\0')
370 open_dir = prefs.gui_fileopen_dir;
371 break;
372 }
373 QString file_name = WiresharkFileDialog::getSaveFileName(this, tr("Specify a Capture File"), open_dir);
374 ui->filenameLineEdit->setText(file_name);
375 }
376
interfaceItemChanged(QTreeWidgetItem * item,int column)377 void CaptureOptionsDialog::interfaceItemChanged(QTreeWidgetItem *item, int column)
378 {
379 QWidget* editor = ui->interfaceTree->indexWidget(ui->interfaceTree->currentIndex());
380 if (editor) {
381 ui->interfaceTree->closePersistentEditor(item, ui->interfaceTree->currentColumn());
382 }
383
384 InterfaceTreeWidgetItem *ti = dynamic_cast<InterfaceTreeWidgetItem *>(item);
385 if (!ti) return;
386
387 interface_t *device;
388 QString interface_name = ti->text(col_interface_);
389 device = find_device_by_if_name(interface_name);
390 if (!device) return;
391
392 switch(column) {
393
394 case col_pmode_:
395 device->pmode = item->checkState(col_pmode_) == Qt::Checked ? TRUE : FALSE;
396 ti->updateInterfaceColumns(device);
397 break;
398
399 #ifdef SHOW_MONITOR_COLUMN
400 case col_monitor_:
401 {
402 gboolean monitor_mode = FALSE;
403 if (ti->checkState(col_monitor_) == Qt::Checked) monitor_mode = TRUE;
404
405 if_capabilities_t *caps;
406 char *auth_str = NULL;
407 QString active_dlt_name;
408
409 set_active_dlt(device, global_capture_opts.default_options.linktype);
410
411 #ifdef HAVE_PCAP_REMOTE
412 if (device->remote_opts.remote_host_opts.auth_type == CAPTURE_AUTH_PWD) {
413 auth_str = g_strdup_printf("%s:%s", device->remote_opts.remote_host_opts.auth_username,
414 device->remote_opts.remote_host_opts.auth_password);
415 }
416 #endif
417 caps = capture_get_if_capabilities(device->name, monitor_mode, auth_str, NULL, NULL, main_window_update);
418 g_free(auth_str);
419
420 if (caps != Q_NULLPTR) {
421
422 for (int i = static_cast<int>(g_list_length(device->links)) - 1; i >= 0; i--) {
423 GList* rem = g_list_nth(device->links, static_cast<guint>(i));
424 device->links = g_list_remove_link(device->links, rem);
425 g_list_free_1(rem);
426 }
427 device->active_dlt = -1;
428 device->monitor_mode_supported = caps->can_set_rfmon;
429 device->monitor_mode_enabled = monitor_mode;
430
431 for (GList *lt_entry = caps->data_link_types; lt_entry != Q_NULLPTR; lt_entry = gxx_list_next(lt_entry)) {
432 link_row *linkr = new link_row();
433 data_link_info_t *data_link_info = gxx_list_data(data_link_info_t *, lt_entry);
434 /*
435 * For link-layer types libpcap/WinPcap/Npcap doesn't know
436 * about, the name will be "DLT n", and the description will
437 * be null.
438 * We mark those as unsupported, and don't allow them to be
439 * used - capture filters won't work on them, for example.
440 */
441 if (data_link_info->description != Q_NULLPTR) {
442 linkr->dlt = data_link_info->dlt;
443 if (active_dlt_name.isEmpty()) {
444 device->active_dlt = data_link_info->dlt;
445 active_dlt_name = data_link_info->description;
446 }
447 linkr->name = g_strdup(data_link_info->description);
448 } else {
449 gchar *str;
450 /* XXX - should we just omit them? */
451 str = g_strdup_printf("%s (not supported)", data_link_info->name);
452 linkr->dlt = -1;
453 linkr->name = g_strdup(str);
454 g_free(str);
455 }
456 device->links = g_list_append(device->links, linkr);
457 }
458 free_if_capabilities(caps);
459 } else {
460 /* We don't know whether this supports monitor mode or not;
461 don't ask for monitor mode. */
462 device->monitor_mode_enabled = FALSE;
463 device->monitor_mode_supported = FALSE;
464 }
465
466 ti->updateInterfaceColumns(device);
467
468 break;
469 }
470 #endif // SHOW_MONITOR_COLUMN
471 default:
472 break;
473 }
474 }
475
on_gbStopCaptureAuto_toggled(bool checked)476 void CaptureOptionsDialog::on_gbStopCaptureAuto_toggled(bool checked)
477 {
478 global_capture_opts.has_file_interval = checked;
479 }
480
on_gbNewFileAuto_toggled(bool checked)481 void CaptureOptionsDialog::on_gbNewFileAuto_toggled(bool checked)
482 {
483 global_capture_opts.multi_files_on = checked;
484 ui->stopMBCheckBox->setEnabled(checked?false:true);
485 ui->stopMBSpinBox->setEnabled(checked?false:true);
486 ui->stopMBComboBox->setEnabled(checked?false:true);
487 ui->gbCompression->setEnabled(checked);
488 ui->rbCompressionNone->setEnabled(checked);
489 ui->rbCompressionGzip->setEnabled(checked);
490 }
491
on_cbUpdatePacketsRT_toggled(bool checked)492 void CaptureOptionsDialog::on_cbUpdatePacketsRT_toggled(bool checked)
493 {
494 global_capture_opts.real_time_mode = checked;
495 }
496
on_cbAutoScroll_toggled(bool checked)497 void CaptureOptionsDialog::on_cbAutoScroll_toggled(bool checked)
498 {
499 auto_scroll_live = checked;
500 }
501
on_cbExtraCaptureInfo_toggled(bool checked)502 void CaptureOptionsDialog::on_cbExtraCaptureInfo_toggled(bool checked)
503 {
504 global_capture_opts.show_info = checked;
505 }
506
on_cbResolveMacAddresses_toggled(bool checked)507 void CaptureOptionsDialog::on_cbResolveMacAddresses_toggled(bool checked)
508 {
509 gbl_resolv_flags.mac_name = checked;
510 }
511
on_cbResolveNetworkNames_toggled(bool checked)512 void CaptureOptionsDialog::on_cbResolveNetworkNames_toggled(bool checked)
513 {
514 gbl_resolv_flags.network_name = checked;
515 }
516
on_cbResolveTransportNames_toggled(bool checked)517 void CaptureOptionsDialog::on_cbResolveTransportNames_toggled(bool checked)
518 {
519 gbl_resolv_flags.transport_name = checked;
520 }
521
on_buttonBox_accepted()522 void CaptureOptionsDialog::on_buttonBox_accepted()
523 {
524 if (saveOptionsToPreferences()) {
525 emit setFilterValid(true, ui->captureFilterComboBox->lineEdit()->text());
526 accept();
527 }
528 }
529
530 // Not sure why we have to do this manually.
on_buttonBox_rejected()531 void CaptureOptionsDialog::on_buttonBox_rejected()
532 {
533 if (saveOptionsToPreferences()) {
534 reject();
535 }
536 }
537
on_buttonBox_helpRequested()538 void CaptureOptionsDialog::on_buttonBox_helpRequested()
539 {
540 // Probably the wrong URL.
541 wsApp->helpTopicAction(HELP_CAPTURE_OPTIONS_DIALOG);
542 }
543
updateInterfaces()544 void CaptureOptionsDialog::updateInterfaces()
545 {
546 if (prefs.capture_pcap_ng) {
547 ui->rbPcapng->setChecked(true);
548 } else {
549 ui->rbPcap->setChecked(true);
550 }
551 ui->capturePromModeCheckBox->setChecked(prefs.capture_prom_mode);
552
553 if (global_capture_opts.saving_to_file) {
554 ui->filenameLineEdit->setText(QString(global_capture_opts.orig_save_file));
555 }
556
557 ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on);
558 ui->PktCheckBox->setChecked(global_capture_opts.has_file_packets);
559 if (global_capture_opts.has_file_packets) {
560 ui->PktSpinBox->setValue(global_capture_opts.file_packets);
561 }
562 ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
563 if (global_capture_opts.has_autostop_filesize) {
564 int value = global_capture_opts.autostop_filesize;
565 if (value > 1000000) {
566 if (global_capture_opts.multi_files_on) {
567 ui->MBSpinBox->setValue(value / 1000000);
568 ui->MBComboBox->setCurrentIndex(2);
569 } else {
570 ui->stopMBCheckBox->setChecked(true);
571 ui->stopMBSpinBox->setValue(value / 1000000);
572 ui->stopMBComboBox->setCurrentIndex(2);
573 }
574 } else if (value > 1000 && value % 1000 == 0) {
575 if (global_capture_opts.multi_files_on) {
576 ui->MBSpinBox->setValue(value / 1000);
577 ui->MBComboBox->setCurrentIndex(1);
578 } else {
579 ui->stopMBCheckBox->setChecked(true);
580 ui->stopMBSpinBox->setValue(value / 1000);
581 ui->stopMBComboBox->setCurrentIndex(1);
582 }
583 } else {
584 if (global_capture_opts.multi_files_on) {
585 ui->MBSpinBox->setValue(value);
586 ui->MBComboBox->setCurrentIndex(0);
587 } else {
588 ui->stopMBCheckBox->setChecked(true);
589 ui->stopMBSpinBox->setValue(value);
590 ui->stopMBComboBox->setCurrentIndex(0);
591 }
592 }
593 }
594
595 ui->SecsCheckBox->setChecked(global_capture_opts.has_file_duration);
596 if (global_capture_opts.has_file_duration) {
597 int value = global_capture_opts.file_duration;
598 if (value > 3600 && value % 3600 == 0) {
599 ui->SecsSpinBox->setValue(value / 3600);
600 ui->SecsComboBox->setCurrentIndex(2);
601 } else if (value > 60 && value % 60 == 0) {
602 ui->SecsSpinBox->setValue(value / 60);
603 ui->SecsComboBox->setCurrentIndex(1);
604 } else {
605 ui->SecsSpinBox->setValue(value);
606 ui->SecsComboBox->setCurrentIndex(0);
607 }
608 }
609
610 ui->IntervalSecsCheckBox->setChecked(global_capture_opts.has_file_interval);
611 if (global_capture_opts.has_file_interval) {
612 int value = global_capture_opts.file_interval;
613 if (value > 3600 && value % 3600 == 0) {
614 ui->IntervalSecsSpinBox->setValue(value / 3600);
615 ui->IntervalSecsComboBox->setCurrentIndex(2);
616 } else if (value > 60 && value % 60 == 0) {
617 ui->IntervalSecsSpinBox->setValue(value / 60);
618 ui->IntervalSecsComboBox->setCurrentIndex(1);
619 } else {
620 ui->IntervalSecsSpinBox->setValue(value);
621 ui->IntervalSecsComboBox->setCurrentIndex(0);
622 }
623 }
624
625 if (global_capture_opts.has_ring_num_files) {
626 ui->RbSpinBox->setValue(global_capture_opts.ring_num_files);
627 ui->RbCheckBox->setCheckState(Qt::Checked);
628 }
629
630 if (global_capture_opts.has_autostop_duration) {
631 ui->stopSecsCheckBox->setChecked(true);
632 int value = global_capture_opts.file_interval;
633 if (value > 3600 && value % 3600 == 0) {
634 ui->stopSecsSpinBox->setValue(value / 3600);
635 ui->stopSecsComboBox->setCurrentIndex(2);
636 } else if (value > 60 && value % 60 == 0) {
637 ui->stopSecsSpinBox->setValue(value / 60);
638 ui->stopSecsComboBox->setCurrentIndex(1);
639 } else {
640 ui->stopSecsSpinBox->setValue(value);
641 ui->stopSecsComboBox->setCurrentIndex(0);
642 }
643 }
644
645 if (global_capture_opts.has_autostop_packets) {
646 ui->stopPktCheckBox->setChecked(true);
647 ui->stopPktSpinBox->setValue(global_capture_opts.autostop_packets);
648 }
649
650 if (global_capture_opts.has_autostop_files) {
651 ui->stopFilesCheckBox->setChecked(true);
652 ui->stopFilesSpinBox->setValue(global_capture_opts.autostop_files);
653 }
654
655 ui->cbUpdatePacketsRT->setChecked(global_capture_opts.real_time_mode);
656 ui->cbAutoScroll->setChecked(true);
657 ui->cbExtraCaptureInfo->setChecked(global_capture_opts.show_info);
658
659 ui->cbResolveMacAddresses->setChecked(gbl_resolv_flags.mac_name);
660 ui->cbResolveNetworkNames->setChecked(gbl_resolv_flags.network_name);
661 ui->cbResolveTransportNames->setChecked(gbl_resolv_flags.transport_name);
662
663 // Rebuild the interface list without disturbing the main welcome screen.
664 disconnect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
665 ui->interfaceTree->clear();
666
667 #ifdef SHOW_BUFFER_COLUMN
668 gint buffer;
669 #endif
670 gint snaplen;
671 gboolean hassnap, pmode;
672 QList<QTreeWidgetItem *> selected_interfaces;
673
674 disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
675
676 if (global_capture_opts.all_ifaces->len > 0) {
677 interface_t *device;
678
679 for (guint device_idx = 0; device_idx < global_capture_opts.all_ifaces->len; device_idx++) {
680 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
681
682 /* Continue if capture device is hidden */
683 if (device->hidden) {
684 continue;
685 }
686
687 // Traffic sparklines
688 InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree);
689 ti->setFlags(ti->flags() | Qt::ItemIsEditable);
690 ti->setData(col_interface_, Qt::UserRole, QString(device->name));
691 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(ti->points));
692
693 ti->setText(col_interface_, device->display_name);
694 if (device->no_addresses > 0) {
695 QString addr_str = tr("%1: %2").arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device->addresses);
696 QTreeWidgetItem *addr_ti = new QTreeWidgetItem(ti);
697
698 addr_str.replace('\n', ", ");
699 addr_ti->setText(0, addr_str);
700 addr_ti->setFlags(addr_ti->flags() ^ Qt::ItemIsSelectable);
701 addr_ti->setFirstColumnSpanned(true);
702 addr_ti->setToolTip(col_interface_, QString("<span>%1</span>").arg(addr_str));
703 ti->setToolTip(col_interface_, QString("<span>%1</span>").arg(addr_str));
704 } else {
705 ti->setToolTip(col_interface_, tr("no addresses"));
706 }
707
708 if (capture_dev_user_pmode_find(device->name, &pmode)) {
709 device->pmode = pmode;
710 }
711 if (capture_dev_user_snaplen_find(device->name, &hassnap, &snaplen)) {
712 /* Default snap length set in preferences */
713 device->snaplen = snaplen;
714 device->has_snaplen = snaplen == WTAP_MAX_PACKET_SIZE_STANDARD ? FALSE : hassnap;
715 } else {
716 /* No preferences set yet, use default values */
717 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
718 device->has_snaplen = FALSE;
719 }
720
721 #ifdef SHOW_BUFFER_COLUMN
722 if (capture_dev_user_buffersize_find(device->name) != -1) {
723 buffer = capture_dev_user_buffersize_find(device->name);
724 device->buffer = buffer;
725 } else {
726 device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
727 }
728 #endif
729 ti->updateInterfaceColumns(device);
730
731 if (device->selected) {
732 selected_interfaces << ti;
733 }
734 }
735 }
736
737 connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
738
739 foreach (QTreeWidgetItem *ti, selected_interfaces) {
740 ti->setSelected(true);
741 }
742 connect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
743 updateSelectedFilter();
744
745 // Manually or automatically size some columns as needed.
746 int one_em = fontMetrics().height();
747 for (int col = 0; col < ui->interfaceTree->topLevelItemCount(); col++) {
748 switch (col) {
749 case col_pmode_:
750 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
751 break;
752 case col_snaplen_:
753 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
754 break;
755 case col_buffer_:
756 ui->interfaceTree->setColumnWidth(col, one_em * 4.25);
757 break;
758 case col_monitor_:
759 ui->interfaceTree->setColumnWidth(col, one_em * 3.25);
760 break;
761 default:
762 ui->interfaceTree->resizeColumnToContents(col);
763 }
764
765 }
766
767 updateWidgets();
768
769 if (!stat_timer_) {
770 updateStatistics();
771 stat_timer_ = new QTimer(this);
772 connect(stat_timer_, SIGNAL(timeout()), this, SLOT(updateStatistics()));
773 stat_timer_->start(stat_update_interval_);
774 }
775 }
776
showEvent(QShowEvent *)777 void CaptureOptionsDialog::showEvent(QShowEvent *)
778 {
779 updateInterfaces();
780 }
781
refreshInterfaceList()782 void CaptureOptionsDialog::refreshInterfaceList()
783 {
784 updateInterfaces();
785 emit interfaceListChanged();
786 }
787
updateLocalInterfaces()788 void CaptureOptionsDialog::updateLocalInterfaces()
789 {
790 updateInterfaces();
791 }
792
updateStatistics(void)793 void CaptureOptionsDialog::updateStatistics(void)
794 {
795 interface_t *device;
796
797 disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
798 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
799
800 for (guint if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++) {
801 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
802 if (!ti) {
803 continue;
804 }
805 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx);
806 QString device_name = ti->text(col_interface_);
807 if (device_name.compare(device->display_name) || device->hidden || device->type == IF_PIPE) {
808 continue;
809 }
810 QList<int> points = ti->data(col_traffic_, Qt::UserRole).value<QList<int> >();
811 points.append(device->packet_diff);
812 ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(points));
813 }
814 }
815 connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int)));
816 ui->interfaceTree->viewport()->update();
817 }
818
on_compileBPF_clicked()819 void CaptureOptionsDialog::on_compileBPF_clicked()
820 {
821 QStringList interfaces;
822 foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems()) {
823 interfaces.append(ti->text(col_interface_));
824 }
825
826 QString filter = ui->captureFilterComboBox->currentText();
827 CompiledFilterOutput *cfo = new CompiledFilterOutput(this, interfaces, filter);
828
829 cfo->show();
830 }
831
saveOptionsToPreferences()832 bool CaptureOptionsDialog::saveOptionsToPreferences()
833 {
834 if (ui->rbPcapng->isChecked()) {
835 global_capture_opts.use_pcapng = true;
836 prefs.capture_pcap_ng = true;
837 } else {
838 global_capture_opts.use_pcapng = false;
839 prefs.capture_pcap_ng = false;
840 }
841
842 g_free(global_capture_opts.save_file);
843 g_free(global_capture_opts.orig_save_file);
844
845 QString filename = ui->filenameLineEdit->text();
846 if (filename.length() > 0) {
847 /* User specified a file to which the capture should be written. */
848 global_capture_opts.saving_to_file = true;
849 global_capture_opts.save_file = qstring_strdup(filename);
850 global_capture_opts.orig_save_file = qstring_strdup(filename);
851 /* Save the directory name for future file dialogs. */
852 set_last_open_dir(get_dirname(filename.toUtf8().data()));
853 } else {
854 /* User didn't specify a file; save to a temporary file. */
855 global_capture_opts.saving_to_file = false;
856 global_capture_opts.save_file = NULL;
857 global_capture_opts.orig_save_file = NULL;
858 }
859
860 global_capture_opts.has_ring_num_files = ui->RbCheckBox->isChecked();
861
862 if (global_capture_opts.has_ring_num_files) {
863 global_capture_opts.ring_num_files = ui->RbSpinBox->value();
864 if (global_capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
865 global_capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
866 #if RINGBUFFER_MIN_NUM_FILES > 0
867 else if (global_capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
868 global_capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
869 #endif
870 }
871 global_capture_opts.multi_files_on = ui->gbNewFileAuto->isChecked();
872 if (global_capture_opts.multi_files_on) {
873 global_capture_opts.has_file_interval = ui->SecsCheckBox->isChecked();
874 if (global_capture_opts.has_file_interval) {
875 global_capture_opts.file_interval = ui->SecsSpinBox->value();
876 int index = ui->SecsComboBox->currentIndex();
877 switch (index) {
878 case 1: global_capture_opts.file_interval *= 60;
879 break;
880 case 2: global_capture_opts.file_interval *= 3600;
881 break;
882 }
883 }
884 global_capture_opts.has_file_packets = ui->PktCheckBox->isChecked();
885 if (global_capture_opts.has_file_packets) {
886 global_capture_opts.file_packets = ui->PktSpinBox->value();
887 }
888 global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
889 if (global_capture_opts.has_autostop_filesize) {
890 global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
891 int index = ui->MBComboBox->currentIndex();
892 switch (index) {
893 case 1: if (global_capture_opts.autostop_filesize > 2000) {
894 QMessageBox::warning(this, tr("Error"),
895 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB."));
896 return false;
897 } else {
898 global_capture_opts.autostop_filesize *= 1000;
899 }
900 break;
901 case 2: if (global_capture_opts.autostop_filesize > 2) {
902 QMessageBox::warning(this, tr("Error"),
903 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB."));
904 return false;
905 } else {
906 global_capture_opts.autostop_filesize *= 1000000;
907 }
908 break;
909 }
910 }
911 /* test if the settings are ok for a ringbuffer */
912 if (global_capture_opts.save_file == NULL) {
913 QMessageBox::warning(this, tr("Error"),
914 tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files."));
915 return false;
916 } else if (!global_capture_opts.has_autostop_filesize &&
917 !global_capture_opts.has_file_interval &&
918 !global_capture_opts.has_file_duration &&
919 !global_capture_opts.has_file_packets) {
920 QMessageBox::warning(this, tr("Error"),
921 tr("Multiple files: No file limit given. You must specify a file size, interval, or number of packets for each file."));
922 g_free(global_capture_opts.save_file);
923 global_capture_opts.save_file = NULL;
924 return false;
925 }
926 } else {
927 global_capture_opts.has_autostop_filesize = ui->stopMBCheckBox->isChecked();
928 if (global_capture_opts.has_autostop_filesize) {
929 global_capture_opts.autostop_filesize = ui->stopMBSpinBox->value();
930 int index = ui->stopMBComboBox->currentIndex();
931 switch (index) {
932 case 1: if (global_capture_opts.autostop_filesize > 2000) {
933 QMessageBox::warning(this, tr("Error"),
934 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB."));
935 return false;
936 } else {
937 global_capture_opts.autostop_filesize *= 1000;
938 }
939 break;
940 case 2: if (global_capture_opts.autostop_filesize > 2) {
941 QMessageBox::warning(this, tr("Error"),
942 tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB."));
943 return false;
944 } else {
945 global_capture_opts.autostop_filesize *= 1000000;
946 }
947 break;
948 }
949 }
950 }
951
952 global_capture_opts.has_autostop_duration = ui->stopSecsCheckBox->isChecked();
953 if (global_capture_opts.has_autostop_duration) {
954 global_capture_opts.autostop_duration = ui->stopSecsSpinBox->value();
955 int index = ui->stopSecsComboBox->currentIndex();
956 switch (index) {
957 case 1: global_capture_opts.autostop_duration *= 60;
958 break;
959 case 2: global_capture_opts.autostop_duration *= 3600;
960 break;
961 }
962 }
963
964 global_capture_opts.has_autostop_packets = ui->stopPktCheckBox->isChecked();
965 if (global_capture_opts.has_autostop_packets) {
966 global_capture_opts.autostop_packets = ui->stopPktSpinBox->value();
967 }
968
969 global_capture_opts.has_autostop_files = ui->stopFilesCheckBox->isChecked();
970 if (global_capture_opts.has_autostop_files) {
971 global_capture_opts.autostop_files = ui->stopFilesSpinBox->value();
972 }
973
974 interface_t *device;
975
976 for (int col = col_link_; col <= col_filter_; col++) {
977 if (ui->interfaceTree->isColumnHidden(col)) {
978 continue;
979 }
980 /* All entries are separated by comma. There is also one before the first interface to be able to identify
981 word boundaries. As 'lo' is part of 'nflog' an exact match is necessary. */
982 switch (col) {
983 case col_link_:
984 {
985 QStringList link_list;
986
987 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
988 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
989 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
990 device = getDeviceByName(device_name);
991 if (!device || device->active_dlt == -1) {
992 continue;
993 }
994 link_list << QString("%1(%2)").arg(device->name).arg(device->active_dlt);
995 }
996 g_free(prefs.capture_devices_linktypes);
997 prefs.capture_devices_linktypes = qstring_strdup(link_list.join(","));
998 break;
999 }
1000 #ifdef SHOW_BUFFER_COLUMN
1001 case col_buffer_:
1002 {
1003 QStringList buffer_size_list;
1004
1005 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1006 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1007 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1008 device = getDeviceByName(device_name);
1009 if (!device || device->buffer == -1) {
1010 continue;
1011 }
1012 buffer_size_list << QString("%1(%2)").arg(device->name).arg(device->buffer);
1013 }
1014 g_free(prefs.capture_devices_buffersize);
1015 prefs.capture_devices_buffersize = qstring_strdup(buffer_size_list.join(","));
1016 break;
1017 }
1018 #endif // HAVE_BUFFER_SETTING
1019 case col_snaplen_:
1020 {
1021 QStringList snaplen_list;
1022
1023 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1024 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1025 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1026 device = getDeviceByName(device_name);
1027 if (!device) continue;
1028 snaplen_list << QString("%1:%2(%3)")
1029 .arg(device->name)
1030 .arg(device->has_snaplen)
1031 .arg(device->has_snaplen ? device->snaplen : WTAP_MAX_PACKET_SIZE_STANDARD);
1032 }
1033 g_free(prefs.capture_devices_snaplen);
1034 prefs.capture_devices_snaplen = qstring_strdup(snaplen_list.join(","));
1035 break;
1036 }
1037 case col_pmode_:
1038 {
1039 QStringList pmode_list;
1040
1041 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1042 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1043 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1044 device = getDeviceByName(device_name);
1045 if (!device || device->pmode == -1) {
1046 continue;
1047 }
1048 pmode_list << QString("%1(%2)").arg(device->name).arg(device->pmode);
1049 }
1050 g_free(prefs.capture_devices_pmode);
1051 prefs.capture_devices_pmode = qstring_strdup(pmode_list.join(","));
1052 break;
1053 }
1054
1055 #ifdef SHOW_MONITOR_COLUMN
1056 case col_monitor_:
1057 {
1058 QStringList monitor_list;
1059
1060 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1061 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1062 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1063 device = getDeviceByName(device_name);
1064 if (!device || !device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) {
1065 continue;
1066 }
1067 monitor_list << device->name;
1068 }
1069 g_free(prefs.capture_devices_monitor_mode);
1070 prefs.capture_devices_monitor_mode = qstring_strdup(monitor_list.join(","));
1071 break;
1072 }
1073 #endif // HAVE_MONITOR_SETTING
1074
1075 #if 0
1076 // The device cfilter should have been applied at this point.
1077 // We shouldn't change it here.
1078 case col_filter_:
1079 {
1080 // XXX Update selected interfaces only?
1081 for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
1082 QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
1083 QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
1084 device = getDeviceByName(device_name);
1085 if (!device) continue;
1086 g_free(device->cfilter);
1087 if (ti->text(col_filter_).isEmpty()) {
1088 device->cfilter = NULL;
1089 } else {
1090 device->cfilter = qstring_strdup(ti->text(col_filter_));
1091 }
1092 }
1093 }
1094 #endif
1095 }
1096 }
1097
1098 g_free(global_capture_opts.compress_type);
1099
1100 if (ui->rbCompressionNone->isChecked() ) {
1101 global_capture_opts.compress_type = NULL;
1102 } else if (ui->rbCompressionGzip->isChecked() ) {
1103 global_capture_opts.compress_type = qstring_strdup("gzip");
1104 } else {
1105 global_capture_opts.compress_type = NULL;
1106 }
1107
1108 prefs_main_write();
1109 return true;
1110 }
1111
updateSelectedFilter()1112 void CaptureOptionsDialog::updateSelectedFilter()
1113 {
1114 // Should match MainWelcome::interfaceSelected.
1115 QPair <const QString, bool> sf_pair = CaptureFilterEdit::getSelectedFilter();
1116 const QString user_filter = sf_pair.first;
1117 bool conflict = sf_pair.second;
1118
1119 if (conflict) {
1120 ui->captureFilterComboBox->lineEdit()->clear();
1121 ui->captureFilterComboBox->setConflict(true);
1122 } else {
1123 ui->captureFilterComboBox->lineEdit()->setText(user_filter);
1124 }
1125 }
1126
on_manageButton_clicked()1127 void CaptureOptionsDialog::on_manageButton_clicked()
1128 {
1129 if (saveOptionsToPreferences()) {
1130 ManageInterfacesDialog *dlg = new ManageInterfacesDialog(this);
1131 dlg->show();
1132 }
1133 }
1134
changeEvent(QEvent * event)1135 void CaptureOptionsDialog::changeEvent(QEvent* event)
1136 {
1137 if (0 != event)
1138 {
1139 switch (event->type())
1140 {
1141 case QEvent::LanguageChange:
1142 ui->retranslateUi(this);
1143 break;
1144 default:
1145 break;
1146 }
1147 }
1148 QDialog::changeEvent(event);
1149 }
1150
getDeviceByName(const QString device_name)1151 interface_t *CaptureOptionsDialog::getDeviceByName(const QString device_name)
1152 {
1153 for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1154 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1155 if (device_name.compare(QString().fromUtf8(device->name)) == 0) {
1156 return device;
1157 }
1158 }
1159 return NULL;
1160 }
1161
1162 //
1163 // InterfaceTreeItem
1164 //
operator <(const QTreeWidgetItem & other) const1165 bool InterfaceTreeWidgetItem::operator< (const QTreeWidgetItem &other) const {
1166 if (treeWidget()->sortColumn() == col_traffic_) {
1167 QList<int> points = data(col_traffic_, Qt::UserRole).value<QList<int> >();
1168 QList<int> other_points = other.data(col_traffic_, Qt::UserRole).value<QList<int> >();
1169 double avg = 0, other_avg = 0;
1170 foreach (int point, points) {
1171 avg += (double) point / points.length();
1172 }
1173 foreach (int point, other_points) {
1174 other_avg += (double) point / other_points.length();
1175 }
1176 return avg < other_avg;
1177 }
1178 return QTreeWidgetItem::operator<(other);
1179 }
1180
data(int column,int role) const1181 QVariant InterfaceTreeWidgetItem::data(int column, int role) const
1182 {
1183 // See setData for the special col_traffic_ treatment.
1184 if (column == col_traffic_ && role == Qt::UserRole) {
1185 return QVariant::fromValue(points);
1186 }
1187
1188 return QTreeWidgetItem::data(column, role);
1189 }
1190
setData(int column,int role,const QVariant & value)1191 void InterfaceTreeWidgetItem::setData(int column, int role, const QVariant &value)
1192 {
1193 // Workaround for closing editors on updates to the points list: normally
1194 // QTreeWidgetItem::setData emits dataChanged when the value (list) changes.
1195 // We could store a pointer to the list, or just have this hack that does
1196 // not emit dataChanged.
1197 if (column == col_traffic_ && role == Qt::UserRole) {
1198 points = value.value<QList<int> >();
1199 return;
1200 }
1201
1202 QTreeWidgetItem::setData(column, role, value);
1203 }
1204
1205 //
1206 // InterfaceTreeDelegate
1207 //
1208
1209 #include <QComboBox>
1210
InterfaceTreeDelegate(QObject * parent)1211 InterfaceTreeDelegate::InterfaceTreeDelegate(QObject *parent)
1212 : QStyledItemDelegate(parent), tree_(NULL)
1213 {
1214 }
1215
1216
~InterfaceTreeDelegate()1217 InterfaceTreeDelegate::~InterfaceTreeDelegate()
1218 {
1219 }
1220
1221
createEditor(QWidget * parent,const QStyleOptionViewItem &,const QModelIndex & idx) const1222 QWidget* InterfaceTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &idx) const
1223 {
1224 QWidget *w = NULL;
1225 #ifdef SHOW_BUFFER_COLUMN
1226 gint buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
1227 #endif
1228 guint snap = WTAP_MAX_PACKET_SIZE_STANDARD;
1229 GList *links = NULL;
1230
1231 if (idx.column() > 1 && idx.data().toString().compare(UTF8_EM_DASH)) {
1232 QTreeWidgetItem *ti = tree_->topLevelItem(idx.row());
1233 QString interface_name = ti->text(col_interface_);
1234 interface_t *device = find_device_by_if_name(interface_name);
1235
1236 if (device) {
1237 #ifdef SHOW_BUFFER_COLUMN
1238 buffer = device->buffer;
1239 #endif
1240 snap = device->snaplen;
1241 links = device->links;
1242 }
1243 switch (idx.column()) {
1244 case col_interface_:
1245 case col_traffic_:
1246 break;
1247 case col_link_:
1248 {
1249 GList *list;
1250 link_row *linkr;
1251 QStringList valid_link_types;
1252
1253 // XXX The GTK+ UI fills in all link types, valid or not. We add
1254 // only the valid ones. If we *do* wish to include invalid link
1255 // types we'll have to jump through the hoops necessary to disable
1256 // QComboBox items.
1257
1258 for (list = links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1259 linkr = gxx_list_data(link_row*, list);
1260 if (linkr->dlt >= 0) {
1261 valid_link_types << linkr->name;
1262 }
1263 }
1264
1265 if (valid_link_types.size() < 2) {
1266 break;
1267 }
1268 QComboBox *cb = new QComboBox(parent);
1269 cb->addItems(valid_link_types);
1270
1271 connect(cb, SIGNAL(currentIndexChanged(QString)), this, SLOT(linkTypeChanged(QString)));
1272 w = (QWidget*) cb;
1273 break;
1274 }
1275 case col_snaplen_:
1276 {
1277 QSpinBox *sb = new QSpinBox(parent);
1278 sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD);
1279 sb->setValue(snap);
1280 sb->setWrapping(true);
1281 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(snapshotLengthChanged(int)));
1282 w = (QWidget*) sb;
1283 break;
1284 }
1285 #ifdef SHOW_BUFFER_COLUMN
1286 case col_buffer_:
1287 {
1288 QSpinBox *sb = new QSpinBox(parent);
1289 sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD);
1290 sb->setValue(buffer);
1291 sb->setWrapping(true);
1292 connect(sb, SIGNAL(valueChanged(int)), this, SLOT(bufferSizeChanged(int)));
1293 w = (QWidget*) sb;
1294 break;
1295 }
1296 #endif
1297 case col_filter_:
1298 {
1299 CaptureFilterCombo *cf = new CaptureFilterCombo(parent, true);
1300 connect(cf->lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString)));
1301 w = (QWidget*) cf;
1302 }
1303 default:
1304 break;
1305 }
1306 }
1307 if (w)
1308 w->setAutoFillBackground(true);
1309 return w;
1310 }
1311
eventFilter(QObject * object,QEvent * event)1312 bool InterfaceTreeDelegate::eventFilter(QObject *object, QEvent *event)
1313 {
1314 QComboBox * comboBox = dynamic_cast<QComboBox*>(object);
1315 if (comboBox) {
1316 if (event->type() == QEvent::MouseButtonRelease) {
1317 comboBox->showPopup();
1318 return true;
1319 }
1320 } else {
1321 return QStyledItemDelegate::eventFilter(object, event);
1322 }
1323 return false;
1324 }
1325
linkTypeChanged(QString selected_link_type)1326 void InterfaceTreeDelegate::linkTypeChanged(QString selected_link_type)
1327 {
1328 GList *list;
1329 link_row *temp;
1330 interface_t *device;
1331
1332 QTreeWidgetItem *ti = tree_->currentItem();
1333 if (!ti) {
1334 return;
1335 }
1336 QString interface_name = ti->text(col_interface_);
1337 device = find_device_by_if_name(interface_name);
1338 if (!device) {
1339 return;
1340 }
1341 for (list = device->links; list != Q_NULLPTR; list = gxx_list_next(list)) {
1342 temp = gxx_list_data(link_row*, list);
1343 if (!selected_link_type.compare(temp->name)) {
1344 device->active_dlt = temp->dlt;
1345 }
1346 }
1347 // XXX We might want to verify that active_dlt is valid at this point.
1348 }
1349
snapshotLengthChanged(int value)1350 void InterfaceTreeDelegate::snapshotLengthChanged(int value)
1351 {
1352 interface_t *device;
1353 QTreeWidgetItem *ti = tree_->currentItem();
1354 if (!ti) {
1355 return;
1356 }
1357 QString interface_name = ti->text(col_interface_);
1358 device = find_device_by_if_name(interface_name);
1359 if (!device) {
1360 return;
1361 }
1362 if (value != WTAP_MAX_PACKET_SIZE_STANDARD) {
1363 device->has_snaplen = true;
1364 device->snaplen = value;
1365 } else {
1366 device->has_snaplen = false;
1367 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
1368 }
1369 }
1370
1371 #ifdef SHOW_BUFFER_COLUMN
bufferSizeChanged(int value)1372 void InterfaceTreeDelegate::bufferSizeChanged(int value)
1373 {
1374 interface_t *device;
1375 QTreeWidgetItem *ti = tree_->currentItem();
1376 if (!ti) {
1377 return;
1378 }
1379 QString interface_name = ti->text(col_interface_);
1380 device = find_device_by_if_name(interface_name);
1381 if (!device) {
1382 return;
1383 }
1384 device->buffer = value;
1385 }
1386 #endif
1387
1388 #endif /* HAVE_LIBPCAP */
1389