aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/capture_ui_utils.h2
-rw-r--r--ui/qt/capture_filter_combo.h1
-rw-r--r--ui/qt/capture_filter_edit.cpp59
-rw-r--r--ui/qt/capture_filter_edit.h6
-rw-r--r--ui/qt/capture_interfaces_dialog.cpp189
-rw-r--r--ui/qt/capture_interfaces_dialog.h7
-rw-r--r--ui/qt/interface_tree.cpp110
-rw-r--r--ui/qt/interface_tree.h9
-rw-r--r--ui/qt/main_welcome.cpp36
-rw-r--r--ui/qt/main_welcome.h6
-rw-r--r--ui/qt/main_window.cpp13
11 files changed, 278 insertions, 160 deletions
diff --git a/ui/capture_ui_utils.h b/ui/capture_ui_utils.h
index 5f6cdcd284..8e7ef65b30 100644
--- a/ui/capture_ui_utils.h
+++ b/ui/capture_ui_utils.h
@@ -98,6 +98,8 @@ gboolean capture_dev_user_pmode_find(const gchar *if_name, gboolean *pmode);
* Find user-specified capture filter that matches interface
* name, if any.
*
+ * This is deprecated and should not be used in new code.
+ *
* @param if_name The name of the interface.
*
* @return The capture filter (must be g_free'd later) or NULL if not found.
diff --git a/ui/qt/capture_filter_combo.h b/ui/qt/capture_filter_combo.h
index 961ccabd9e..785b6ad36c 100644
--- a/ui/qt/capture_filter_combo.h
+++ b/ui/qt/capture_filter_combo.h
@@ -34,6 +34,7 @@ public:
explicit CaptureFilterCombo(QWidget *parent = 0, bool plain = false);
bool addRecentCapture(const char *filter);
void writeRecent(FILE *rf);
+ void setConflict(bool conflict = false) { cf_edit_->setConflict(conflict); }
signals:
void interfacesChanged();
diff --git a/ui/qt/capture_filter_edit.cpp b/ui/qt/capture_filter_edit.cpp
index 7779ad6f5a..0a033f43dc 100644
--- a/ui/qt/capture_filter_edit.cpp
+++ b/ui/qt/capture_filter_edit.cpp
@@ -126,10 +126,7 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
setCompleter(new QCompleter(completion_model_, this));
setCompletionTokenChars(libpcap_primitive_chars_);
- placeholder_text_ = QString(tr("Enter a capture filter %1")).arg(UTF8_HORIZONTAL_ELLIPSIS);
-#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
- setPlaceholderText(placeholder_text_);
-#endif
+ setConflict(false);
if (!plain_) {
bookmark_button_ = new StockIconToolButton(this, "x-capture-filter-bookmark");
@@ -215,7 +212,7 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
QThread *syntax_thread = new QThread;
syntax_worker_ = new CaptureFilterSyntaxWorker;
syntax_worker_->moveToThread(syntax_thread);
- connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initCaptureFilter()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(updateBookmarkMenu()));
connect(wsApp, SIGNAL(captureFilterListChanged()), this, SLOT(updateBookmarkMenu()));
connect(syntax_thread, SIGNAL(started()), syntax_worker_, SLOT(start()));
connect(syntax_thread, SIGNAL(started()), this, SLOT(checkFilter()));
@@ -294,12 +291,55 @@ void CaptureFilterEdit::resizeEvent(QResizeEvent *)
}
}
+void CaptureFilterEdit::setConflict(bool conflict)
+{
+ if (conflict) {
+ //: This is a very long concept that needs to fit into a short space.
+ placeholder_text_ = tr("Multiple filters selected. Override them here or leave this blank to preserve them.");
+ setToolTip(tr("<p>The interfaces you have selected have different capture filters."
+ " Typing a filter here will override them. Doing nothing will"
+ " preserve them.</p>"));
+ } else {
+ placeholder_text_ = QString(tr("Enter a capture filter %1")).arg(UTF8_HORIZONTAL_ELLIPSIS);
+ setToolTip(QString());
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ setPlaceholderText(placeholder_text_);
+#endif
+}
+
+// XXX Make this private along with setConflict.
+QPair<const QString, bool> CaptureFilterEdit::getSelectedFilter()
+{
+ QString user_filter;
+ bool filter_conflict = false;
+#ifdef HAVE_LIBPCAP
+ int selected_devices = 0;
+
+ 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.selected) {
+ selected_devices++;
+ if (selected_devices == 1) {
+ user_filter = device.cfilter;
+ } else {
+ if (user_filter.compare(device.cfilter)) {
+ filter_conflict = true;
+ }
+ }
+ }
+ }
+#endif // HAVE_LIBPCAP
+ return QPair<const QString, bool>(user_filter, filter_conflict);
+}
+
void CaptureFilterEdit::checkFilter(const QString& filter)
{
setSyntaxState(Busy);
popFilterSyntaxStatus();
bool empty = filter.isEmpty();
+ setConflict(false);
if (bookmark_button_) {
bool match = false;
@@ -385,15 +425,6 @@ void CaptureFilterEdit::updateBookmarkMenu()
checkFilter();
}
-void CaptureFilterEdit::initCaptureFilter()
-{
-#ifdef HAVE_LIBPCAP
- setText(global_capture_opts.default_options.cfilter);
-#endif // HAVE_LIBPCAP
-
- updateBookmarkMenu();
-}
-
void CaptureFilterEdit::setFilterSyntaxState(QString filter, int state, QString err_msg)
{
if (filter.compare(text()) == 0) { // The user hasn't changed the filter
diff --git a/ui/qt/capture_filter_edit.h b/ui/qt/capture_filter_edit.h
index bb9daf6232..df3c1eb362 100644
--- a/ui/qt/capture_filter_edit.h
+++ b/ui/qt/capture_filter_edit.h
@@ -34,6 +34,11 @@ class CaptureFilterEdit : public SyntaxLineEdit
Q_OBJECT
public:
explicit CaptureFilterEdit(QWidget *parent = 0, bool plain = false);
+ void setConflict(bool conflict = false);
+ // No selections: (QString(), false)
+ // Selections, same filter: (filter, false)
+ // Selections, different filters (QString(), true)
+ static QPair<const QString, bool> getSelectedFilter();
protected:
void paintEvent(QPaintEvent *evt);
@@ -50,7 +55,6 @@ public slots:
void prepareFilter();
private slots:
- void initCaptureFilter();
void applyCaptureFilter();
void checkFilter(const QString &filter);
void setFilterSyntaxState(QString filter, int state, QString err_msg);
diff --git a/ui/qt/capture_interfaces_dialog.cpp b/ui/qt/capture_interfaces_dialog.cpp
index 82acc44131..d0c6e5a570 100644
--- a/ui/qt/capture_interfaces_dialog.cpp
+++ b/ui/qt/capture_interfaces_dialog.cpp
@@ -152,16 +152,19 @@ CaptureInterfacesDialog::CaptureInterfacesDialog(QWidget *parent) :
ui->filenameLineEdit->setPlaceholderText(tr("Leave blank to use a temporary file"));
#endif
- connect(ui->interfaceTree,SIGNAL(itemClicked(QTreeWidgetItem*,int)),this,SLOT(interfaceClicked(QTreeWidgetItem*,int)));
- connect(ui->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
+ // 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, SIGNAL(activated(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(this, SIGNAL(interfacesChanged()), ui->captureFilterComboBox, SIGNAL(interfacesChanged()));
+ connect(&interface_item_delegate_, SIGNAL(filterChanged(QString)),
+ this, SIGNAL(captureFilterTextEdited(QString)));
connect(this, SIGNAL(ifsChanged()), this, SLOT(refreshInterfaceList()));
connect(wsApp, SIGNAL(localInterfaceListChanged()), this, SLOT(updateLocalInterfaces()));
connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked()));
@@ -169,29 +172,20 @@ CaptureInterfacesDialog::CaptureInterfacesDialog(QWidget *parent) :
void CaptureInterfacesDialog::interfaceSelected()
{
- interface_t *device;
+ InterfaceTree::updateGlobalDeviceSelections(ui->interfaceTree, col_interface_);
+
+ start_bt_->setEnabled((global_capture_opts.num_selected > 0) ? true: false);
+
+ emit interfacesChanged();
+
+ updateSelectedFilter();
- if (ui->interfaceTree->selectedItems().isEmpty()) {
- for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
- device->selected = false;
- device->locked = true;
- }
- global_capture_opts.num_selected = 0;
- start_bt_->setEnabled(false);
- emit setSelectedInterfaces();
- for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
- device->locked = false;
- }
- }
updateWidgets();
}
void CaptureInterfacesDialog::filterEdited()
{
QList<QTreeWidgetItem*> si = ui->interfaceTree->selectedItems();
- if (si.isEmpty()) return;
foreach (QTreeWidgetItem *ti, si) {
ti->setText(col_filter_, ui->captureFilterComboBox->lineEdit()->text());
@@ -218,41 +212,6 @@ void CaptureInterfacesDialog::updateWidgets()
start_bt_->setEnabled(can_capture);
}
-void CaptureInterfacesDialog::interfaceClicked(QTreeWidgetItem *, int)
-{
- guint i;
- QString filter = ui->captureFilterComboBox->currentText();
-
- global_capture_opts.num_selected = 0;
- for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
- interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
- device->selected = FALSE;
- }
-
- foreach (QTreeWidgetItem *ti, ui->interfaceTree->selectedItems())
- {
- QString interface_name = ti->text(col_interface_);
-
- for (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 (interface_name.compare(device->display_name)) {
- continue;
- } else {
- device->selected = TRUE;
- global_capture_opts.num_selected++;
- break;
- }
- }
-
- start_bt_->setEnabled((global_capture_opts.num_selected > 0) ? true: false);
-
- if (filter.compare(QString(""))) {
- emit interfacesChanged();
- }
- emit setSelectedInterfaces();
- }
-}
-
CaptureInterfacesDialog::~CaptureInterfacesDialog()
{
delete ui;
@@ -269,8 +228,9 @@ void CaptureInterfacesDialog::on_capturePromModeCheckBox_toggled(bool checked)
prefs.capture_prom_mode = checked;
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- int device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
+ QString device_name = ti->data(col_interface_, Qt::UserRole).toString();
+ device = getDeviceByName(device_name);
+ if (!device) continue;
// QString device_name = ui->interfaceTree->topLevelItem(row)->text(col_interface_);
device->pmode = checked;
ti->setText(col_pmode_, checked? tr("enabled"):tr("disabled"));
@@ -460,6 +420,8 @@ void CaptureInterfacesDialog::updateInterfaces()
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();
GList *list;
@@ -469,6 +431,7 @@ void CaptureInterfacesDialog::updateInterfaces()
#endif
gint snaplen;
gboolean hassnap, pmode;
+ QList<QTreeWidgetItem *> selected_interfaces;
if (global_capture_opts.all_ifaces->len > 0) {
interface_t *device;
@@ -484,7 +447,7 @@ void CaptureInterfacesDialog::updateInterfaces()
// Traffic sparklines
InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem(ui->interfaceTree);
ti->setFlags(ti->flags() | Qt::ItemIsEditable);
- ti->setData(col_interface_, Qt::UserRole, qVariantFromValue(device_idx));
+ ti->setData(col_interface_, Qt::UserRole, QString(device->name));
ti->setData(col_traffic_, Qt::UserRole, qVariantFromValue(&ti->points));
ti->setText(col_interface_, device->display_name);
@@ -562,34 +525,20 @@ void CaptureInterfacesDialog::updateInterfaces()
#ifdef HAVE_EXTCAP
}
#endif
- // If the capture filter column has text, assume that the user
- // has filled it in via selectedIfaceCaptureFilterComboBox.
- if (ti->text(col_filter_).isEmpty()) {
- gchar* user_cfilter = capture_dev_user_cfilter_find(device->name);
- if (user_cfilter) {
- g_free(device->cfilter);
- device->cfilter = user_cfilter;
- }
- ti->setText(col_filter_, device->cfilter);
- }
+ ti->setText(col_filter_, device->cfilter);
- if (prefs.capture_device && strstr(prefs.capture_device, device->name) != NULL) {
- device->selected = TRUE;
- global_capture_opts.num_selected++;
+ if (device->selected) {
+ selected_interfaces << ti;
}
- ti->setSelected(device->selected);
}
}
- // col_interface_ = 0,
- // col_traffic_,
- // col_link_,
- // col_pmode_,
- // col_snaplen_,
- // col_buffer_,
- // col_monitor_,
- // col_filter_,
- // col_num_columns_
+ 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++) {
@@ -622,6 +571,11 @@ void CaptureInterfacesDialog::updateInterfaces()
}
}
+void CaptureInterfacesDialog::showEvent(QShowEvent *)
+{
+ updateInterfaces();
+}
+
void CaptureInterfacesDialog::refreshInterfaceList()
{
updateInterfaces();
@@ -802,12 +756,6 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
interface_t *device;
- // Close the editor if it's open.
- QTreeWidgetItem *ti = ui->interfaceTree->currentItem();
- if (ti) {
- ui->interfaceTree->setCurrentItem(ti, col_interface_);
- }
-
for (int col = col_link_; col <= col_filter_; col++) {
if (ui->interfaceTree->isColumnHidden(col)) {
continue;
@@ -821,9 +769,9 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
- if (device->active_dlt == -1) {
+ 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);
@@ -839,9 +787,9 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
- if (device->buffer == -1) {
+ 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);
@@ -857,8 +805,9 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
+ 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)
@@ -874,9 +823,9 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
- if (device->pmode == -1) {
+ 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);
@@ -892,9 +841,9 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
for (int row = 0; row < ui->interfaceTree->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->interfaceTree->topLevelItem(row);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
- if (!device->monitor_mode_supported || (device->monitor_mode_supported && !device->monitor_mode_enabled)) {
+ 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;
@@ -904,13 +853,18 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
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);
- guint device_idx = ti->data(col_interface_, Qt::UserRole).toUInt();
- device = &g_array_index(global_capture_opts.all_ifaces, interface_t, device_idx);
+ 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;
@@ -919,6 +873,7 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
}
}
}
+#endif
}
}
if (!prefs.gui_use_pref_save) {
@@ -927,6 +882,21 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
return true;
}
+void CaptureInterfacesDialog::updateSelectedFilter()
+{
+ // Should match MainWelcome::interfaceSelected.
+ QPair <const QString, bool> 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 CaptureInterfacesDialog::on_manage_clicked()
{
if (saveOptionsToPreferences()) {
@@ -951,6 +921,17 @@ void CaptureInterfacesDialog::changeEvent(QEvent* event)
QDialog::changeEvent(event);
}
+interface_t *CaptureInterfacesDialog::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
//
diff --git a/ui/qt/capture_interfaces_dialog.h b/ui/qt/capture_interfaces_dialog.h
index 0c38cf310e..e990c4bace 100644
--- a/ui/qt/capture_interfaces_dialog.h
+++ b/ui/qt/capture_interfaces_dialog.h
@@ -79,6 +79,9 @@ public:
void SetTab(int index);
void updateInterfaces();
+protected:
+ virtual void showEvent(QShowEvent *);
+
private slots:
void on_capturePromModeCheckBox_toggled(bool checked);
void on_gbStopCaptureAuto_toggled(bool checked);
@@ -94,7 +97,6 @@ private slots:
void start_button_clicked();
void on_buttonBox_rejected();
void on_buttonBox_helpRequested();
- void interfaceClicked(QTreeWidgetItem *item, int column);
void interfaceSelected();
void filterEdited();
void updateWidgets();
@@ -113,6 +115,7 @@ signals:
void interfacesChanged();
void ifsChanged();
void interfaceListChanged();
+ void captureFilterTextEdited(const QString & text);
private:
Ui::CaptureInterfacesDialog *ui;
@@ -124,7 +127,9 @@ private:
QTimer *stat_timer_;
InterfaceTreeDelegate interface_item_delegate_;
+ interface_t *getDeviceByName(const QString device_name);
bool saveOptionsToPreferences();
+ void updateSelectedFilter();
};
#endif /* HAVE_LIBPCAP */
diff --git a/ui/qt/interface_tree.cpp b/ui/qt/interface_tree.cpp
index 3f7fa7d849..67b0c12d8c 100644
--- a/ui/qt/interface_tree.cpp
+++ b/ui/qt/interface_tree.cpp
@@ -45,7 +45,21 @@
#include <QHeaderView>
#include <QTimer>
-// To do:
+// The interface list and capture filter editor in the main window and
+// the capture interfaces dialog should have the following behavior:
+//
+// - The global capture options are the source of truth for selected
+// interfaces.
+// - The global capture options are the source of truth for the capture
+// filter for an interface.
+// - If multiple interfaces with different filters are selected, the
+// CaptureFilterEdit should be cleared and show a corresponding
+// placeholder message. Device cfilters should not be changed.
+// - Entering a filter in a CaptureFilterEdit should update the device
+// cfilter for each selected interface. This should happen even when
+// conflicting filters are selected, as described above.
+// - Interface selections and cfilter changes in CaptureInterfacesDialog
+// should be reflected in MainWelcome.
#ifdef HAVE_LIBPCAP
const int stat_update_interval_ = 1000; // ms
@@ -81,7 +95,7 @@ InterfaceTree::InterfaceTree(QWidget *parent) :
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(getInterfaceList()));
connect(wsApp, SIGNAL(localInterfaceListChanged()), this, SLOT(interfaceListChanged()));
- connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(updateSelectedInterfaces()));
+ connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(selectedInterfaceChanged()));
}
InterfaceTree::~InterfaceTree() {
@@ -181,6 +195,7 @@ void InterfaceTree::display()
QList<QTreeWidgetItem *> phys_ifaces;
QList<QTreeWidgetItem *> virt_ifaces;
+ global_capture_opts.num_selected = 0;
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
@@ -192,31 +207,6 @@ void InterfaceTree::display()
InterfaceTreeWidgetItem *ti = new InterfaceTreeWidgetItem();
ti->setText(IFTREE_COL_NAME, QString().fromUtf8(device.display_name));
- // To do:
- // - Sync with code in CaptureInterfacesDialog.
- // - Add more information to the tooltip.
- QString tt_str = "<p>";
- if (device.no_addresses > 0) {
- tt_str += QString("%1: %2").arg(device.no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device.addresses);
- tt_str.replace('\n', ", ");
- } else {
- tt_str = tr("No addresses");
- }
- tt_str += "<br/>";
- QString cfilter = gchar_free_to_qstring(capture_dev_user_cfilter_find(device.name));
- if (cfilter.isEmpty()) {
- tt_str += tr("No capture filter");
- } else {
- tt_str += QString("%1: %2")
- .arg(tr("Capture filter"))
- .arg(cfilter);
- }
- tt_str += "</p>";
-
- for (int col = 0; col < columnCount(); col++) {
- ti->setToolTip(col, tt_str);
- }
-
ti->setData(IFTREE_COL_NAME, Qt::UserRole, QString(device.name));
ti->setData(IFTREE_COL_STATS, Qt::UserRole, qVariantFromValue(&ti->points));
#if HAVE_EXTCAP
@@ -251,7 +241,8 @@ void InterfaceTree::display()
if (!phys_ifaces.isEmpty()) addTopLevelItems(phys_ifaces);
if (!virt_ifaces.isEmpty()) addTopLevelItems(virt_ifaces);
- setSelectedInterfaces();
+ updateSelectedInterfaces();
+ updateToolTips();
// XXX Add other device information
resizeColumnToContents(IFTREE_COL_NAME);
@@ -358,15 +349,19 @@ void InterfaceTree::updateStatistics(void) {
#endif // HAVE_LIBPCAP
}
-void InterfaceTree::updateSelectedInterfaces()
+// Update our global device selections based on the given TreeWidget.
+// This is shared with CaptureInterfacesDialog.
+// Column name_col UserRole data MUST be set to the interface name.
+void InterfaceTree::updateGlobalDeviceSelections(QTreeWidget *if_tree, int name_col)
{
+ if (!if_tree) return;
#ifdef HAVE_LIBPCAP
- QTreeWidgetItemIterator iter(this);
+ QTreeWidgetItemIterator iter(if_tree);
global_capture_opts.num_selected = 0;
while (*iter) {
- QString device_name = (*iter)->data(IFTREE_COL_NAME, Qt::UserRole).value<QString>();
+ QString device_name = (*iter)->data(name_col, Qt::UserRole).value<QString>();
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) {
@@ -388,18 +383,21 @@ void InterfaceTree::updateSelectedInterfaces()
break;
}
}
- iter++;
+ ++iter;
}
- emit interfacesUpdated();
#endif // HAVE_LIBPCAP
}
-void InterfaceTree::setSelectedInterfaces()
+// Update selected interfaces based on the global interface list..
+// Must not change any interface data.
+// Must not emit itemSelectionChanged.
+void InterfaceTree::updateSelectedInterfaces()
{
#ifdef HAVE_LIBPCAP
interface_t *device;
QTreeWidgetItemIterator iter(this);
+ bool blocking = blockSignals(true);
while (*iter) {
QString device_name = (*iter)->data(IFTREE_COL_NAME, Qt::UserRole).value<QString>();
@@ -412,6 +410,50 @@ void InterfaceTree::setSelectedInterfaces()
}
iter++;
}
+ blockSignals(blocking);
+#endif // HAVE_LIBPCAP
+}
+
+// Update the tooltip for each interface based on the global interface list..
+// Must not change any interface data.
+void InterfaceTree::updateToolTips()
+{
+#ifdef HAVE_LIBPCAP
+ QTreeWidgetItemIterator iter(this);
+
+ while (*iter) {
+ QString device_name = (*iter)->data(IFTREE_COL_NAME, Qt::UserRole).value<QString>();
+ 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) {
+ // To do:
+ // - Sync with code in CaptureInterfacesDialog.
+ // - Add more information to the tooltip.
+ QString tt_str = "<p>";
+ if (device.no_addresses > 0) {
+ tt_str += QString("%1: %2").arg(device.no_addresses > 1 ? tr("Addresses") : tr("Address")).arg(device.addresses);
+ tt_str.replace('\n', ", ");
+ } else {
+ tt_str = tr("No addresses");
+ }
+ tt_str += "<br/>";
+ QString cfilter = device.cfilter;
+ if (cfilter.isEmpty()) {
+ tt_str += tr("No capture filter");
+ } else {
+ tt_str += QString("%1: %2")
+ .arg(tr("Capture filter"))
+ .arg(cfilter);
+ }
+ tt_str += "</p>";
+
+ for (int col = 0; col < columnCount(); col++) {
+ (*iter)->setToolTip(col, tt_str);
+ }
+ }
+ }
+ ++iter;
+ }
#endif // HAVE_LIBPCAP
}
diff --git a/ui/qt/interface_tree.h b/ui/qt/interface_tree.h
index 0fc2e0f7c3..decba6a929 100644
--- a/ui/qt/interface_tree.h
+++ b/ui/qt/interface_tree.h
@@ -58,6 +58,9 @@ public:
void resetColumnCount();
+ // Used by CaptureInterfacesDialog.
+ static void updateGlobalDeviceSelections(QTreeWidget *if_tree, int name_col);
+
protected:
void hideEvent(QHideEvent *evt);
void showEvent(QShowEvent *evt);
@@ -71,7 +74,6 @@ private:
#endif // HAVE_LIBPCAP
signals:
- void interfacesUpdated();
public slots:
// add_interface_to_list
@@ -79,13 +81,14 @@ public slots:
// change_interface_selection_for_all
//void getPoints(int row, QList<int> *pts);
void getPoints(int row, PointList *pts);
- void setSelectedInterfaces();
void interfaceListChanged();
+ void selectedInterfaceChanged() { updateGlobalDeviceSelections(this, IFTREE_COL_NAME); }
+ void updateSelectedInterfaces();
+ void updateToolTips();
private slots:
void getInterfaceList();
void updateStatistics(void);
- void updateSelectedInterfaces();
};
diff --git a/ui/qt/main_welcome.cpp b/ui/qt/main_welcome.cpp
index a789132f78..94ac30f399 100644
--- a/ui/qt/main_welcome.cpp
+++ b/ui/qt/main_welcome.cpp
@@ -171,8 +171,9 @@ MainWelcome::MainWelcome(QWidget *parent) :
connect(welcome_ui_->interfaceTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
this, SLOT(interfaceClicked(QTreeWidgetItem*,int)));
#endif
- connect(welcome_ui_->interfaceTree, SIGNAL(interfacesUpdated()),
+ connect(welcome_ui_->interfaceTree, SIGNAL(itemSelectionChanged()),
welcome_ui_->captureFilterComboBox, SIGNAL(interfacesChanged()));
+ connect(welcome_ui_->interfaceTree, SIGNAL(itemSelectionChanged()), this, SLOT(interfaceSelected()));
connect(welcome_ui_->captureFilterComboBox->lineEdit(), SIGNAL(textEdited(QString)),
this, SLOT(captureFilterTextEdited(QString)));
connect(welcome_ui_->captureFilterComboBox, SIGNAL(pushFilterSyntaxStatus(const QString&)),
@@ -242,6 +243,13 @@ void MainWelcome::appInitialized()
welcome_ui_->childContainer->setGraphicsEffect(NULL);
#endif
+#ifdef HAVE_LIBPCAP
+ welcome_ui_->captureFilterComboBox->lineEdit()->setText(global_capture_opts.default_options.cfilter);
+#endif // HAVE_LIBPCAP
+
+ // Trigger interfacesUpdated.
+ welcome_ui_->interfaceTree->selectedInterfaceChanged();
+
delete splash_overlay_;
splash_overlay_ = NULL;
}
@@ -275,6 +283,26 @@ void MainWelcome::captureFilterTextEdited(const QString capture_filter)
// update_filter_string(device.name, filter_text);
}
}
+ welcome_ui_->interfaceTree->updateToolTips();
+}
+
+// The interface list selection has changed. At this point the user might
+// have entered a filter or we might have pre-filled one from a number of
+// sources such as our remote connection, the command line, or a previous
+// selection.
+// Must not change any interface data.
+void MainWelcome::interfaceSelected()
+{
+ QPair <const QString, bool> sf_pair = CaptureFilterEdit::getSelectedFilter();
+ const QString user_filter = sf_pair.first;
+ bool conflict = sf_pair.second;
+
+ if (conflict) {
+ welcome_ui_->captureFilterComboBox->lineEdit()->clear();
+ welcome_ui_->captureFilterComboBox->setConflict(true);
+ } else {
+ welcome_ui_->captureFilterComboBox->lineEdit()->setText(user_filter);
+ }
}
void MainWelcome::interfaceDoubleClicked(QTreeWidgetItem *item, int)
@@ -382,6 +410,12 @@ void MainWelcome::resizeEvent(QResizeEvent *event)
QFrame::resizeEvent(event);
}
+void MainWelcome::setCaptureFilterText(const QString capture_filter)
+{
+ welcome_ui_->captureFilterComboBox->lineEdit()->setText(capture_filter);
+ captureFilterTextEdited(capture_filter);
+}
+
void MainWelcome::changeEvent(QEvent* event)
{
if (0 != event)
diff --git a/ui/qt/main_welcome.h b/ui/qt/main_welcome.h
index 4118d0668a..d6d7f13c84 100644
--- a/ui/qt/main_welcome.h
+++ b/ui/qt/main_welcome.h
@@ -45,6 +45,9 @@ public:
const QString captureFilter();
void setCaptureFilter(const QString capture_filter);
+public slots:
+ void interfaceSelected();
+
protected:
void resizeEvent(QResizeEvent *event);
@@ -69,6 +72,9 @@ signals:
void showExtcapOptions(QString &device_name);
#endif
+public slots:
+ void setCaptureFilterText(const QString capture_filter);
+
private slots:
void appInitialized();
void captureFilterTextEdited(const QString capture_filter);
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 25f501363a..e604c5c708 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -653,10 +653,19 @@ MainWindow::MainWindow(QWidget *parent) :
connect(&capture_interfaces_dialog_, SIGNAL(getPoints(int,PointList*)),
this->main_welcome_->getInterfaceTree(), SLOT(getPoints(int,PointList*)));
- connect(&capture_interfaces_dialog_, SIGNAL(setSelectedInterfaces()),
- this->main_welcome_->getInterfaceTree(), SLOT(setSelectedInterfaces()));
+ // 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(&capture_interfaces_dialog_, SIGNAL(interfaceListChanged()),
this->main_welcome_->getInterfaceTree(), SLOT(interfaceListChanged()));
+ connect(&capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
+ this->main_welcome_, SLOT(interfaceSelected()));
+ connect(&capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
+ this->main_welcome_->getInterfaceTree(), SLOT(updateSelectedInterfaces()));
+ connect(&capture_interfaces_dialog_, SIGNAL(interfacesChanged()),
+ this->main_welcome_->getInterfaceTree(), SLOT(updateToolTips()));
+ connect(&capture_interfaces_dialog_, SIGNAL(captureFilterTextEdited(QString)),
+ this->main_welcome_, SLOT(setCaptureFilterText(QString)));
#endif
/* Create plugin_if hooks */