diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ui/Makefile.am | 2 | ||||
-rw-r--r-- | ui/iface_toolbar.c | 68 | ||||
-rw-r--r-- | ui/iface_toolbar.h | 105 | ||||
-rw-r--r-- | ui/qt/CMakeLists.txt | 7 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 10 | ||||
-rw-r--r-- | ui/qt/funnel_text_dialog.cpp | 2 | ||||
-rw-r--r-- | ui/qt/interface_toolbar.cpp | 895 | ||||
-rw-r--r-- | ui/qt/interface_toolbar.h | 120 | ||||
-rw-r--r-- | ui/qt/interface_toolbar.ui | 69 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_lineedit.cpp | 149 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_lineedit.h | 71 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_reader.cpp | 140 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_reader.h | 65 | ||||
-rw-r--r-- | ui/qt/main_window.cpp | 126 | ||||
-rw-r--r-- | ui/qt/main_window.h | 6 | ||||
-rw-r--r-- | ui/qt/main_window.ui | 6 | ||||
-rw-r--r-- | ui/qt/main_window_slots.cpp | 40 | ||||
-rw-r--r-- | ui/recent.c | 14 | ||||
-rw-r--r-- | ui/recent.h | 1 |
20 files changed, 1890 insertions, 7 deletions
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 8a52ef9463..e02eab1c6e 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -34,6 +34,7 @@ set(COMMON_UI_SRC failure_message.c filter_files.c firewall_rules.c + iface_toolbar.c iface_lists.c io_graph_item.c language.c diff --git a/ui/Makefile.am b/ui/Makefile.am index 776ad4230b..49699c6615 100644 --- a/ui/Makefile.am +++ b/ui/Makefile.am @@ -60,6 +60,7 @@ WIRESHARK_UI_SRC = \ failure_message.c \ filter_files.c \ firewall_rules.c \ + iface_toolbar.c \ iface_lists.c \ io_graph_item.c \ language.c \ @@ -109,6 +110,7 @@ WIRESHARK_UI_INCLUDES = \ help_url.h \ packet_list_utils.h \ firewall_rules.h \ + iface_toolbar.h \ iface_lists.h \ io_graph_item.h \ language.h \ diff --git a/ui/iface_toolbar.c b/ui/iface_toolbar.c new file mode 100644 index 0000000000..0e16456ee4 --- /dev/null +++ b/ui/iface_toolbar.c @@ -0,0 +1,68 @@ +/* iface_toolbar.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib.h> + +#include "iface_toolbar.h" + + +static iface_toolbar_add_cb_t iface_toolbar_add_cb; +static iface_toolbar_remove_cb_t iface_toolbar_remove_cb; + +void iface_toolbar_add(const iface_toolbar *toolbar) +{ + if (iface_toolbar_add_cb) { + iface_toolbar_add_cb(toolbar); + } +} + +void iface_toolbar_remove(const gchar *menu_title) +{ + if (iface_toolbar_remove_cb) { + iface_toolbar_remove_cb(menu_title); + } +} + +gboolean iface_toolbar_use(void) +{ + return iface_toolbar_add_cb ? TRUE : FALSE; +} + +void iface_toolbar_register_cb(iface_toolbar_add_cb_t add_cb, iface_toolbar_remove_cb_t remove_cb) +{ + iface_toolbar_add_cb = add_cb; + iface_toolbar_remove_cb = remove_cb; +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/iface_toolbar.h b/ui/iface_toolbar.h new file mode 100644 index 0000000000..888c817230 --- /dev/null +++ b/ui/iface_toolbar.h @@ -0,0 +1,105 @@ +/* iface_toolbar.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __IFACE_TOOLBAR_H__ +#define __IFACE_TOOLBAR_H__ + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + INTERFACE_TYPE_UNKNOWN, + INTERFACE_TYPE_BOOLEAN, + INTERFACE_TYPE_BUTTON, + INTERFACE_TYPE_SELECTOR, + INTERFACE_TYPE_STRING +} iface_toolbar_ctrl_type; + +typedef enum { + INTERFACE_ROLE_UNKNOWN, + INTERFACE_ROLE_CONTROL, + INTERFACE_ROLE_HELP, + INTERFACE_ROLE_LOGGER, + INTERFACE_ROLE_RESET +} iface_toolbar_ctrl_role; + +typedef struct _iface_toolbar_value { + int num; + gchar *value; + gchar *display; + gboolean is_default; +} iface_toolbar_value; + +typedef struct _iface_toolbar_control { + int num; + iface_toolbar_ctrl_type ctrl_type; + iface_toolbar_ctrl_role ctrl_role; + gchar *display; + gchar *validation; + gboolean is_required; + gchar *tooltip; + gchar *placeholder; + union { + gboolean boolean; + gchar *string; + } default_value; + GList *values; +} iface_toolbar_control; + +typedef struct _iface_toolbar { + gchar *menu_title; + gchar *help; + GList *ifnames; + GList *controls; +} iface_toolbar; + +typedef void (*iface_toolbar_add_cb_t)(const iface_toolbar *); +typedef void (*iface_toolbar_remove_cb_t)(const gchar *); + +void iface_toolbar_add(const iface_toolbar *toolbar); + +void iface_toolbar_remove(const gchar *menu_title); + +gboolean iface_toolbar_use(void); + +void iface_toolbar_register_cb(iface_toolbar_add_cb_t, iface_toolbar_remove_cb_t); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IFACE_TOOLBAR_H__ */ + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index e8936e9119..ca3d67f530 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -87,6 +87,9 @@ set(WIRESHARK_QT_HEADERS gsm_map_summary_dialog.h iax2_analysis_dialog.h import_text_dialog.h + interface_toolbar.h + interface_toolbar_reader.h + interface_toolbar_lineedit.h interface_tree_model.h interface_tree_cache_model.h interface_sort_filter_model.h @@ -257,6 +260,9 @@ set(WIRESHARK_QT_SRC geometry_state_dialog.cpp iax2_analysis_dialog.cpp import_text_dialog.cpp + interface_toolbar.cpp + interface_toolbar_reader.cpp + interface_toolbar_lineedit.cpp interface_tree_model.cpp interface_tree_cache_model.cpp interface_sort_filter_model.cpp @@ -418,6 +424,7 @@ set(WIRESHARK_QT_UI iax2_analysis_dialog.ui import_text_dialog.ui interface_frame.ui + interface_toolbar.ui io_graph_dialog.ui layout_preferences_frame.ui lbm_lbtrm_transport_dialog.ui diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index 77d17ea449..7f52918fcf 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -70,6 +70,7 @@ NODIST_GENERATED_HEADER_FILES = \ ui_iax2_analysis_dialog.h \ ui_import_text_dialog.h \ ui_interface_frame.h \ + ui_interface_toolbar.h \ ui_io_graph_dialog.h \ ui_layout_preferences_frame.h \ ui_lbm_lbtrm_transport_dialog.h \ @@ -215,6 +216,9 @@ MOC_HDRS = \ iax2_analysis_dialog.h \ import_text_dialog.h \ interface_frame.h \ + interface_toolbar.h \ + interface_toolbar_lineedit.h \ + interface_toolbar_reader.h \ interface_tree_model.h \ interface_tree_cache_model.h \ interface_sort_filter_model.h \ @@ -340,6 +344,7 @@ UI_FILES = \ iax2_analysis_dialog.ui \ import_text_dialog.ui \ interface_frame.ui \ + interface_toolbar.ui \ io_graph_dialog.ui \ layout_preferences_frame.ui \ lbm_lbtrm_transport_dialog.ui \ @@ -499,6 +504,9 @@ WIRESHARK_QT_SRC = \ iax2_analysis_dialog.cpp \ import_text_dialog.cpp \ interface_frame.cpp \ + interface_toolbar.cpp \ + interface_toolbar_lineedit.cpp \ + interface_toolbar_reader.cpp \ interface_tree_model.cpp \ interface_tree_cache_model.cpp \ interface_sort_filter_model.cpp \ @@ -822,6 +830,8 @@ io_graph_dialog.$(OBJEXT): ui_io_graph_dialog.h interface_frame.$(OBJEXT): ui_interface_frame.h +interface_toolbar.$(OBJEXT): ui_interface_toolbar.h + layout_preferences_frame.$(OBJEXT): ui_layout_preferences_frame.h lbm_lbtrm_transport_dialog.$(OBJEXT): ui_lbm_lbtrm_transport_dialog.h diff --git a/ui/qt/funnel_text_dialog.cpp b/ui/qt/funnel_text_dialog.cpp index 6ba873f451..8be47b032c 100644 --- a/ui/qt/funnel_text_dialog.cpp +++ b/ui/qt/funnel_text_dialog.cpp @@ -47,6 +47,7 @@ FunnelTextDialog::FunnelTextDialog(const QString &title) : if (!title.isEmpty()) { loadGeometry(0, 0, QString("Funnel %1").arg(title)); } + setWindowTitle(wsApp->windowTitleString(title)); funnel_text_window_.funnel_text_dialog = this; @@ -75,7 +76,6 @@ void FunnelTextDialog::reject() struct _funnel_text_window_t *FunnelTextDialog::textWindowNew(const QString title) { FunnelTextDialog *ftd = new FunnelTextDialog(title); - ftd->setWindowTitle(wsApp->windowTitleString(title)); ftd->show(); return &ftd->funnel_text_window_; } diff --git a/ui/qt/interface_toolbar.cpp b/ui/qt/interface_toolbar.cpp new file mode 100644 index 0000000000..56a1a53b34 --- /dev/null +++ b/ui/qt/interface_toolbar.cpp @@ -0,0 +1,895 @@ +/* interface_toolbar.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <errno.h> + +#include "interface_toolbar.h" +#include "interface_toolbar_lineedit.h" +#include "simple_dialog.h" +#include "ui/main_statusbar.h" +#include <ui_interface_toolbar.h> + +#include "sync_pipe.h" +#include "wsutil/file_util.h" + +#include <QCheckBox> +#include <QComboBox> +#include <QDesktopServices> +#include <QLineEdit> +#include <QPushButton> +#include <QThread> +#include <QUrl> + +static const char *interface_type_property = "control_type"; +static const char *interface_role_property = "control_role"; + +// From interface control protocol. +enum InterfaceControlCommand { + commandControlInitialized = 0, + commandControlSet = 1, + commandControlAdd = 2, + commandControlRemove = 3, + commandControlEnable = 4, + commandControlDisable = 5, + commandStatusMessage = 6, + commandInformationMessage = 7, + commandWarningMessage = 8, + commandErrorMessage = 9, +}; + +// To do: +// - Move control pipe handling to extcap + +InterfaceToolbar::InterfaceToolbar(QWidget *parent, const iface_toolbar *toolbar) : + QFrame(parent), + ui(new Ui::InterfaceToolbar), + help_link_(toolbar->help), + use_spacer_(true) +{ + ui->setupUi(this); + + // Fill inn interfaces list and initialize default interface values + ui->interfacesComboBox->blockSignals(true); + for (GList *walker = toolbar->ifnames; walker; walker = walker->next) + { + QString ifname((gchar *)walker->data); + ui->interfacesComboBox->addItem(ifname); + interface_[ifname].reader_thread = NULL; + interface_[ifname].out_fd = -1; + interface_[ifname].log_dialog = NULL; + } + ui->interfacesComboBox->blockSignals(false); + + initializeControls(toolbar); + +#ifdef Q_OS_MAC + foreach (QWidget *w, findChildren<QWidget *>()) + { + w->setAttribute(Qt::WA_MacSmallSize, true); + } +#endif + + if (!use_spacer_) + { + ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Fixed, QSizePolicy::Fixed); + } + + updateWidgets(); +} + +InterfaceToolbar::~InterfaceToolbar() +{ + foreach (QString ifname, interface_.keys()) + { + if (interface_[ifname].log_dialog) + { + interface_[ifname].log_dialog->close(); + } + } + + delete ui; +} + +void InterfaceToolbar::initializeControls(const iface_toolbar *toolbar) +{ + for (GList *walker = toolbar->controls; walker; walker = walker->next) + { + iface_toolbar_control *control = (iface_toolbar_control *)walker->data; + + if (control_widget_.contains(control->num)) + { + // Already have a widget with this number + continue; + } + + QWidget *widget = NULL; + switch (control->ctrl_type) + { + case INTERFACE_TYPE_BOOLEAN: + widget = createCheckbox(control); + break; + + case INTERFACE_TYPE_BUTTON: + widget = createButton(control); + break; + + case INTERFACE_TYPE_SELECTOR: + widget = createSelector(control); + break; + + case INTERFACE_TYPE_STRING: + widget = createString(control); + break; + + default: + // Not supported + break; + } + + if (widget) + { + widget->setProperty(interface_type_property, control->ctrl_type); + widget->setProperty(interface_role_property, control->ctrl_role); + control_widget_[control->num] = widget; + } + } +} + +void InterfaceToolbar::setDefaultValue(int num, const QByteArray &value) +{ + foreach (QString ifname, interface_.keys()) + { + // Adding default value to all interfaces + interface_[ifname].value[num] = value; + } + default_value_[num] = value; +} + +QWidget *InterfaceToolbar::createCheckbox(iface_toolbar_control *control) +{ + QCheckBox *checkbox = new QCheckBox(QString().fromUtf8(control->display)); + checkbox->setToolTip(QString().fromUtf8(control->tooltip)); + + if (control->default_value.boolean) + { + checkbox->setCheckState(Qt::Checked); + QByteArray default_value(1, 1); + setDefaultValue(control->num, default_value); + } + + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onCheckBoxChanged(int))); + + ui->leftLayout->addWidget(checkbox); + + return checkbox; +} + +QWidget *InterfaceToolbar::createButton(iface_toolbar_control *control) +{ + QPushButton *button = new QPushButton(QString().fromUtf8((gchar *)control->display)); + button->setMaximumHeight(27); + button->setToolTip(QString().fromUtf8(control->tooltip)); + + switch (control->ctrl_role) + { + case INTERFACE_ROLE_CONTROL: + setDefaultValue(control->num, (gchar *)control->display); + connect(button, SIGNAL(pressed()), this, SLOT(onButtonPressed())); + break; + + case INTERFACE_ROLE_HELP: + connect(button, SIGNAL(pressed()), this, SLOT(onHelpButtonPressed())); + if (help_link_.isEmpty()) + { + // No help URL provided + button->hide(); + } + break; + + case INTERFACE_ROLE_LOGGER: + connect(button, SIGNAL(pressed()), this, SLOT(onLogButtonPressed())); + break; + + case INTERFACE_ROLE_RESET: + button->setText("Reset"); + button->setToolTip("Restore default values"); + connect(button, SIGNAL(pressed()), this, SLOT(onResetButtonPressed())); + break; + + default: + break; + } + + ui->rightLayout->addWidget(button); + + return button; +} + +QWidget *InterfaceToolbar::createSelector(iface_toolbar_control *control) +{ + QLabel *label = new QLabel(QString().fromUtf8(control->display)); + label->setToolTip(QString().fromUtf8(control->tooltip)); + QComboBox *combobox = new QComboBox(); + combobox->setToolTip(QString().fromUtf8(control->tooltip)); + combobox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + + for (GList *walker = control->values; walker; walker = walker->next) + { + iface_toolbar_value *val = (iface_toolbar_value *)walker->data; + QString value = QString().fromUtf8((gchar *)val->value); + if (value.length() == 0) + { + // Invalid value + continue; + } + QString display = QString().fromUtf8((gchar *)val->display); + QByteArray interface_value; + + interface_value.append(value); + if (display.length() == 0) + { + display = value; + } + else + { + interface_value.append('\0' + display); + } + combobox->addItem(display, value); + if (val->is_default) + { + combobox->setCurrentText(display); + setDefaultValue(control->num, value.toUtf8()); + } + foreach (QString ifname, interface_.keys()) + { + // Adding values to all interfaces + interface_[ifname].list[control->num].append(interface_value); + } + default_list_[control->num].append(interface_value); + } + + connect(combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxChanged(int))); + + ui->leftLayout->addWidget(label); + ui->leftLayout->addWidget(combobox); + label_widget_[control->num] = label; + + return combobox; +} + +QWidget *InterfaceToolbar::createString(iface_toolbar_control *control) +{ + QLabel *label = new QLabel(QString().fromUtf8(control->display)); + label->setToolTip(QString().fromUtf8(control->tooltip)); + InterfaceToolbarLineEdit *lineedit = new InterfaceToolbarLineEdit(NULL, control->validation, control->is_required); + lineedit->setToolTip(QString().fromUtf8(control->tooltip)); + lineedit->setPlaceholderText(QString().fromUtf8(control->placeholder)); + + if (control->default_value.string) + { + lineedit->setText(QString().fromUtf8(control->default_value.string)); + setDefaultValue(control->num, control->default_value.string); + } + + connect(lineedit, SIGNAL(editedTextApplied()), this, SLOT(onLineEditChanged())); + + ui->leftLayout->addWidget(label); + ui->leftLayout->addWidget(lineedit); + label_widget_[control->num] = label; + use_spacer_ = false; + + return lineedit; +} + +void InterfaceToolbar::setWidgetValue(QWidget *widget, int command, QByteArray payload) +{ + if (QComboBox *combobox = dynamic_cast<QComboBox *>(widget)) + { + combobox->blockSignals(true); + switch (command) + { + case commandControlSet: + { + int idx = combobox->findData(payload); + if (idx != -1) + { + combobox->setCurrentIndex(idx); + } + break; + } + + case commandControlAdd: + { + QString value; + QString display; + if (payload.contains('\0')) + { + // The payload contains "value\0display" + QList<QByteArray> values = payload.split('\0'); + value = values[0]; + display = values[1]; + } + else + { + value = display = payload; + } + + int idx = combobox->findData(value); + if (idx != -1) + { + // The value already exists, update item text + combobox->setItemText(idx, display); + } + else + { + combobox->addItem(display, value); + } + break; + } + + case commandControlRemove: + { + if (payload.size() == 0) + { + combobox->clear(); + } + else + { + int idx = combobox->findData(payload); + if (idx != -1) + { + combobox->removeItem(idx); + } + } + break; + } + + default: + break; + } + combobox->blockSignals(false); + } + else if (InterfaceToolbarLineEdit *lineedit = dynamic_cast<InterfaceToolbarLineEdit *>(widget)) + { + // We don't block signals here because changes are applied with enter or apply button, + // and we want InterfaceToolbarLineEdit to always syntax check the text. + switch (command) + { + case commandControlSet: + lineedit->setText(payload); + lineedit->disableApplyButton(); + break; + + default: + break; + } + } + else if (QCheckBox *checkbox = dynamic_cast<QCheckBox *>(widget)) + { + checkbox->blockSignals(true); + switch (command) + { + case commandControlSet: + { + Qt::CheckState state = Qt::Unchecked; + if (payload.size() > 0 && payload.at(0) != 0) + { + state = Qt::Checked; + } + checkbox->setCheckState(state); + break; + } + + default: + break; + } + checkbox->blockSignals(false); + } + else if (QPushButton *button = dynamic_cast<QPushButton *>(widget)) + { + if ((command == commandControlSet) && + widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL) + { + button->setText(payload); + } + } +} + +void InterfaceToolbar::setInterfaceValue(QString ifname, QWidget *widget, int num, int command, QByteArray payload) +{ + if (dynamic_cast<QComboBox *>(widget)) + { + switch (command) + { + case commandControlSet: + foreach (QByteArray entry, interface_[ifname].list[num]) + { + if (entry == payload || entry.startsWith(payload + '\0')) + { + interface_[ifname].value[num] = payload; + } + } + break; + + case commandControlAdd: + interface_[ifname].list[num].append(payload); + break; + + case commandControlRemove: + if (payload.size() == 0) + { + interface_[ifname].value[num].clear(); + interface_[ifname].list[num].clear(); + } + else + { + foreach (QByteArray entry, interface_[ifname].list[num]) + { + if (entry == payload || entry.startsWith(payload + '\0')) + { + interface_[ifname].list[num].removeAll(entry); + } + } + } + break; + + default: + break; + } + } + else if (dynamic_cast<InterfaceToolbarLineEdit *>(widget)) + { + switch (command) + { + case commandControlSet: + interface_[ifname].value[num] = payload; + break; + + default: + break; + } + } + else if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) && + (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_LOGGER)) + { + if (command == commandControlSet) + { + if (interface_[ifname].log_dialog) + { + interface_[ifname].log_dialog->clearText(); + } + interface_[ifname].log_text.clear(); + } + if (command == commandControlSet || command == commandControlAdd) + { + if (interface_[ifname].log_dialog) + { + interface_[ifname].log_dialog->appendText(payload); + } + interface_[ifname].log_text.append(payload); + } + } + else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL) + { + // QCheckBox or QPushButton + interface_[ifname].value[num] = payload; + } +} + + +void InterfaceToolbar::controlReceived(QString ifname, int num, int command, QByteArray payload) +{ + switch (command) + { + case commandControlSet: + case commandControlAdd: + case commandControlRemove: + if (QWidget *widget = control_widget_[num]) + { + setInterfaceValue(ifname, widget, num, command, payload); + + if (ifname.compare(ui->interfacesComboBox->currentText()) == 0) + { + setWidgetValue(widget, command, payload); + } + } + break; + + case commandControlEnable: + case commandControlDisable: + if (QWidget *widget = control_widget_[num]) + { + if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL) + { + bool enable = (command == commandControlEnable ? true : false); + interface_[ifname].widget_disabled[num] = !enable; + + if (ifname.compare(ui->interfacesComboBox->currentText()) == 0) + { + widget->setEnabled(enable); + if (label_widget_.contains(num)) + { + label_widget_[num]->setEnabled(enable); + } + } + } + } + break; + + case commandStatusMessage: + statusbar_push_temporary_msg("%s", payload.data()); + break; + + case commandInformationMessage: + simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%s", payload.data()); + break; + + case commandWarningMessage: + simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%s", payload.data()); + break; + + case commandErrorMessage: + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", payload.data()); + break; + + default: + // Unknown commands are silently ignored + break; + } +} + +void InterfaceToolbar::controlSend(QString ifname, int num, int command, const QByteArray &payload = QByteArray()) +{ + if (payload.length() > 65535) + { + // Not supported + return; + } + + if (interface_[ifname].out_fd == -1) + { + // Does not have a control out channel + return; + } + + ssize_t payload_length = payload.length() + 2; + unsigned char high_nibble = (payload_length >> 16) & 0xFF; + unsigned char mid_nibble = (payload_length >> 8) & 0xFF; + unsigned char low_nibble = (payload_length >> 0) & 0xFF; + + QByteArray ba; + + ba.append(SP_TOOLBAR_CTRL); + ba.append(high_nibble); + ba.append(mid_nibble); + ba.append(low_nibble); + ba.append(num); + ba.append(command); + ba.append(payload); + + if (ws_write(interface_[ifname].out_fd, ba.data(), ba.length()) != ba.length()) + { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Unable to send control message:\n%s.", + g_strerror(errno)); + } +} + +void InterfaceToolbar::onButtonPressed() +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + QPushButton *button = static_cast<QPushButton *>(sender()); + int num = control_widget_.key(button); + + controlSend(ifname, num, commandControlSet); +} + +void InterfaceToolbar::onCheckBoxChanged(int state) +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + QCheckBox *checkbox = static_cast<QCheckBox *>(sender()); + int num = control_widget_.key(checkbox); + + QByteArray payload(1, state == Qt::Unchecked ? 0 : 1); + controlSend(ifname, num, commandControlSet, payload); + interface_[ifname].value[num] = payload; +} + +void InterfaceToolbar::onComboBoxChanged(int idx) +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + QComboBox *combobox = static_cast<QComboBox *>(sender()); + int num = control_widget_.key(combobox); + QString value = combobox->itemData(idx).toString(); + + QByteArray payload(value.toUtf8()); + controlSend(ifname, num, commandControlSet, payload); + interface_[ifname].value[num] = payload; +} + +void InterfaceToolbar::onLineEditChanged() +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + InterfaceToolbarLineEdit *lineedit = static_cast<InterfaceToolbarLineEdit *>(sender()); + int num = control_widget_.key(lineedit); + + QByteArray payload(lineedit->text().toUtf8()); + controlSend(ifname, num, commandControlSet, payload); + interface_[ifname].value[num] = payload; +} + +void InterfaceToolbar::onLogButtonPressed() +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + + if (!interface_[ifname].log_dialog) + { + QPushButton *button = static_cast<QPushButton *>(sender()); + interface_[ifname].log_dialog = new FunnelTextDialog(ifname + " " + button->text()); + connect(interface_[ifname].log_dialog, SIGNAL(accepted()), this, SLOT(closeLog())); + connect(interface_[ifname].log_dialog, SIGNAL(rejected()), this, SLOT(closeLog())); + + interface_[ifname].log_dialog->setText(interface_[ifname].log_text); + } + + interface_[ifname].log_dialog->show(); + interface_[ifname].log_dialog->raise(); + interface_[ifname].log_dialog->activateWindow(); +} + +void InterfaceToolbar::onHelpButtonPressed() +{ + QUrl help_url(help_link_); + + if (help_url.scheme().compare("file") != 0) { + QDesktopServices::openUrl(help_url); + } +} + +void InterfaceToolbar::closeLog() +{ + FunnelTextDialog *log_dialog = static_cast<FunnelTextDialog *>(sender()); + + foreach (QString ifname, interface_.keys()) + { + if (interface_[ifname].log_dialog == log_dialog) + { + interface_[ifname].log_dialog = NULL; + } + } +} + +void InterfaceToolbar::startReaderThread(QString ifname, QString control_in) +{ + QThread *thread = new QThread; + InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in); + reader->moveToThread(thread); + + connect(thread, SIGNAL(started()), reader, SLOT(loop())); + connect(reader, SIGNAL(finished()), thread, SLOT(quit())); + connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(reader, SIGNAL(received(QString, int, int, QByteArray)), + this, SLOT(controlReceived(QString, int, int, QByteArray))); + + interface_[ifname].reader_thread = thread; + + thread->start(); +} + +void InterfaceToolbar::startCapture(QString ifname, QString control_in, QString control_out) +{ + if (!interface_.contains(ifname) || // This interface is not for us + interface_[ifname].out_fd != -1) // Already have control channels for this interface + { + return; + } + + // The reader thread will open control in channel + startReaderThread(ifname, control_in); + + // Open control out channel + interface_[ifname].out_fd = ws_open(control_out.toUtf8(), O_WRONLY | O_BINARY, 0); + + sendChangedValues(ifname); + controlSend(ifname, 0, commandControlInitialized); + + updateWidgets(); +} + +void InterfaceToolbar::stopCapture() +{ + foreach (QString ifname, interface_.keys()) + { + if (interface_[ifname].reader_thread) + { +#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) + interface_[ifname].reader_thread->requestInterruption(); +#endif + interface_[ifname].reader_thread = NULL; + } + + if (interface_[ifname].out_fd != -1) + { + ws_close (interface_[ifname].out_fd); + interface_[ifname].out_fd = -1; + } + + foreach (int num, control_widget_.keys()) + { + // Reset disabled property for all widgets + interface_[ifname].widget_disabled[num] = false; + + QWidget *widget = control_widget_[num]; + if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) && + (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)) + { + // Reset default value for control buttons + interface_[ifname].value[num] = default_value_[num]; + + if (ifname.compare(ui->interfacesComboBox->currentText()) == 0) + { + setWidgetValue(widget, commandControlSet, default_value_[num]); + } + } + } + } + + updateWidgets(); +} + +void InterfaceToolbar::sendChangedValues(QString ifname) +{ + // Send all values which has changed + foreach (int num, control_widget_.keys()) + { + QWidget *widget = control_widget_[num]; + if ((interface_[ifname].value[num] != default_value_[num]) && + (widget->property(interface_type_property).toInt() != INTERFACE_TYPE_BUTTON) && + (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)) + { + controlSend(ifname, num, commandControlSet, interface_[ifname].value[num]); + } + } +} + +void InterfaceToolbar::onResetButtonPressed() +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + + // Set default values to all widgets and interfaces + foreach (int num, control_widget_.keys()) + { + QWidget *widget = control_widget_[num]; + if (default_list_[num].size() > 0) + { + // This is a QComboBox. Clear list and add new entries. + setWidgetValue(widget, commandControlRemove, QByteArray()); + interface_[ifname].list[num].clear(); + + foreach (QByteArray value, default_list_[num]) + { + setWidgetValue(widget, commandControlAdd, value); + interface_[ifname].list[num].append(value); + } + } + + switch (widget->property(interface_role_property).toInt()) + { + case INTERFACE_ROLE_CONTROL: + setWidgetValue(widget, commandControlSet, default_value_[num]); + interface_[ifname].value[num] = default_value_[num]; + break; + + case INTERFACE_ROLE_LOGGER: + if (interface_[ifname].log_dialog) + { + interface_[ifname].log_dialog->clearText(); + } + interface_[ifname].log_text.clear(); + break; + + default: + break; + } + } +} + +bool InterfaceToolbar::hasInterface(QString ifname) +{ + return interface_.contains(ifname); +} + +void InterfaceToolbar::updateWidgets() +{ + const QString &ifname = ui->interfacesComboBox->currentText(); + bool is_capturing = (interface_[ifname].out_fd == -1 ? false : true); + + foreach (int num, control_widget_.keys()) + { + QWidget *widget = control_widget_[num]; + if (!is_capturing && + (widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) && + (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)) + { + widget->setEnabled(false); + } + else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL) + { + bool widget_enabled = !interface_[ifname].widget_disabled[num]; + widget->setEnabled(widget_enabled); + if (label_widget_.contains(num)) + { + label_widget_[num]->setEnabled(widget_enabled); + } + } + } + + foreach (int num, control_widget_.keys()) + { + QWidget *widget = control_widget_[num]; + if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) && + (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_RESET)) + { + widget->setEnabled(!is_capturing); + } + } +} + +void InterfaceToolbar::on_interfacesComboBox_currentIndexChanged(const QString &ifname) +{ + foreach (int num, control_widget_.keys()) + { + QWidget *widget = control_widget_[num]; + if (interface_[ifname].list[num].size() > 0) + { + // This is a QComboBox. Clear list and add new entries. + setWidgetValue(widget, commandControlRemove, QByteArray()); + + foreach (QByteArray value, interface_[ifname].list[num]) + { + setWidgetValue(widget, commandControlAdd, value); + } + } + + if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL) + { + setWidgetValue(widget, commandControlSet, interface_[ifname].value[num]); + } + } + + updateWidgets(); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/interface_toolbar.h b/ui/qt/interface_toolbar.h new file mode 100644 index 0000000000..ebde37db4d --- /dev/null +++ b/ui/qt/interface_toolbar.h @@ -0,0 +1,120 @@ +/* interface_toolbar.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INTERFACE_TOOLBAR_H +#define INTERFACE_TOOLBAR_H + +#include <glib.h> + +#include "ui/iface_toolbar.h" +#include "funnel_text_dialog.h" +#include "interface_toolbar_reader.h" + +#include <QFrame> +#include <QMap> +#include <QString> + + +namespace Ui { +class InterfaceToolbar; +} + +struct interface_values +{ + QThread *reader_thread; + int out_fd; + QMap<int, QByteArray> value; + QMap<int, QList<QByteArray> > list; + FunnelTextDialog *log_dialog; + QString log_text; + QMap<int, bool> widget_disabled; +}; + +class InterfaceToolbar : public QFrame +{ + Q_OBJECT + +public: + explicit InterfaceToolbar(QWidget *parent = 0, const iface_toolbar *toolbar = NULL); + ~InterfaceToolbar(); + + void startCapture(QString ifname, QString control_in, QString control_out); + void stopCapture(); + bool hasInterface(QString ifname); + +public slots: + void controlReceived(QString ifname, int num, int command, QByteArray message); + +signals: + void closeReader(); + +private slots: + void startReaderThread(QString ifname, QString control_in); + void updateWidgets(); + + void onButtonPressed(); + void onCheckBoxChanged(int state); + void onComboBoxChanged(int idx); + void onLineEditChanged(); + void onLogButtonPressed(); + void onHelpButtonPressed(); + void onResetButtonPressed(); + + void closeLog(); + + void on_interfacesComboBox_currentIndexChanged(const QString &ifname); + +private: + void initializeControls(const iface_toolbar *toolbar); + void setDefaultValue(int num, const QByteArray &value); + void sendChangedValues(QString ifname); + QWidget *createCheckbox(iface_toolbar_control *control); + QWidget *createButton(iface_toolbar_control *control); + QWidget *createSelector(iface_toolbar_control *control); + QWidget *createString(iface_toolbar_control *control); + void controlSend(QString ifname, int num, int type, const QByteArray &payload); + void setWidgetValue(QWidget *widget, int type, QByteArray payload); + void setInterfaceValue(QString ifname, QWidget *widget, int num, int type, QByteArray payload); + + Ui::InterfaceToolbar *ui; + QMap<QString, struct interface_values> interface_; + QMap<int, QByteArray> default_value_; + QMap<int, QList<QByteArray> > default_list_; + QMap<int, QWidget *> control_widget_; + QMap<int, QWidget *> label_widget_; + QString help_link_; + bool use_spacer_; +}; + +#endif // INTERFACE_TOOLBAR_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/interface_toolbar.ui b/ui/qt/interface_toolbar.ui new file mode 100644 index 0000000000..20faae5a57 --- /dev/null +++ b/ui/qt/interface_toolbar.ui @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>InterfaceToolbar</class> + <widget class="QFrame" name="InterfaceToolbar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>32</height> + </rect> + </property> + <property name="windowTitle"> + <string>Frame</string> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="interfacesLabel"> + <property name="toolTip"> + <string>Select interface</string> + </property> + <property name="text"> + <string>Interface</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="interfacesComboBox"> + <property name="toolTip"> + <string>Select interface</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="leftLayout"/> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>5</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="rightLayout"/> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/ui/qt/interface_toolbar_lineedit.cpp b/ui/qt/interface_toolbar_lineedit.cpp new file mode 100644 index 0000000000..181bcb3be5 --- /dev/null +++ b/ui/qt/interface_toolbar_lineedit.cpp @@ -0,0 +1,149 @@ +/* interface_toolbar_lineedit.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include "interface_toolbar_lineedit.h" +#include "stock_icon_tool_button.h" +#include "epan/prefs.h" +#include "color_utils.h" + +#include <QStyle> + +// To do: +// - Make a narrower apply button + +InterfaceToolbarLineEdit::InterfaceToolbarLineEdit(QWidget *parent, QString validation_regex, bool is_required) : + QLineEdit(parent), + validation_regex_(validation_regex), + is_required_(is_required), + text_edited_(false) +{ + apply_button_ = new StockIconToolButton(this, "x-filter-apply"); + apply_button_->setCursor(Qt::ArrowCursor); + apply_button_->setEnabled(false); + apply_button_->setToolTip(tr("Apply changes")); + apply_button_->setIconSize(QSize(24, 14)); + apply_button_->setStyleSheet( + "QToolButton {" + " border: none;" + " background: transparent;" // Disables platform style on Windows. + " padding: 0 0 0 0;" + "}" + ); + + updateStyleSheet(isValid()); + + connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(validateText())); + connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(validateEditedText())); + connect(this, SIGNAL(returnPressed()), this, SLOT(applyEditedText())); + connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyEditedText())); +} + +void InterfaceToolbarLineEdit::validateText() +{ + bool valid = isValid(); + + apply_button_->setEnabled(valid); + updateStyleSheet(valid); +} + +void InterfaceToolbarLineEdit::validateEditedText() +{ + text_edited_ = true; +} + +void InterfaceToolbarLineEdit::applyEditedText() +{ + if (text_edited_ && isValid()) + { + emit editedTextApplied(); + disableApplyButton(); + } +} + +void InterfaceToolbarLineEdit::disableApplyButton() +{ + apply_button_->setEnabled(false); + text_edited_ = false; +} + +bool InterfaceToolbarLineEdit::isValid() +{ + bool valid = true; + + if (is_required_ && text().length() == 0) + { + valid = false; + } + + if (!validation_regex_.isEmpty() && text().length() > 0) + { + QRegExp expr(validation_regex_); + if (!expr.isValid() || expr.indexIn(text(), 0) == -1) + { + valid = false; + } + } + + return valid; +} + +void InterfaceToolbarLineEdit::updateStyleSheet(bool is_valid) +{ + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + QSize apsz = apply_button_->sizeHint(); + + QString style_sheet = QString( + "InterfaceToolbarLineEdit {" + " padding-right: %1px;" + " background-color: %2;" + "}" + ) + .arg(apsz.width() + frameWidth) + .arg(is_valid ? QString("") : ColorUtils::fromColorT(prefs.gui_text_invalid).name()); + + setStyleSheet(style_sheet); +} + +void InterfaceToolbarLineEdit::resizeEvent(QResizeEvent *) +{ + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + QSize apsz = apply_button_->sizeHint(); + + apply_button_->move(contentsRect().right() - frameWidth - apsz.width() + 2, + contentsRect().top()); + apply_button_->setMinimumHeight(contentsRect().height()); + apply_button_->setMaximumHeight(contentsRect().height()); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/interface_toolbar_lineedit.h b/ui/qt/interface_toolbar_lineedit.h new file mode 100644 index 0000000000..e26a50c976 --- /dev/null +++ b/ui/qt/interface_toolbar_lineedit.h @@ -0,0 +1,71 @@ +/* interface_toolbar_lineedit.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INTERFACE_TOOLBAR_LINEEDIT_H +#define INTERFACE_TOOLBAR_LINEEDIT_H + +#include <QLineEdit> + +class StockIconToolButton; + +class InterfaceToolbarLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit InterfaceToolbarLineEdit(QWidget *parent = 0, QString validation_regex = QString(), bool is_required = false); + void disableApplyButton(); + +protected: + void resizeEvent(QResizeEvent *); + +signals: + void editedTextApplied(); + +private slots: + void validateText(); + void validateEditedText(); + void applyEditedText(); + +private: + bool isValid(); + void updateStyleSheet(bool is_valid); + + StockIconToolButton *apply_button_; + QString validation_regex_; + bool is_required_; + bool text_edited_; +}; + +#endif // INTERFACE_TOOLBAR_LINEEDIT_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/interface_toolbar_reader.cpp b/ui/qt/interface_toolbar_reader.cpp new file mode 100644 index 0000000000..5c8c52a247 --- /dev/null +++ b/ui/qt/interface_toolbar_reader.cpp @@ -0,0 +1,140 @@ +/* interface_toolbar_reader.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> + +#include "interface_toolbar_reader.h" +#include "sync_pipe.h" +#include "wsutil/file_util.h" + +#include <QThread> + +const int header_size = 6; + +// To do: +// - Add support for WIN32 + +void InterfaceToolbarReader::loop() +{ +#ifndef _WIN32 + struct timeval timeout; + QByteArray header; + QByteArray payload; + fd_set readfds; + + int fd = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0); + if (fd == -1) + { + emit finished(); + return; + } + + forever + { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + int ret = select(fd + 1, &readfds, NULL, NULL, &timeout); + if (ret == -1) + { + break; + } +#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) + if (QThread::currentThread()->isInterruptionRequested()) + { + break; + } +#endif + + if (ret > 0 && FD_ISSET(fd, &readfds)) + { + header.resize(header_size); + if (ws_read(fd, header.data(), header_size) != header_size) + { + break; + } + + unsigned char high_nibble = header[1] & 0xFF; + unsigned char mid_nibble = header[2] & 0xFF; + unsigned char low_nibble = header[3] & 0xFF; + ssize_t payload_len = (ssize_t)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2; + + payload.resize(payload_len); + if (payload_len > 0) + { + ssize_t total_len = 0; + while (total_len < payload_len) + { + ssize_t read_len = ws_read(fd, payload.data() + total_len, payload_len - total_len); + if (read_len == -1) + { + if (errno != EAGAIN) + { + break; + } + } + else + { + total_len += read_len; + } + } + if (total_len != payload_len) + { + break; + } + } + if (header[0] == SP_TOOLBAR_CTRL) + { + emit received(ifname_, (unsigned char)header[4], (unsigned char)header[5], payload); + } + } + } + + ws_close(fd); +#endif + emit finished(); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/interface_toolbar_reader.h b/ui/qt/interface_toolbar_reader.h new file mode 100644 index 0000000000..1b34db4fb0 --- /dev/null +++ b/ui/qt/interface_toolbar_reader.h @@ -0,0 +1,65 @@ +/* interface_toolbar_reader.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INTERFACE_TOOLBAR_READER_H +#define INTERFACE_TOOLBAR_READER_H + +#include <QObject> +#include <QByteArray> + +namespace Ui { +class InterfaceToolbarReader; +} + +class InterfaceToolbarReader : public QObject +{ + Q_OBJECT + +public: + InterfaceToolbarReader(QString ifname, QString control_in, QObject *parent = 0) : + QObject(parent), ifname_(ifname), control_in_(control_in) {} + +public slots: + void loop(); + +signals: + void received(QString ifname, int num, int command, QByteArray payload); + void finished(); + +private: + QString ifname_; + QString control_in_; +}; + +#endif // INTERFACE_TOOLBAR_READER_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 1570b4f4cc..0952594516 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -33,6 +33,7 @@ #include <epan/export_object.h> #include "ui/commandline.h" +#include "ui/iface_toolbar.h" #ifdef HAVE_LIBPCAP #include "ui/capture.h" @@ -61,6 +62,7 @@ #include "file_set_dialog.h" #include "funnel_statistics.h" #include "import_text_dialog.h" +#include "interface_toolbar.h" #include "packet_list.h" #include "proto_tree.h" #include "simple_dialog.h" @@ -205,6 +207,23 @@ static void plugin_if_mainwindow_update_toolbars(gconstpointer user_data) if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) { QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name")); gbl_cur_main_window_->removeAdditionalToolbar(toolbarName); + + } +} + +static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry) +{ + if (gbl_cur_main_window_ && toolbar_entry) + { + gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry); + } +} + +static void mainwindow_remove_toolbar(const gchar *menu_title) +{ + if (gbl_cur_main_window_ && menu_title) + { + gbl_cur_main_window_->removeInterfaceToolbar(menu_title); } } @@ -759,6 +778,17 @@ MainWindow::MainWindow(QWidget *parent) : #endif plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars); +#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && !defined(_WIN32) + // Register Interface Toolbar callbacks + // + // Qt version must be 5.2 or higher because the use of + // QThread::requestInterruption() in interface_toolbar.cpp and + // QThread::isInterruptionRequested() in interface_toolbar_reader.cpp + // + // The toolbar in/out control pipes are not supported on WIN32 yet. + iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar); +#endif + main_ui_->mainStack->setCurrentWidget(main_welcome_); } @@ -779,6 +809,13 @@ QMenu *MainWindow::createPopupMenu() menu->addAction(main_ui_->actionViewFilterToolbar); menu->addAction(main_ui_->actionViewWirelessToolbar); + if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) { + QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title()); + foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + submenu->addAction(action); + } + } + if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) { QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title()); foreach (QAction *action, main_ui_->menuAdditionalToolbars->actions()) { @@ -795,6 +832,76 @@ QMenu *MainWindow::createPopupMenu() return menu; } +void MainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc) strcmp) ? true : false; + + QString title = QString().fromUtf8(toolbar_entry->menu_title); + QAction *action = new QAction(title, menu); + action->setEnabled(true); + action->setCheckable(true); + action->setChecked(visible); + action->setToolTip(tr("Show or hide the toolbar")); + + QAction *before = NULL; + foreach (QAction *action, menu->actions()) { + // Ensure we add the menu entries in sorted order + if (action->text().compare(title, Qt::CaseInsensitive) > 0) { + before = action; + break; + } + } + menu->insertAction(before, action); + + InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry); + + QToolBar *toolbar = new QToolBar(this); + toolbar->addWidget(interface_toolbar); + toolbar->setMovable(false); + toolbar->setVisible(visible); + + action->setData(qVariantFromValue(toolbar)); + + addToolBar(Qt::TopToolBarArea, toolbar); + insertToolBarBreak(toolbar); + + if (show_hide_actions_) { + show_hide_actions_->addAction(action); + } + + menu->menuAction()->setVisible(true); +} + +void MainWindow::removeInterfaceToolbar(const gchar *menu_title) +{ + QMenu *menu = main_ui_->menuInterfaceToolbars; + QAction *action = NULL; + QMap<QAction *, QWidget *>::iterator i; + + QString title = QString().fromUtf8(menu_title); + foreach (action, menu->actions()) { + if (title.compare(action->text()) == 0) { + break; + } + } + + if (action) { + if (show_hide_actions_) { + show_hide_actions_->removeAction(action); + } + menu->removeAction(action); + + QToolBar *toolbar = action->data().value<QToolBar *>(); + removeToolBar(toolbar); + + delete action; + delete toolbar; + } + + menu->menuAction()->setVisible(!menu->actions().isEmpty()); +} + void MainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb) { pipe_source_ = source; @@ -1895,6 +2002,9 @@ void MainWindow::initShowHideMainWidgets() showHideMainWidgets(shmwa); } + // Initial hide the Interface Toolbar submenu + main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false); + /* Initially hide the additional toolbars menus */ main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false); @@ -2356,7 +2466,7 @@ void MainWindow::resizeEvent(QResizeEvent *event) } /* Update main window items based on whether there's a capture in progress. */ -void MainWindow::setForCaptureInProgress(bool capture_in_progress) +void MainWindow::setForCaptureInProgress(bool capture_in_progress, GArray *ifaces) { setMenusForCaptureInProgress(capture_in_progress); @@ -2368,6 +2478,20 @@ void MainWindow::setForCaptureInProgress(bool capture_in_progress) // set_capture_if_dialog_for_capture_in_progress(capture_in_progress); #endif + +#ifdef HAVE_EXTCAP + QList<InterfaceToolbar *> toolbars = findChildren<InterfaceToolbar *>(); + foreach (InterfaceToolbar *toolbar, toolbars) { + if (capture_in_progress && ifaces) { + for (guint i = 0; i < ifaces->len; i++) { + interface_options interface_opts = g_array_index(ifaces, interface_options, i); + toolbar->startCapture(interface_opts.name, interface_opts.extcap_control_in, interface_opts.extcap_control_out); + } + } else { + toolbar->stopCapture(); + } + } +#endif } static QList<register_stat_group_t> menu_groups = QList<register_stat_group_t>() diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index aeb3a18052..23e1de7cce 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -31,6 +31,7 @@ #include "file.h" #include "ui/ui_util.h" +#include "ui/iface_toolbar.h" #include <epan/prefs.h> #include <epan/plugin_if.h> @@ -100,6 +101,9 @@ public: void removeAdditionalToolbar(QString toolbarName); + void addInterfaceToolbar(const iface_toolbar *toolbar_entry); + void removeInterfaceToolbar(const gchar *menu_title); + protected: virtual bool eventFilter(QObject *obj, QEvent *event); virtual void keyPressEvent(QKeyEvent *event); @@ -224,7 +228,7 @@ private: void externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth); - void setForCaptureInProgress(bool capture_in_progress = false); + void setForCaptureInProgress(bool capture_in_progress = false, GArray *ifaces = NULL); QMenu* findOrAddMenu(QMenu *parent_menu, QString& menu_text); void recursiveCopyProtoTreeItems(QTreeWidgetItem *item, QString &clip, int ident_level); diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index 39bfc55cb1..8ee6ec69c9 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -268,6 +268,11 @@ <property name="title"> <string>&View</string> </property> + <widget class="QMenu" name="menuInterfaceToolbars"> + <property name="title"> + <string>Interface Toolbars</string> + </property> + </widget> <widget class="QMenu" name="menuZoom"> <property name="title"> <string>&Zoom</string> @@ -345,6 +350,7 @@ <addaction name="actionViewMainToolbar"/> <addaction name="actionViewFilterToolbar"/> <addaction name="actionViewWirelessToolbar"/> + <addaction name="menuInterfaceToolbars"/> <addaction name="menuAdditionalToolbars" /> <addaction name="actionViewStatusBar"/> <addaction name="separator"/> diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index 4103da00b8..33eaa56318 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -119,6 +119,7 @@ #include "funnel_statistics.h" #include "gsm_map_summary_dialog.h" #include "iax2_analysis_dialog.h" +#include "interface_toolbar.h" #include "io_graph_dialog.h" #include <additional_toolbar.h> #include "lbm_stream_dialog.h" @@ -486,6 +487,15 @@ void MainWindow::layoutToolbars() main_ui_->wirelessToolBar->setVisible(recent.wireless_toolbar_show); main_ui_->statusBar->setVisible(recent.statusbar_show); + foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + QToolBar *toolbar = action->data().value<QToolBar *>(); + if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) { + toolbar->setVisible(true); + } else { + toolbar->setVisible(false); + } + } + QList<QToolBar *> toolbars = findChildren<QToolBar *>(); foreach (QToolBar *bar, toolbars) { AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar); @@ -495,6 +505,7 @@ void MainWindow::layoutToolbars() visible = true; iftoolbar->setVisible(visible); + } } } @@ -523,6 +534,14 @@ void MainWindow::updateRecentActions() main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails)); main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes)); + foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) { + action->setChecked(true); + } else { + action->setChecked(false); + } + } + foreach (QAction * action, main_ui_->menuAdditionalToolbars->actions()) { ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data()); bool checked = false; @@ -628,7 +647,7 @@ void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action // Capture callbacks -void MainWindow::captureCapturePrepared(capture_session *) { +void MainWindow::captureCapturePrepared(capture_session *session) { #ifdef HAVE_LIBPCAP setTitlebarForCaptureInProgress(); @@ -636,7 +655,7 @@ void MainWindow::captureCapturePrepared(capture_session *) { /* Disable menu items that make no sense if you're currently running a capture. */ - setForCaptureInProgress(true); + setForCaptureInProgress(true, session->capture_opts->ifaces); // set_capture_if_dialog_for_capture_in_progress(TRUE); // /* Don't set up main window for a capture file. */ @@ -645,14 +664,14 @@ void MainWindow::captureCapturePrepared(capture_session *) { #endif // HAVE_LIBPCAP } -void MainWindow::captureCaptureUpdateStarted(capture_session *) { +void MainWindow::captureCaptureUpdateStarted(capture_session *session) { #ifdef HAVE_LIBPCAP /* We've done this in "prepared" above, but it will be cleared while switching to the next multiple file. */ setTitlebarForCaptureInProgress(); - setForCaptureInProgress(true); + setForCaptureInProgress(true, session->capture_opts->ifaces); setForCapturedPackets(true); #endif // HAVE_LIBPCAP @@ -2257,6 +2276,19 @@ void MainWindow::showHideMainWidgets(QAction *action) recent.byte_view_show = show; main_ui_->actionViewPacketBytes->setChecked(show); } else { + foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) { + QToolBar *toolbar = action->data().value<QToolBar *>(); + if (widget == toolbar) { + GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp); + if (show && !entry) { + recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8())); + } else if (!show && entry) { + recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data); + } + action->setChecked(show); + } + } + ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data()); if (toolbar) { GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp); diff --git a/ui/recent.c b/ui/recent.c index 30c44f485a..898296c1c0 100644 --- a/ui/recent.c +++ b/ui/recent.c @@ -75,6 +75,7 @@ #define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames" #define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors" #define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show" +#define RECENT_GUI_INTERFACE_TOOLBAR_SHOW "gui.interface_toolbar_show" #define RECENT_GUI_GEOMETRY "gui.geom." @@ -866,6 +867,12 @@ write_profile_recent(void) fprintf(rf, RECENT_GUI_TOOLBAR_SHOW ": %s\n", string_list); g_free(string_list); + fprintf(rf, "\n# Interface Toolbars show.\n"); + fprintf(rf, "# List of interface toolbars to show.\n"); + string_list = join_string_list(recent.interface_toolbars); + fprintf(rf, RECENT_GUI_INTERFACE_TOOLBAR_SHOW ": %s\n", string_list); + g_free(string_list); + fclose(rf); /* XXX - catch I/O errors (e.g. "ran out of disk space") and return @@ -1121,6 +1128,8 @@ read_set_recent_pair_static(gchar *key, const gchar *value, recent.gui_fileopen_remembered_dir = g_strdup(value); } else if (strcmp(key, RECENT_GUI_TOOLBAR_SHOW) == 0) { recent.gui_additional_toolbars = prefs_get_string_list(value); + } else if (strcmp(key, RECENT_GUI_INTERFACE_TOOLBAR_SHOW) == 0) { + recent.interface_toolbars = prefs_get_string_list(value); } return PREFS_SET_OK; @@ -1294,6 +1303,11 @@ recent_read_profile_static(char **rf_path_return, int *rf_errno_return) recent.gui_additional_toolbars = NULL; } + if (recent.interface_toolbars) { + g_list_free_full (recent.interface_toolbars, g_free); + recent.interface_toolbars = NULL; + } + /* Construct the pathname of the user's profile recent file. */ rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE); diff --git a/ui/recent.h b/ui/recent.h index 2f33302b9b..d41dd60d3d 100644 --- a/ui/recent.h +++ b/ui/recent.h @@ -111,6 +111,7 @@ typedef struct recent_settings_tag { gboolean gui_rlc_use_pdus_from_mac; GList *custom_colors; GList *gui_additional_toolbars; + GList *interface_toolbars; } recent_settings_t; /** Global recent settings. */ |