From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- ui/qt/capture_options_dialog.cpp | 1534 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1534 insertions(+) create mode 100644 ui/qt/capture_options_dialog.cpp (limited to 'ui/qt/capture_options_dialog.cpp') diff --git a/ui/qt/capture_options_dialog.cpp b/ui/qt/capture_options_dialog.cpp new file mode 100644 index 0000000..a0aed79 --- /dev/null +++ b/ui/qt/capture_options_dialog.cpp @@ -0,0 +1,1534 @@ +/* capture_options_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include "capture_options_dialog.h" +#include +#include +#include "compiled_filter_output.h" +#include "manage_interfaces_dialog.h" + +#include "main_application.h" + +#include "extcap.h" + +#ifdef HAVE_LIBPCAP + +#include +#include +#include + +#include "ringbuffer.h" +#include "ui/capture_ui_utils.h" +#include "ui/capture_globals.h" +#include "ui/iface_lists.h" +#include "ui/file_dialog.h" + +#include "ui/ws_ui_util.h" +#include "ui/util.h" +#include +#include "ui/preference_utils.h" +#include "ui/recent.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "ui/qt/widgets/wireshark_file_dialog.h" + +// To do: +// - Set a size hint for item delegates. +// - Make promiscuous and monitor mode checkboxes. +// - Fix InterfaceTreeDelegate method names. +// - You can edit filters via the main CaptureFilterCombo and via each +// individual interface row. We should probably do one or the other. +// - There might be a point in having the separate combo boxes in the +// individual interface row, if their CaptureFilterCombos actually +// called recent_get_cfilter_list with the interface name to get the +// separate list of recent capture filters for that interface, but +// they don't. + +const int stat_update_interval_ = 1000; // ms + +#ifdef CAN_SET_CAPTURE_BUFFER_SIZE +#define SHOW_BUFFER_COLUMN 1 +#endif + +#if defined(HAVE_PCAP_CREATE) +#define SHOW_MONITOR_COLUMN 1 +#endif + +/* + * Symbolic names for column indices. + */ +enum +{ + col_extcap_ = 0, + col_interface_, + col_traffic_, + col_link_, + col_pmode_, + col_snaplen_, + col_buffer_, + col_monitor_, + col_filter_, + col_num_columns_ +}; + +static interface_t *find_device_by_if_name(const QString &interface_name) +{ + interface_t *device; + guint i; + for (i = 0; i < global_capture_opts.all_ifaces->len; i++) { + device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i); + if (!interface_name.compare(device->display_name) && !device->hidden && device->type != IF_PIPE) { + return device; + } + } + return NULL; +} + +class InterfaceTreeWidgetItem : public QTreeWidgetItem +{ +public: + InterfaceTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {} + bool operator< (const QTreeWidgetItem &other) const; + QVariant data(int column, int role) const; + void setData(int column, int role, const QVariant &value); + QList points; + + void updateInterfaceColumns(interface_t *device) + { + if (!device) return; + + // Prevent infinite recursive signal loop + // itemChanged->interfaceItemChanged->updateInterfaceColumns + treeWidget()->blockSignals(true); + QString default_str = QObject::tr("default"); + + // XXX - this is duplicated in InterfaceTreeModel::data; + // it should be done in common code somewhere. + QString linkname; + if (device->active_dlt == -1) + linkname = "Unknown"; + else { + linkname = QObject::tr("DLT %1").arg(device->active_dlt); + for (GList *list = device->links; list != NULL; list = gxx_list_next(list)) { + link_row *linkr = gxx_list_data(link_row *, list); + if (linkr->dlt == device->active_dlt) { + linkname = linkr->name; + break; + } + } + } + setText(col_link_, linkname); + + if (device->if_info.type == IF_EXTCAP) { + /* extcap interfaces does not have this settings */ + setApplicable(col_pmode_, false); + + setApplicable(col_snaplen_, false); +#ifdef SHOW_BUFFER_COLUMN + setApplicable(col_buffer_, false); +#endif + } else { + setApplicable(col_pmode_, true); + setCheckState(col_pmode_, device->pmode ? Qt::Checked : Qt::Unchecked); + + QString snaplen_string = device->has_snaplen ? QString::number(device->snaplen) : default_str; + setText(col_snaplen_, snaplen_string); +#ifdef SHOW_BUFFER_COLUMN + setText(col_buffer_, QString::number(device->buffer)); +#endif + } + setText(col_filter_, device->cfilter); + +#ifdef SHOW_MONITOR_COLUMN + if (device->monitor_mode_supported) { + setApplicable(col_monitor_, true); + setCheckState(col_monitor_, device->monitor_mode_enabled ? Qt::Checked : Qt::Unchecked); + } else { + setApplicable(col_monitor_, false); + } +#endif + treeWidget()->blockSignals(false); + } + + void setApplicable(int column, bool applicable = false) { + QPalette palette = mainApp->palette(); + + if (applicable) { + setText(column, QString()); + } else { + setData(column, Qt::CheckStateRole, QVariant()); + palette.setCurrentColorGroup(QPalette::Disabled); + setText(column, UTF8_EM_DASH); + } + setForeground(column, palette.text().color()); + } + +}; + +CaptureOptionsDialog::CaptureOptionsDialog(QWidget *parent) : + GeometryStateDialog(parent), + ui(new Ui::CaptureOptionsDialog) +{ + ui->setupUi(this); + loadGeometry(); + setWindowTitle(mainApp->windowTitleString(tr("Capture Options"))); + + stat_timer_ = NULL; + stat_cache_ = NULL; + + ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Start")); + + // Start out with the list *not* sorted, so they show up in the order + // in which they were provided + ui->interfaceTree->sortByColumn(-1, Qt::AscendingOrder); + ui->interfaceTree->setItemDelegateForColumn(col_extcap_, &interface_item_delegate_); + ui->interfaceTree->setItemDelegateForColumn(col_interface_, &interface_item_delegate_); + ui->interfaceTree->setItemDelegateForColumn(col_traffic_, new SparkLineDelegate(this)); + ui->interfaceTree->setItemDelegateForColumn(col_link_, &interface_item_delegate_); + + ui->interfaceTree->setItemDelegateForColumn(col_snaplen_, &interface_item_delegate_); +#ifdef SHOW_BUFFER_COLUMN + ui->interfaceTree->setItemDelegateForColumn(col_buffer_, &interface_item_delegate_); +#else + ui->interfaceTree->setColumnHidden(col_buffer_, true); +#endif +#ifndef SHOW_MONITOR_COLUMN + ui->interfaceTree->setColumnHidden(col_monitor_, true); +#endif + ui->interfaceTree->setItemDelegateForColumn(col_filter_, &interface_item_delegate_); + + interface_item_delegate_.setTree(ui->interfaceTree); + + ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file")); + + ui->rbCompressionNone->setChecked(true); + + ui->tempDirLineEdit->setPlaceholderText(g_get_tmp_dir()); + ui->tempDirLineEdit->setText(global_capture_opts.temp_dir); + + // Changes in interface selections or capture filters should be propagated + // to the main welcome screen where they will be applied to the global + // capture options. + connect(this, SIGNAL(interfacesChanged()), ui->captureFilterComboBox, SIGNAL(interfacesChanged())); + connect(ui->captureFilterComboBox, SIGNAL(captureFilterSyntaxChanged(bool)), this, SLOT(updateWidgets())); + connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)), + this, SLOT(filterEdited())); + connect(ui->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)), + this, SIGNAL(captureFilterTextEdited(QString))); + connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)), + ui->captureFilterComboBox->lineEdit(), SLOT(setText(QString))); + connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)), + this, SIGNAL(captureFilterTextEdited(QString))); + connect(this, SIGNAL(ifsChanged()), this, SLOT(refreshInterfaceList())); + connect(mainApp, SIGNAL(localInterfaceListChanged()), this, SLOT(updateLocalInterfaces())); + connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); + connect(ui->interfaceTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(itemClicked(QTreeWidgetItem*,int))); + connect(ui->interfaceTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem*,int))); + connect(ui->tempDirBrowseButton, SIGNAL(clicked()), this, SLOT(tempDirBrowseButtonClicked())); + + ui->tabWidget->setCurrentIndex(0); + + updateWidgets(); +} + +CaptureOptionsDialog::~CaptureOptionsDialog() +{ + delete ui; +} + +/* Update global device selections based on the TreeWidget selection. */ +void CaptureOptionsDialog::updateGlobalDeviceSelections() +{ +#ifdef HAVE_LIBPCAP + QTreeWidgetItemIterator iter(ui->interfaceTree); + + global_capture_opts.num_selected = 0; + + while (*iter) { + QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value(); + for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) { + interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i); + if (device_name.compare(QString().fromUtf8(device->name)) == 0) { + if ((*iter)->isSelected()) { + device->selected = TRUE; + global_capture_opts.num_selected++; + } else { + device->selected = FALSE; + } + break; + } + } + ++iter; + } +#endif +} + +/* Update TreeWidget selection based on global device selections. */ +void CaptureOptionsDialog::updateFromGlobalDeviceSelections() +{ +#ifdef HAVE_LIBPCAP + QTreeWidgetItemIterator iter(ui->interfaceTree); + + // Prevent recursive interface interfaceSelected signals + ui->interfaceTree->blockSignals(true); + + while (*iter) { + QString device_name = (*iter)->data(col_interface_, Qt::UserRole).value(); + for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) { + interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i); + if (device_name.compare(QString().fromUtf8(device->name)) == 0) { + if ((bool)device->selected != (*iter)->isSelected()) { + (*iter)->setSelected(device->selected); + } + break; + } + } + ++iter; + } + + ui->interfaceTree->blockSignals(false); +#endif +} + +void CaptureOptionsDialog::interfaceSelected() +{ + if (sender() == ui->interfaceTree) { + // Local changes, propagate our changes + updateGlobalDeviceSelections(); + emit interfacesChanged(); + } else { + // Changes from the welcome screen, adjust to its state. + updateFromGlobalDeviceSelections(); + } + + updateSelectedFilter(); + + updateWidgets(); +} + +void CaptureOptionsDialog::filterEdited() +{ + QList si = ui->interfaceTree->selectedItems(); + + foreach (QTreeWidgetItem *ti, si) { + ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text()); + } + + if (si.count() > 0) { + QModelIndex col_filter_idx = ui->interfaceTree->model()->index(ui->interfaceTree->indexOfTopLevelItem(si[0]), col_filter_); + ui->interfaceTree->scrollTo(col_filter_idx); + } +} + +void CaptureOptionsDialog::updateWidgets() +{ + SyntaxLineEdit *sle = qobject_cast(ui->captureFilterComboBox->lineEdit()); + if (!sle) { + return; + } + + bool can_capture = false; + + if (ui->interfaceTree->selectedItems().count() > 0 && sle->syntaxState() != SyntaxLineEdit::Invalid) { + can_capture = true; + } + + ui->compileBPF->setEnabled(can_capture); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(can_capture); +} + +void CaptureOptionsDialog::on_capturePromModeCheckBox_toggled(bool checked) +{ + interface_t *device; + prefs.capture_prom_mode = checked; + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + InterfaceTreeWidgetItem *ti = dynamic_cast(ui->interfaceTree->topLevelItem(row)); + if (!ti) continue; + + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device) continue; + device->pmode = checked; + ti->updateInterfaceColumns(device); + } +} + +void CaptureOptionsDialog::browseButtonClicked() +{ + const char *open_dir = NULL; + + switch (prefs.gui_fileopen_style) { + + case FO_STYLE_LAST_OPENED: + open_dir = get_open_dialog_initial_dir(); + break; + + case FO_STYLE_SPECIFIED: + if (prefs.gui_fileopen_dir[0] != '\0') + open_dir = prefs.gui_fileopen_dir; + break; + } + QString file_name = WiresharkFileDialog::getSaveFileName(this, tr("Specify a Capture File"), open_dir); + ui->filenameLineEdit->setText(file_name); +} + +void CaptureOptionsDialog::tempDirBrowseButtonClicked() +{ + QString specified_dir = WiresharkFileDialog::getExistingDirectory(this, tr("Specify temporary directory")); + ui->tempDirLineEdit->setText(specified_dir); +} + +void CaptureOptionsDialog::interfaceItemChanged(QTreeWidgetItem *item, int column) +{ + QWidget* editor = ui->interfaceTree->indexWidget(ui->interfaceTree->currentIndex()); + if (editor) { + ui->interfaceTree->closePersistentEditor(item, ui->interfaceTree->currentColumn()); + } + + InterfaceTreeWidgetItem *ti = dynamic_cast(item); + if (!ti) return; + + interface_t *device; + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) return; + + switch(column) { + + case col_pmode_: + device->pmode = item->checkState(col_pmode_) == Qt::Checked ? TRUE : FALSE; + ti->updateInterfaceColumns(device); + break; + +#ifdef SHOW_MONITOR_COLUMN + case col_monitor_: + { + gboolean monitor_mode = FALSE; + if (ti->checkState(col_monitor_) == Qt::Checked) monitor_mode = TRUE; + + if_capabilities_t *caps; + char *auth_str = NULL; + QString active_dlt_name; + + set_active_dlt(device, global_capture_opts.default_options.linktype); + + #ifdef HAVE_PCAP_REMOTE + if (device->remote_opts.remote_host_opts.auth_type == CAPTURE_AUTH_PWD) { + auth_str = ws_strdup_printf("%s:%s", device->remote_opts.remote_host_opts.auth_username, + device->remote_opts.remote_host_opts.auth_password); + } + #endif + caps = capture_get_if_capabilities(device->name, monitor_mode, auth_str, NULL, NULL, main_window_update); + g_free(auth_str); + + if (caps != Q_NULLPTR) { + + for (int i = static_cast(g_list_length(device->links)) - 1; i >= 0; i--) { + GList* rem = g_list_nth(device->links, static_cast(i)); + device->links = g_list_remove_link(device->links, rem); + g_list_free_1(rem); + } + device->active_dlt = -1; + device->monitor_mode_supported = caps->can_set_rfmon; + device->monitor_mode_enabled = monitor_mode; + + for (GList *lt_entry = caps->data_link_types; lt_entry != Q_NULLPTR; lt_entry = gxx_list_next(lt_entry)) { + link_row *linkr = new link_row(); + data_link_info_t *data_link_info = gxx_list_data(data_link_info_t *, lt_entry); + /* + * For link-layer types libpcap/WinPcap/Npcap doesn't know + * about, the name will be "DLT n", and the description will + * be null. + * We mark those as unsupported, and don't allow them to be + * used - capture filters won't work on them, for example. + */ + if (data_link_info->description != Q_NULLPTR) { + linkr->dlt = data_link_info->dlt; + if (active_dlt_name.isEmpty()) { + device->active_dlt = data_link_info->dlt; + active_dlt_name = data_link_info->description; + } + linkr->name = g_strdup(data_link_info->description); + } else { + gchar *str; + /* XXX - should we just omit them? */ + str = ws_strdup_printf("%s (not supported)", data_link_info->name); + linkr->dlt = -1; + linkr->name = g_strdup(str); + g_free(str); + } + device->links = g_list_append(device->links, linkr); + } + free_if_capabilities(caps); + } else { + /* We don't know whether this supports monitor mode or not; + don't ask for monitor mode. */ + device->monitor_mode_enabled = FALSE; + device->monitor_mode_supported = FALSE; + } + + ti->updateInterfaceColumns(device); + + break; + } +#endif // SHOW_MONITOR_COLUMN + default: + break; + } +} + +void CaptureOptionsDialog::itemClicked(QTreeWidgetItem *item, int column) +{ + InterfaceTreeWidgetItem *ti = dynamic_cast(item); + if (!ti) return; + +#ifdef HAVE_LIBPCAP + interface_t *device; + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) return; + + switch(column) { + + case col_extcap_: + if (device->if_info.type == IF_EXTCAP) { + /* this checks if configuration is required and not yet provided or saved via prefs */ + QString device_name = ti->data(col_extcap_, Qt::UserRole).value(); + if (extcap_has_configuration((const char *)(device_name.toStdString().c_str()))) + { + emit showExtcapOptions(device_name, false); + return; + } + } + break; + + default: + break; + } +#endif /* HAVE_LIBPCAP */ +} + +void CaptureOptionsDialog::itemDoubleClicked(QTreeWidgetItem *item, int column) +{ + InterfaceTreeWidgetItem *ti = dynamic_cast(item); + if (!ti) return; + + switch(column) { + + // Double click starts capture just on columns which are not editable + case col_interface_: + case col_traffic_: + { +#ifdef HAVE_LIBPCAP + interface_t *device; + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) return; + + if (device->if_info.type == IF_EXTCAP) { + /* this checks if configuration is required and not yet provided or saved via prefs */ + QString device_name = ti->data(col_extcap_, Qt::UserRole).value(); + if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str()))) + { + emit showExtcapOptions(device_name, true); + return; + } + } +#endif /* HAVE_LIBPCAP */ + emit startCapture(); + close(); + break; + } + + default: + break; + } +} + +void CaptureOptionsDialog::on_gbStopCaptureAuto_toggled(bool checked) +{ + global_capture_opts.has_file_interval = checked; +} + +void CaptureOptionsDialog::on_gbNewFileAuto_toggled(bool checked) +{ + global_capture_opts.multi_files_on = checked; + ui->stopMBCheckBox->setEnabled(checked?false:true); + ui->stopMBSpinBox->setEnabled(checked?false:true); + ui->stopMBComboBox->setEnabled(checked?false:true); + ui->gbCompression->setEnabled(checked); + ui->rbCompressionNone->setEnabled(checked); +#ifdef HAVE_ZLIB + ui->rbCompressionGzip->setEnabled(checked); +#else + ui->rbCompressionGzip->setEnabled(false); +#endif +} + +void CaptureOptionsDialog::on_cbUpdatePacketsRT_toggled(bool checked) +{ + global_capture_opts.real_time_mode = checked; +} + +void CaptureOptionsDialog::on_cbAutoScroll_toggled(bool checked) +{ + recent.capture_auto_scroll = checked; +} + +void CaptureOptionsDialog::on_cbExtraCaptureInfo_toggled(bool checked) +{ + global_capture_opts.show_info = checked; +} + +void CaptureOptionsDialog::on_cbResolveMacAddresses_toggled(bool checked) +{ + gbl_resolv_flags.mac_name = checked; +} + +void CaptureOptionsDialog::on_cbResolveNetworkNames_toggled(bool checked) +{ + gbl_resolv_flags.network_name = checked; +} + +void CaptureOptionsDialog::on_cbResolveTransportNames_toggled(bool checked) +{ + gbl_resolv_flags.transport_name = checked; +} + +void CaptureOptionsDialog::on_buttonBox_accepted() +{ + if (saveOptionsToPreferences()) { + +#ifdef HAVE_LIBPCAP + InterfaceTreeWidgetItem *ti = dynamic_cast(ui->interfaceTree->currentItem()); + if (ti) { + interface_t *device; + + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (device && device->if_info.type == IF_EXTCAP) { + /* this checks if configuration is required and not yet provided or saved via prefs */ + QString device_name = ti->data(col_extcap_, Qt::UserRole).value(); + if (extcap_requires_configuration((const char *)(device_name.toStdString().c_str()))) + { + emit showExtcapOptions(device_name, true); + return; + } + } + } +#endif /* HAVE_LIBPCAP */ + + emit setFilterValid(true, ui->captureFilterComboBox->lineEdit()->text()); + accept(); + } +} + +// Not sure why we have to do this manually. +void CaptureOptionsDialog::on_buttonBox_rejected() +{ + if (saveOptionsToPreferences()) { + reject(); + } +} + +void CaptureOptionsDialog::on_buttonBox_helpRequested() +{ + // Probably the wrong URL. + mainApp->helpTopicAction(HELP_CAPTURE_OPTIONS_DIALOG); +} + +void CaptureOptionsDialog::updateInterfaces() +{ + if (prefs.capture_pcap_ng) { + ui->rbPcapng->setChecked(true); + } else { + ui->rbPcap->setChecked(true); + } + ui->capturePromModeCheckBox->setChecked(prefs.capture_prom_mode); + + if (global_capture_opts.saving_to_file) { + ui->filenameLineEdit->setText(QString(global_capture_opts.orig_save_file)); + } + + ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on); + ui->PktCheckBox->setChecked(global_capture_opts.has_file_packets); + if (global_capture_opts.has_file_packets) { + ui->PktSpinBox->setValue(global_capture_opts.file_packets); + } + ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize); + if (global_capture_opts.has_autostop_filesize) { + int value = global_capture_opts.autostop_filesize; + if (value > 1000000) { + if (global_capture_opts.multi_files_on) { + ui->MBSpinBox->setValue(value / 1000000); + ui->MBComboBox->setCurrentIndex(2); + } else { + ui->stopMBCheckBox->setChecked(true); + ui->stopMBSpinBox->setValue(value / 1000000); + ui->stopMBComboBox->setCurrentIndex(2); + } + } else if (value > 1000 && value % 1000 == 0) { + if (global_capture_opts.multi_files_on) { + ui->MBSpinBox->setValue(value / 1000); + ui->MBComboBox->setCurrentIndex(1); + } else { + ui->stopMBCheckBox->setChecked(true); + ui->stopMBSpinBox->setValue(value / 1000); + ui->stopMBComboBox->setCurrentIndex(1); + } + } else { + if (global_capture_opts.multi_files_on) { + ui->MBSpinBox->setValue(value); + ui->MBComboBox->setCurrentIndex(0); + } else { + ui->stopMBCheckBox->setChecked(true); + ui->stopMBSpinBox->setValue(value); + ui->stopMBComboBox->setCurrentIndex(0); + } + } + } + + ui->SecsCheckBox->setChecked(global_capture_opts.has_file_duration); + if (global_capture_opts.has_file_duration) { + int value = global_capture_opts.file_duration; + if (value > 3600 && value % 3600 == 0) { + ui->SecsSpinBox->setValue(value / 3600); + ui->SecsComboBox->setCurrentIndex(2); + } else if (value > 60 && value % 60 == 0) { + ui->SecsSpinBox->setValue(value / 60); + ui->SecsComboBox->setCurrentIndex(1); + } else { + ui->SecsSpinBox->setValue(value); + ui->SecsComboBox->setCurrentIndex(0); + } + } + + ui->IntervalSecsCheckBox->setChecked(global_capture_opts.has_file_interval); + if (global_capture_opts.has_file_interval) { + int value = global_capture_opts.file_interval; + if (value > 3600 && value % 3600 == 0) { + ui->IntervalSecsSpinBox->setValue(value / 3600); + ui->IntervalSecsComboBox->setCurrentIndex(2); + } else if (value > 60 && value % 60 == 0) { + ui->IntervalSecsSpinBox->setValue(value / 60); + ui->IntervalSecsComboBox->setCurrentIndex(1); + } else { + ui->IntervalSecsSpinBox->setValue(value); + ui->IntervalSecsComboBox->setCurrentIndex(0); + } + } + + if (global_capture_opts.has_ring_num_files) { + ui->RbSpinBox->setValue(global_capture_opts.ring_num_files); + ui->RbCheckBox->setCheckState(Qt::Checked); + } + + if (global_capture_opts.has_autostop_duration) { + ui->stopSecsCheckBox->setChecked(true); + int value = global_capture_opts.autostop_duration; + if (value > 3600 && value % 3600 == 0) { + ui->stopSecsSpinBox->setValue(value / 3600); + ui->stopSecsComboBox->setCurrentIndex(2); + } else if (value > 60 && value % 60 == 0) { + ui->stopSecsSpinBox->setValue(value / 60); + ui->stopSecsComboBox->setCurrentIndex(1); + } else { + ui->stopSecsSpinBox->setValue(value); + ui->stopSecsComboBox->setCurrentIndex(0); + } + } + + if (global_capture_opts.has_autostop_packets) { + ui->stopPktCheckBox->setChecked(true); + ui->stopPktSpinBox->setValue(global_capture_opts.autostop_packets); + } + + if (global_capture_opts.has_autostop_files) { + ui->stopFilesCheckBox->setChecked(true); + ui->stopFilesSpinBox->setValue(global_capture_opts.autostop_files); + } + + ui->cbUpdatePacketsRT->setChecked(global_capture_opts.real_time_mode); + ui->cbAutoScroll->setChecked(recent.capture_auto_scroll); + ui->cbExtraCaptureInfo->setChecked(global_capture_opts.show_info); + + ui->cbResolveMacAddresses->setChecked(gbl_resolv_flags.mac_name); + ui->cbResolveNetworkNames->setChecked(gbl_resolv_flags.network_name); + ui->cbResolveTransportNames->setChecked(gbl_resolv_flags.transport_name); + + // Rebuild the interface list without disturbing the main welcome screen. + disconnect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected())); + ui->interfaceTree->clear(); + +#ifdef SHOW_BUFFER_COLUMN + gint buffer; +#endif + gint snaplen; + gboolean hassnap, pmode; + QList selected_interfaces; + + disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int))); + + if (global_capture_opts.all_ifaces->len > 0) { + interface_t *device; + + for (guint device_idx = 0; device_idx < global_capture_opts.all_ifaces->len; device_idx++) { + device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx); + + /* Continue if capture device is hidden */ + if (device->hidden) { + continue; + } + + // Traffic sparklines + InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree); + ti->setFlags(ti->flags() | Qt::ItemIsEditable); + + if (device->if_info.type == IF_EXTCAP) { + ti->setIcon(col_extcap_, QIcon(StockIcon("x-capture-options"))); + ti->setData(col_extcap_, Qt::UserRole, QString(device->if_info.name)); + ti->setToolTip(col_extcap_, QString("Extcap interface settings")); + } + + ti->setText(col_interface_, device->display_name); + ti->setData(col_interface_, Qt::UserRole, QString(device->name)); + if (device->if_info.type != IF_EXTCAP) + ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(ti->points)); + + if (device->no_addresses > 0) { + QString addr_str = tr("%1: %2").arg(device->no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device->addresses); + QTreeWidgetItem *addr_ti = new QTreeWidgetItem(ti); + + addr_str.replace('\n', ", "); + addr_ti->setText(0, addr_str); + addr_ti->setFlags(addr_ti->flags() ^ Qt::ItemIsSelectable); + addr_ti->setFirstColumnSpanned(true); + addr_ti->setToolTip(col_interface_, QString("%1").arg(addr_str)); + ti->setToolTip(col_interface_, QString("%1").arg(addr_str)); + } else { + ti->setToolTip(col_interface_, tr("no addresses")); + } + + if (capture_dev_user_pmode_find(device->name, &pmode)) { + device->pmode = pmode; + } + if (capture_dev_user_snaplen_find(device->name, &hassnap, &snaplen)) { + /* Default snap length set in preferences */ + device->snaplen = snaplen; + device->has_snaplen = snaplen == WTAP_MAX_PACKET_SIZE_STANDARD ? FALSE : hassnap; + } else { + /* No preferences set yet, use default values */ + device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; + device->has_snaplen = FALSE; + } + +#ifdef SHOW_BUFFER_COLUMN + if (capture_dev_user_buffersize_find(device->name) != -1) { + buffer = capture_dev_user_buffersize_find(device->name); + device->buffer = buffer; + } else { + device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE; + } +#endif + ti->updateInterfaceColumns(device); + + if (device->selected) { + selected_interfaces << ti; + } + } + } + + connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int))); + + foreach (QTreeWidgetItem *ti, selected_interfaces) { + ti->setSelected(true); + } + connect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected())); + updateSelectedFilter(); + + // Manually or automatically size some columns as needed. + int one_em = fontMetrics().height(); + for (int col = 0; col < ui->interfaceTree->topLevelItemCount(); col++) { + switch (col) { + case col_pmode_: + ui->interfaceTree->setColumnWidth(col, one_em * 3.25); + break; + case col_snaplen_: + ui->interfaceTree->setColumnWidth(col, one_em * 4.25); + break; + case col_buffer_: + ui->interfaceTree->setColumnWidth(col, one_em * 4.25); + break; + case col_monitor_: + ui->interfaceTree->setColumnWidth(col, one_em * 3.25); + break; + default: + ui->interfaceTree->resizeColumnToContents(col); + } + + } + + updateWidgets(); + + if (!stat_timer_) { + updateStatistics(); + stat_timer_ = new QTimer(this); + connect(stat_timer_, SIGNAL(timeout()), this, SLOT(updateStatistics())); + stat_timer_->start(stat_update_interval_); + } +} + +void CaptureOptionsDialog::showEvent(QShowEvent *) +{ + updateInterfaces(); +} + +void CaptureOptionsDialog::refreshInterfaceList() +{ + updateInterfaces(); + emit interfaceListChanged(); +} + +void CaptureOptionsDialog::updateLocalInterfaces() +{ + updateInterfaces(); +} + +void CaptureOptionsDialog::updateStatistics(void) +{ + interface_t *device; + + disconnect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int))); + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + + for (guint if_idx = 0; if_idx < global_capture_opts.all_ifaces->len; if_idx++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + if (!ti) { + continue; + } + device = &g_array_index(global_capture_opts.all_ifaces, interface_t, if_idx); + QString device_name = ti->text(col_interface_); + if (device_name.compare(device->display_name) || device->hidden || device->type == IF_PIPE) { + continue; + } + QList points = ti->data(col_traffic_, Qt::UserRole).value >(); + points.append(device->packet_diff); + ti->setData(col_traffic_, Qt::UserRole, QVariant::fromValue(points)); + } + } + connect(ui->interfaceTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(interfaceItemChanged(QTreeWidgetItem*,int))); + ui->interfaceTree->viewport()->update(); +} + +void CaptureOptionsDialog::on_compileBPF_clicked() +{ + QStringList interfaces; + foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems()) { + interfaces.append(ti->text(col_interface_)); + } + + QString filter = ui->captureFilterComboBox->currentText(); + CompiledFilterOutput *cfo = new CompiledFilterOutput(this, interfaces, filter); + + cfo->show(); +} + +bool CaptureOptionsDialog::saveOptionsToPreferences() +{ + if (ui->rbPcapng->isChecked()) { + global_capture_opts.use_pcapng = true; + prefs.capture_pcap_ng = true; + } else { + global_capture_opts.use_pcapng = false; + prefs.capture_pcap_ng = false; + } + + g_free(global_capture_opts.save_file); + g_free(global_capture_opts.orig_save_file); + + QString filename = ui->filenameLineEdit->text(); + if (filename.length() > 0) { + /* User specified a file to which the capture should be written. */ + global_capture_opts.saving_to_file = true; + global_capture_opts.save_file = qstring_strdup(filename); + global_capture_opts.orig_save_file = qstring_strdup(filename); + /* Save the directory name for future file dialogs. */ + set_last_open_dir(get_dirname(filename.toUtf8().data())); + } else { + /* User didn't specify a file; save to a temporary file. */ + global_capture_opts.saving_to_file = false; + global_capture_opts.save_file = NULL; + global_capture_opts.orig_save_file = NULL; + } + + QString tempdir = ui->tempDirLineEdit->text(); + if (tempdir.length() > 0) { + global_capture_opts.temp_dir = qstring_strdup(tempdir); + } + else { + global_capture_opts.temp_dir = NULL; + } + + global_capture_opts.has_ring_num_files = ui->RbCheckBox->isChecked(); + + if (global_capture_opts.has_ring_num_files) { + global_capture_opts.ring_num_files = ui->RbSpinBox->value(); + if (global_capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES) + global_capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES; +#if RINGBUFFER_MIN_NUM_FILES > 0 + else if (global_capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES) + global_capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES; +#endif + } + global_capture_opts.multi_files_on = ui->gbNewFileAuto->isChecked(); + if (global_capture_opts.multi_files_on) { + global_capture_opts.has_file_duration = ui->SecsCheckBox->isChecked(); + if (global_capture_opts.has_file_duration) { + global_capture_opts.file_duration = ui->SecsSpinBox->value(); + int index = ui->SecsComboBox->currentIndex(); + switch (index) { + case 1: global_capture_opts.file_duration *= 60; + break; + case 2: global_capture_opts.file_duration *= 3600; + break; + } + } + global_capture_opts.has_file_interval = ui->IntervalSecsCheckBox->isChecked(); + if (global_capture_opts.has_file_interval) { + global_capture_opts.file_interval = ui->IntervalSecsSpinBox->value(); + int index = ui->IntervalSecsComboBox->currentIndex(); + switch (index) { + case 1: global_capture_opts.file_interval *= 60; + break; + case 2: global_capture_opts.file_interval *= 3600; + break; + } + } + global_capture_opts.has_file_packets = ui->PktCheckBox->isChecked(); + if (global_capture_opts.has_file_packets) { + global_capture_opts.file_packets = ui->PktSpinBox->value(); + } + global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked(); + if (global_capture_opts.has_autostop_filesize) { + global_capture_opts.autostop_filesize = ui->MBSpinBox->value(); + int index = ui->MBComboBox->currentIndex(); + switch (index) { + case 1: if (global_capture_opts.autostop_filesize > 2000) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB.")); + return false; + } else { + global_capture_opts.autostop_filesize *= 1000; + } + break; + case 2: if (global_capture_opts.autostop_filesize > 2) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB.")); + return false; + } else { + global_capture_opts.autostop_filesize *= 1000000; + } + break; + } + } + /* test if the settings are ok for a ringbuffer */ + if (global_capture_opts.save_file == NULL) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files.")); + return false; + } else if (!global_capture_opts.has_autostop_filesize && + !global_capture_opts.has_file_interval && + !global_capture_opts.has_file_duration && + !global_capture_opts.has_file_packets) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: No file limit given. You must specify a file size, interval, or number of packets for each file.")); + g_free(global_capture_opts.save_file); + global_capture_opts.save_file = NULL; + return false; + } + } else { + global_capture_opts.has_autostop_filesize = ui->stopMBCheckBox->isChecked(); + if (global_capture_opts.has_autostop_filesize) { + global_capture_opts.autostop_filesize = ui->stopMBSpinBox->value(); + int index = ui->stopMBComboBox->currentIndex(); + switch (index) { + case 1: if (global_capture_opts.autostop_filesize > 2000) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB.")); + return false; + } else { + global_capture_opts.autostop_filesize *= 1000; + } + break; + case 2: if (global_capture_opts.autostop_filesize > 2) { + QMessageBox::warning(this, tr("Error"), + tr("Multiple files: Requested filesize too large. The filesize cannot be greater than 2 GiB.")); + return false; + } else { + global_capture_opts.autostop_filesize *= 1000000; + } + break; + } + } + } + + global_capture_opts.has_autostop_duration = ui->stopSecsCheckBox->isChecked(); + if (global_capture_opts.has_autostop_duration) { + global_capture_opts.autostop_duration = ui->stopSecsSpinBox->value(); + int index = ui->stopSecsComboBox->currentIndex(); + switch (index) { + case 1: global_capture_opts.autostop_duration *= 60; + break; + case 2: global_capture_opts.autostop_duration *= 3600; + break; + } + } + + global_capture_opts.has_autostop_packets = ui->stopPktCheckBox->isChecked(); + if (global_capture_opts.has_autostop_packets) { + global_capture_opts.autostop_packets = ui->stopPktSpinBox->value(); + } + + global_capture_opts.has_autostop_files = ui->stopFilesCheckBox->isChecked(); + if (global_capture_opts.has_autostop_files) { + global_capture_opts.autostop_files = ui->stopFilesSpinBox->value(); + } + + interface_t *device; + + for (int col = col_link_; col <= col_filter_; col++) { + if (ui->interfaceTree->isColumnHidden(col)) { + continue; + } + /* All entries are separated by comma. There is also one before the first interface to be able to identify + word boundaries. As 'lo' is part of 'nflog' an exact match is necessary. */ + switch (col) { + case col_link_: + { + QStringList link_list; + + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device || device->active_dlt == -1) { + continue; + } + link_list << QString("%1(%2)").arg(device->name).arg(device->active_dlt); + } + g_free(prefs.capture_devices_linktypes); + prefs.capture_devices_linktypes = qstring_strdup(link_list.join(",")); + break; + } +#ifdef SHOW_BUFFER_COLUMN + case col_buffer_: + { + QStringList buffer_size_list; + + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device || device->buffer == -1) { + continue; + } + buffer_size_list << QString("%1(%2)").arg(device->name).arg(device->buffer); + } + g_free(prefs.capture_devices_buffersize); + prefs.capture_devices_buffersize = qstring_strdup(buffer_size_list.join(",")); + break; + } +#endif // HAVE_BUFFER_SETTING + case col_snaplen_: + { + QStringList snaplen_list; + + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device) continue; + snaplen_list << QString("%1:%2(%3)") + .arg(device->name) + .arg(device->has_snaplen) + .arg(device->has_snaplen ? device->snaplen : WTAP_MAX_PACKET_SIZE_STANDARD); + } + g_free(prefs.capture_devices_snaplen); + prefs.capture_devices_snaplen = qstring_strdup(snaplen_list.join(",")); + break; + } + case col_pmode_: + { + QStringList pmode_list; + + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device || device->pmode == -1) { + continue; + } + pmode_list << QString("%1(%2)").arg(device->name).arg(device->pmode); + } + g_free(prefs.capture_devices_pmode); + prefs.capture_devices_pmode = qstring_strdup(pmode_list.join(",")); + break; + } + +#ifdef SHOW_MONITOR_COLUMN + case col_monitor_: + { + QStringList monitor_list; + + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device || !device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) { + continue; + } + monitor_list << device->name; + } + g_free(prefs.capture_devices_monitor_mode); + prefs.capture_devices_monitor_mode = qstring_strdup(monitor_list.join(",")); + break; + } +#endif // HAVE_MONITOR_SETTING + +#if 0 + // The device cfilter should have been applied at this point. + // We shouldn't change it here. + case col_filter_: + { + // XXX Update selected interfaces only? + for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) { + QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row); + QString device_name = ti->data(col_interface_, Qt::UserRole).toString(); + device = getDeviceByName(device_name); + if (!device) continue; + g_free(device->cfilter); + if (ti->text(col_filter_).isEmpty()) { + device->cfilter = NULL; + } else { + device->cfilter = qstring_strdup(ti->text(col_filter_)); + } + } + } +#endif + } + } + + g_free(global_capture_opts.compress_type); + + if (ui->rbCompressionNone->isChecked() ) { + global_capture_opts.compress_type = NULL; + } else if (ui->rbCompressionGzip->isChecked() ) { + global_capture_opts.compress_type = qstring_strdup("gzip"); + } else { + global_capture_opts.compress_type = NULL; + } + + prefs_main_write(); + return true; +} + +void CaptureOptionsDialog::updateSelectedFilter() +{ + // Should match MainWelcome::interfaceSelected. + QPair sf_pair = CaptureFilterEdit::getSelectedFilter(); + const QString user_filter = sf_pair.first; + bool conflict = sf_pair.second; + + if (conflict) { + ui->captureFilterComboBox->lineEdit()->clear(); + ui->captureFilterComboBox->setConflict(true); + } else { + ui->captureFilterComboBox->lineEdit()->setText(user_filter); + } +} + +void CaptureOptionsDialog::on_manageButton_clicked() +{ + if (saveOptionsToPreferences()) { + ManageInterfacesDialog *dlg = new ManageInterfacesDialog(this); + dlg->show(); + } +} + +void CaptureOptionsDialog::changeEvent(QEvent* event) +{ + if (0 != event) + { + switch (event->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } + } + QDialog::changeEvent(event); +} + +interface_t *CaptureOptionsDialog::getDeviceByName(const QString device_name) +{ + for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) { + interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i); + if (device_name.compare(QString().fromUtf8(device->name)) == 0) { + return device; + } + } + return NULL; +} + +// +// InterfaceTreeItem +// +bool InterfaceTreeWidgetItem::operator< (const QTreeWidgetItem &other) const { + if (treeWidget()->sortColumn() == col_traffic_) { + QList points = data(col_traffic_, Qt::UserRole).value >(); + QList other_points = other.data(col_traffic_, Qt::UserRole).value >(); + double avg = 0, other_avg = 0; + foreach (int point, points) { + avg += (double) point / points.length(); + } + foreach (int point, other_points) { + other_avg += (double) point / other_points.length(); + } + return avg < other_avg; + } + return QTreeWidgetItem::operator<(other); +} + +QVariant InterfaceTreeWidgetItem::data(int column, int role) const +{ + // See setData for the special col_traffic_ treatment. + if (column == col_traffic_ && role == Qt::UserRole) { + return QVariant::fromValue(points); + } + + return QTreeWidgetItem::data(column, role); +} + +void InterfaceTreeWidgetItem::setData(int column, int role, const QVariant &value) +{ + // Workaround for closing editors on updates to the points list: normally + // QTreeWidgetItem::setData emits dataChanged when the value (list) changes. + // We could store a pointer to the list, or just have this hack that does + // not emit dataChanged. + if (column == col_traffic_ && role == Qt::UserRole) { + points = value.value >(); + return; + } + + QTreeWidgetItem::setData(column, role, value); +} + +// +// InterfaceTreeDelegate +// + +#include + +InterfaceTreeDelegate::InterfaceTreeDelegate(QObject *parent) + : QStyledItemDelegate(parent), tree_(NULL) +{ +} + + +InterfaceTreeDelegate::~InterfaceTreeDelegate() +{ +} + + +QWidget* InterfaceTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &idx) const +{ + QWidget *w = NULL; +#ifdef SHOW_BUFFER_COLUMN + gint buffer = DEFAULT_CAPTURE_BUFFER_SIZE; +#endif + guint snap = WTAP_MAX_PACKET_SIZE_STANDARD; + GList *links = NULL; + + if (idx.column() > 1 && idx.data().toString().compare(UTF8_EM_DASH)) { + QTreeWidgetItem *ti = tree_->topLevelItem(idx.row()); + QString interface_name = ti->text(col_interface_); + interface_t *device = find_device_by_if_name(interface_name); + + if (device) { +#ifdef SHOW_BUFFER_COLUMN + buffer = device->buffer; +#endif + snap = device->snaplen; + links = device->links; + } + switch (idx.column()) { + case col_extcap_: + case col_interface_: + case col_traffic_: + break; + case col_link_: + { + GList *list; + link_row *linkr; + QStringList valid_link_types; + + // XXX The GTK+ UI fills in all link types, valid or not. We add + // only the valid ones. If we *do* wish to include invalid link + // types we'll have to jump through the hoops necessary to disable + // QComboBox items. + + for (list = links; list != Q_NULLPTR; list = gxx_list_next(list)) { + linkr = gxx_list_data(link_row*, list); + if (linkr->dlt >= 0) { + valid_link_types << linkr->name; + } + } + + if (valid_link_types.size() < 2) { + break; + } + QComboBox *cb = new QComboBox(parent); + cb->addItems(valid_link_types); + + connect(cb, &QComboBox::currentTextChanged, this, &InterfaceTreeDelegate::linkTypeChanged); + w = (QWidget*) cb; + break; + } + case col_snaplen_: + { + QSpinBox *sb = new QSpinBox(parent); + sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD); + sb->setValue(snap); + sb->setWrapping(true); + connect(sb, SIGNAL(valueChanged(int)), this, SLOT(snapshotLengthChanged(int))); + w = (QWidget*) sb; + break; + } +#ifdef SHOW_BUFFER_COLUMN + case col_buffer_: + { + QSpinBox *sb = new QSpinBox(parent); + sb->setRange(1, WTAP_MAX_PACKET_SIZE_STANDARD); + sb->setValue(buffer); + sb->setWrapping(true); + connect(sb, SIGNAL(valueChanged(int)), this, SLOT(bufferSizeChanged(int))); + w = (QWidget*) sb; + break; + } +#endif + case col_filter_: + { + // XXX: Should this take the interface name, so that the history + // list is taken from the interface-specific recent cfilter list? + CaptureFilterCombo *cf = new CaptureFilterCombo(parent, true); + connect(cf->lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString))); + w = (QWidget*) cf; + } + default: + break; + } + } + if (w) + w->setAutoFillBackground(true); + return w; +} + +bool InterfaceTreeDelegate::eventFilter(QObject *object, QEvent *event) +{ + QComboBox * comboBox = dynamic_cast(object); + if (comboBox) { + if (event->type() == QEvent::MouseButtonRelease) { + comboBox->showPopup(); + return true; + } + } else { + return QStyledItemDelegate::eventFilter(object, event); + } + return false; +} + +void InterfaceTreeDelegate::linkTypeChanged(const QString selected_link_type) +{ + GList *list; + link_row *temp; + interface_t *device; + + QTreeWidgetItem *ti = tree_->currentItem(); + if (!ti) { + return; + } + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) { + return; + } + for (list = device->links; list != Q_NULLPTR; list = gxx_list_next(list)) { + temp = gxx_list_data(link_row*, list); + if (!selected_link_type.compare(temp->name)) { + device->active_dlt = temp->dlt; + } + } + // XXX We might want to verify that active_dlt is valid at this point. +} + +void InterfaceTreeDelegate::snapshotLengthChanged(int value) +{ + interface_t *device; + QTreeWidgetItem *ti = tree_->currentItem(); + if (!ti) { + return; + } + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) { + return; + } + if (value != WTAP_MAX_PACKET_SIZE_STANDARD) { + device->has_snaplen = true; + device->snaplen = value; + } else { + device->has_snaplen = false; + device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; + } +} + +#ifdef SHOW_BUFFER_COLUMN +void InterfaceTreeDelegate::bufferSizeChanged(int value) +{ + interface_t *device; + QTreeWidgetItem *ti = tree_->currentItem(); + if (!ti) { + return; + } + QString interface_name = ti->text(col_interface_); + device = find_device_by_if_name(interface_name); + if (!device) { + return; + } + device->buffer = value; +} +#endif + +#endif /* HAVE_LIBPCAP */ -- cgit v1.2.3