ManageInterfacesDialog: New handling of pipes

This moves the handling of pipes to the new InterfaceTreeModel as well.
It also includes a new PathChooserDelegate and cache handling for adding
data to an interface list without putting it into storage

Change-Id: Id255a81161b4da517e26127abe8ea7f5eb36d55a
Reviewed-on: https://code.wireshark.org/review/18497
Reviewed-by: Roland Knall <rknall@gmail.com>
This commit is contained in:
Roland Knall 2016-10-25 14:27:56 +02:00
parent 1fae14257a
commit 6500a660c2
13 changed files with 529 additions and 266 deletions

View File

@ -111,6 +111,7 @@ set(WIRESHARK_QT_HEADERS
packet_list.h
packet_list_model.h
packet_range_group_box.h
path_chooser_delegate.h
percent_bar_delegate.h
preference_editor_frame.h
preferences_dialog.h
@ -273,6 +274,7 @@ set(WIRESHARK_QT_SRC
packet_list_model.cpp
packet_list_record.cpp
packet_range_group_box.cpp
path_chooser_delegate.cpp
percent_bar_delegate.cpp
preference_editor_frame.cpp
preferences_dialog.cpp

View File

@ -235,6 +235,7 @@ MOC_HDRS = \
numeric_value_chooser_delegate.h \
overlay_scroll_bar.h \
packet_comment_dialog.h \
path_chooser_delegate.h \
packet_dialog.h \
packet_format_group_box.h \
packet_list.h \
@ -517,6 +518,7 @@ WIRESHARK_QT_SRC = \
packet_list_model.cpp \
packet_list_record.cpp \
packet_range_group_box.cpp \
path_chooser_delegate.cpp \
percent_bar_delegate.cpp \
preference_editor_frame.cpp \
preferences_dialog.cpp \

View File

@ -21,6 +21,7 @@
*/
#include "ui/qt/interface_tree_model.h"
#include "ui/qt/interface_tree_cache_model.h"
#include "ui/qt/interface_sort_filter_model.h"
#include <glib.h>
@ -35,6 +36,11 @@
InterfaceSortFilterModel::InterfaceSortFilterModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
resetAllFilter();
}
void InterfaceSortFilterModel::resetAllFilter()
{
_filterHidden = true;
_filterTypes = true;
@ -44,6 +50,9 @@ InterfaceSortFilterModel::InterfaceSortFilterModel(QObject *parent) :
/* Adding all columns, to have a default setting */
for ( int col = 0; col < IFTREE_COL_MAX; col++ )
_columns.append((InterfaceTreeColumns)col);
invalidateFilter();
invalidate();
}
void InterfaceSortFilterModel::setStoreOnChange(bool storeOnChange)
@ -214,8 +223,21 @@ bool InterfaceSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex
if ( sourceModel()->rowCount() == 0 )
return false;
int type = ((InterfaceTreeModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_TYPE).toInt();
bool hidden = ((InterfaceTreeModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_HIDDEN, Qt::UserRole).toBool();
int type = -1;
bool hidden = false;
if (dynamic_cast<InterfaceTreeCacheModel*>(sourceModel()) != 0)
{
type = ((InterfaceTreeCacheModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_TYPE).toInt();
hidden = ((InterfaceTreeCacheModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_HIDDEN, Qt::UserRole).toBool();
}
else if (dynamic_cast<InterfaceTreeModel*>(sourceModel()) != 0)
{
type = ((InterfaceTreeModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_TYPE).toInt();
hidden = ((InterfaceTreeModel *)sourceModel())->getColumnContent(idx, IFTREE_COL_HIDDEN, Qt::UserRole).toBool();
}
else
return false;
if ( hidden && _filterHidden )
return false;

View File

@ -38,6 +38,7 @@ public:
InterfaceSortFilterModel(QObject *parent);
void setStoreOnChange(bool storeOnChange);
void resetAllFilter();
void setFilterHidden(bool filter);
bool filterHidden() const;

View File

@ -50,7 +50,7 @@ InterfaceTreeCacheModel::InterfaceTreeCacheModel(QObject *parent) :
checkableColumns << IFTREE_COL_MONITOR_MODE;
#endif
editableColumns << IFTREE_COL_INTERFACE_COMMENT << IFTREE_COL_SNAPLEN;
editableColumns << IFTREE_COL_INTERFACE_COMMENT << IFTREE_COL_SNAPLEN << IFTREE_COL_PIPE_PATH;
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
editableColumns << IFTREE_COL_BUFFERLEN;
@ -59,6 +59,13 @@ InterfaceTreeCacheModel::InterfaceTreeCacheModel(QObject *parent) :
InterfaceTreeCacheModel::~InterfaceTreeCacheModel()
{
/* This list should only exist, if the dialog is closed, without calling save first */
if ( newDevices.size() > 0 )
{
qDeleteAll(newDevices);
newDevices.clear();
}
delete storage;
delete sourceModel;
}
@ -82,6 +89,60 @@ QVariant InterfaceTreeCacheModel::getColumnContent(int idx, int col, int role)
return InterfaceTreeCacheModel::data(index(idx, col), role);
}
void InterfaceTreeCacheModel::saveNewDevices()
{
QList<interface_t *>::const_iterator it = newDevices.constBegin();
/* idx is used for iterating only over the indices of the new devices. As all new
* devices are stored with an index higher then sourceModel->rowCount(), we start
* only with those storage indices.
* it is just the iterator over the new devices. A new device must not necessarily
* have storage, which will lead to that device not being stored in global_capture_opts */
for (int idx = sourceModel->rowCount(); it != newDevices.constEnd(); ++it, idx++)
{
interface_t * device = (interface_t *)(*it);
bool useDevice = false;
QMap<InterfaceTreeColumns, QVariant> * dataField = storage->value(idx, 0);
/* When devices are being added, they are added using generic values. So only devices
* whose data have been changed should be used from here on out. */
if ( dataField != 0 )
{
if ( device->if_info.type != IF_PIPE )
{
continue;
}
if ( device->if_info.type == IF_PIPE )
{
QVariant saveValue = dataField->value(IFTREE_COL_PIPE_PATH);
if ( saveValue.isValid() )
{
g_free(device->if_info.name);
device->if_info.name = qstring_strdup(saveValue.toString());
g_free(device->name);
device->name = qstring_strdup(saveValue.toString());
g_free(device->display_name);
device->display_name = qstring_strdup(saveValue.toString());
useDevice = true;
}
}
if ( useDevice )
g_array_append_val(global_capture_opts.all_ifaces, *device);
}
/* All entries of this new devices have been considered */
storage->remove(idx);
delete dataField;
}
qDeleteAll(newDevices);
newDevices.clear();
}
void InterfaceTreeCacheModel::save()
{
if ( storage->count() == 0 )
@ -89,9 +150,13 @@ void InterfaceTreeCacheModel::save()
QMap<char**, QStringList> prefStorage;
/* Storing new devices first including their changed values */
saveNewDevices();
for(unsigned int idx = 0; idx < global_capture_opts.all_ifaces->len; idx++)
{
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
if (! device.name )
continue;
@ -108,7 +173,7 @@ void InterfaceTreeCacheModel::save()
QVariant saveValue = it.value();
/* Setting the field values for each individual saved value cannot be generic, as the
* struct cannot be accessed generically. Therefore below, each individually changed
* struct cannot be accessed in a generic way. Therefore below, each individually changed
* value has to be handled separately. Comments are stored only in the preference file
* and applied to the data name during loading. Therefore comments are not handled here */
@ -226,11 +291,13 @@ void InterfaceTreeCacheModel::save()
++it;
}
wsApp->emitAppSignal(WiresharkApplication::LocalInterfacesChanged);
}
int InterfaceTreeCacheModel::rowCount(const QModelIndex & parent) const
{
return sourceModel->rowCount(parent);
return sourceModel->rowCount(parent) + newDevices.size();
}
bool InterfaceTreeCacheModel::changeIsAllowed(InterfaceTreeColumns col) const
@ -240,54 +307,70 @@ bool InterfaceTreeCacheModel::changeIsAllowed(InterfaceTreeColumns col) const
return false;
}
interface_t * InterfaceTreeCacheModel::lookup(const QModelIndex &index) const
{
interface_t * result = 0;
if ( ! index.isValid() )
return result;
if ( ! global_capture_opts.all_ifaces && newDevices.size() == 0 )
return result;
int idx = index.row();
if ( (unsigned int) idx >= global_capture_opts.all_ifaces->len )
{
idx = idx - global_capture_opts.all_ifaces->len;
if ( idx < newDevices.size() )
result = newDevices[idx];
}
else
{
result = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
}
return result;
}
/* This checks if the column can be edited for the given index. This differs from
* isAllowedToBeChanged in such a way, that it is only used in flags and not any
* other method.*/
bool InterfaceTreeCacheModel::isAllowedToBeEdited(const QModelIndex &index) const
{
if ( ! index.isValid() || ! global_capture_opts.all_ifaces )
return false;
interface_t * device = lookup(index);
if ( device == 0 )
return false;
int idx = index.row();
if ( (unsigned int) idx >= global_capture_opts.all_ifaces->len )
return false;
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
#ifdef HAVE_EXTCAP
if ( device.if_info.type == IF_EXTCAP )
{
/* extcap interfaces do not have those settings */
if ( col == IFTREE_COL_PROMISCUOUSMODE || col == IFTREE_COL_SNAPLEN )
return false;
if ( device->if_info.type == IF_EXTCAP )
{
/* extcap interfaces do not have those settings */
if ( col == IFTREE_COL_PROMISCUOUSMODE || col == IFTREE_COL_SNAPLEN )
return false;
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
if ( col == IFTREE_COL_BUFFERLEN )
return false;
if ( col == IFTREE_COL_BUFFERLEN )
return false;
#endif
}
}
#endif
return true;
return true;
}
bool InterfaceTreeCacheModel::isAllowedToBeChanged(const QModelIndex &index) const
{
if ( ! index.isValid() || ! global_capture_opts.all_ifaces )
return false;
interface_t * device = lookup(index);
int idx = index.row();
if ( (unsigned int) idx >= global_capture_opts.all_ifaces->len )
if ( device == 0 )
return false;
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
if ( col == IFTREE_COL_HIDDEN )
{
if ( prefs.capture_device )
{
if ( ! g_strcmp0(prefs.capture_device, device.display_name) )
if ( ! g_strcmp0(prefs.capture_device, device->display_name) )
return false;
}
}
@ -360,6 +443,7 @@ QVariant InterfaceTreeCacheModel::data(const QModelIndex &index, int role) const
return QVariant();
int row = index.row();
InterfaceTreeColumns col = (InterfaceTreeColumns)index.column();
if ( isAllowedToBeEdited(index) )
@ -385,7 +469,112 @@ QVariant InterfaceTreeCacheModel::data(const QModelIndex &index, int role) const
return QString("-");
}
return sourceModel->data(index, role);
if ( row >= sourceModel->rowCount() )
{
/* Handle all fields, which will have to be displayed for new devices. Only pipes
* are supported at the moment, so the information to be displayed is pretty limited.
* After saving, the devices are stored in global_capture_opts and no longer
* classify as new devices. */
interface_t * device = lookup(index);
if ( device != 0 )
{
if ( role == Qt::DisplayRole || role == Qt::EditRole )
{
if ( col == IFTREE_COL_PIPE_PATH ||
col == IFTREE_COL_NAME ||
col == IFTREE_COL_INTERFACE_NAME )
{
QMap<InterfaceTreeColumns, QVariant> * dataField = 0;
if ( ( dataField = storage->value(row, 0) ) != 0 &&
dataField->contains(IFTREE_COL_PIPE_PATH) )
{
return dataField->value(IFTREE_COL_PIPE_PATH, QVariant());
}
else
return QString(device->name);
}
else if ( col == IFTREE_COL_TYPE )
{
return QVariant::fromValue((int)device->if_info.type);
}
}
else if ( role == Qt::CheckStateRole )
{
if ( col == IFTREE_COL_HIDDEN )
{
/* Hidden is a de-selection, therefore inverted logic here */
return device->hidden ? Qt::Unchecked : Qt::Checked;
}
}
}
}
else
return sourceModel->data(index, role);
return QVariant();
}
QModelIndex InterfaceTreeCacheModel::index(int row, int column, const QModelIndex &parent) const
{
if ( row >= sourceModel->rowCount() && ( row - sourceModel->rowCount() ) < newDevices.count() )
{
return createIndex(row, column, (void *)0);
}
return sourceModel->index(row, column, parent);
}
void InterfaceTreeCacheModel::addDevice(interface_t * newDevice)
{
emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
newDevices << newDevice;
emit endInsertRows();
}
void InterfaceTreeCacheModel::deleteDevice(const QModelIndex &index)
{
if ( ! index.isValid() )
return;
emit beginRemoveRows(QModelIndex(), index.row(), index.row());
int row = index.row();
/* device is in newDevices */
if ( row >= sourceModel->rowCount() )
{
int newDeviceIdx = row - sourceModel->rowCount();
newDevices.removeAt(newDeviceIdx);
if ( storage->contains(index.row()) )
storage->remove(index.row());
/* The storage array has to be resorted, if the index, that was removed
* had been in the middle of the array. Can't start at index.row(), as
* it may not be contained in storage
* We must iterate using a list, not an iterator, otherwise the change
* will fold on itself. */
QList<int> storageKeys = storage->keys();
for ( int i = 0; i < storageKeys.size(); ++i )
{
int key = storageKeys.at(i);
if ( key > index.row() )
{
storage->insert(key - 1, storage->value(key));
storage->remove(key);
}
}
emit endRemoveRows();
}
else
{
g_array_remove_index(global_capture_opts.all_ifaces, row);
emit endRemoveRows();
wsApp->emitAppSignal(WiresharkApplication::LocalInterfacesChanged);
}
}
/*

View File

@ -45,16 +45,26 @@ public:
QVariant getColumnContent(int idx, int col, int role = Qt::DisplayRole);
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
void reset(int row);
void save();
void addDevice(interface_t * newDevice);
void deleteDevice(const QModelIndex &index);
private:
InterfaceTreeModel * sourceModel;
QList<interface_t *> newDevices;
void saveNewDevices();
QMap<int, QMap<InterfaceTreeColumns, QVariant> *> * storage;
QList<InterfaceTreeColumns> editableColumns;
QList<InterfaceTreeColumns> checkableColumns;
interface_t * lookup(const QModelIndex &index) const;
bool changeIsAllowed(InterfaceTreeColumns col) const;
bool isAllowedToBeChanged(const QModelIndex &index) const;
bool isAllowedToBeEdited(const QModelIndex &index) const;

View File

@ -135,6 +135,10 @@ QVariant InterfaceTreeModel::data(const QModelIndex &index, int role) const
{
return QString(device.name);
}
else if ( col == IFTREE_COL_PIPE_PATH )
{
return QString(device.if_info.name);
}
else if ( col == IFTREE_COL_CAPTURE_FILTER )
{
if ( device.cfilter && strlen(device.cfilter) > 0 )
@ -264,10 +268,14 @@ QVariant InterfaceTreeModel::headerData(int section, Qt::Orientation orientation
{
return tr("Friendly Name");
}
else if ( section == IFTREE_COL_INTERFACE_NAME )
else if ( section == IFTREE_COL_NAME )
{
return tr("Interface Name");
}
else if ( section == IFTREE_COL_PIPE_PATH )
{
return tr("Local Pipe Path");
}
else if ( section == IFTREE_COL_INTERFACE_COMMENT )
{
return tr("Comment");

View File

@ -61,6 +61,7 @@ enum InterfaceTreeColumns
IFTREE_COL_MONITOR_MODE,
#endif
IFTREE_COL_CAPTURE_FILTER,
IFTREE_COL_PIPE_PATH,
IFTREE_COL_MAX /* is not being displayed, it is the definition for the maximum numbers of columns */
};

View File

@ -22,9 +22,9 @@
#include <glib.h>
#include "manage_interfaces_dialog.h"
#include <ui_manage_interfaces_dialog.h>
#include "epan/prefs.h"
#include "epan/to_str.h"
#include "ui/last_open_dir.h"
#include "capture_opts.h"
#include "ui/capture_globals.h"
#include "ui/qt/capture_interfaces_dialog.h"
@ -49,6 +49,8 @@
#include "ui/capture_ui_utils.h"
#include "ui/qt/path_chooser_delegate.h"
#include <QCheckBox>
#include <QFileDialog>
#include <QHBoxLayout>
@ -90,7 +92,7 @@ ManageInterfacesDialog::ManageInterfacesDialog(QWidget *parent) :
#ifdef Q_OS_MAC
ui->addPipe->setAttribute(Qt::WA_MacSmallSize, true);
ui->addPipe->setAttribute(Qt::WA_MacSmallSize, true);
ui->delPipe->setAttribute(Qt::WA_MacSmallSize, true);
ui->addRemote->setAttribute(Qt::WA_MacSmallSize, true);
ui->delRemote->setAttribute(Qt::WA_MacSmallSize, true);
#endif
@ -110,14 +112,27 @@ ManageInterfacesDialog::ManageInterfacesDialog(QWidget *parent) :
proxyModel->setFilterHidden(false);
proxyModel->setFilterByType(false);
ui->localView->setModel(proxyModel);
ui->localView->resizeColumnToContents(proxyModel->mapSourceToColumn(IFTREE_COL_HIDDEN));
ui->localView->resizeColumnToContents(proxyModel->mapSourceToColumn(IFTREE_COL_INTERFACE_NAME));
ui->pipeList->setItemDelegateForColumn(col_p_pipe_, &new_pipe_item_delegate_);
new_pipe_item_delegate_.setTree(ui->pipeList);
showPipes();
pipeProxyModel = new InterfaceSortFilterModel(this);
columns.clear();
columns.append(IFTREE_COL_PIPE_PATH);
pipeProxyModel->setColumns(columns);
pipeProxyModel->setSourceModel(sourceModel);
pipeProxyModel->setFilterHidden(true);
pipeProxyModel->setFilterByType(true, true);
pipeProxyModel->setInterfaceTypeVisible(IF_PIPE, false);
ui->pipeView->setModel(pipeProxyModel);
ui->delPipe->setEnabled(pipeProxyModel->rowCount() > 0);
ui->pipeView->setItemDelegateForColumn(
pipeProxyModel->mapSourceToColumn(IFTREE_COL_PIPE_PATH), new PathChooserDelegate()
);
connect(ui->pipeView->selectionModel(),
SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this,
SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
#if defined(HAVE_PCAP_REMOTE)
// The default indentation (20) means our checkboxes are shifted too far on Windows.
@ -128,7 +143,7 @@ ManageInterfacesDialog::ManageInterfacesDialog(QWidget *parent) :
ui->remoteSettings->setEnabled(false);
showRemoteInterfaces();
#else
ui->remoteTab->setEnabled(false);
ui->tabWidget->removeTab(tab_remote_);
#endif
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateWidgets()));
@ -149,16 +164,15 @@ ManageInterfacesDialog::~ManageInterfacesDialog()
delete ui;
}
void ManageInterfacesDialog::onSelectionChanged(const QItemSelection &sel, const QItemSelection &)
{
ui->delPipe->setEnabled( sel.count() > 0 );
}
void ManageInterfacesDialog::updateWidgets()
{
QString hint;
if (ui->pipeList->selectedItems().length() > 0) {
ui->delPipe->setEnabled(true);
} else {
ui->delPipe->setEnabled(false);
}
#ifdef HAVE_PCAP_REMOTE
bool enable_del_remote = false;
bool enable_remote_settings = false;
@ -195,30 +209,8 @@ void ManageInterfacesDialog::updateWidgets()
ui->hintLabel->setText(hint);
}
void ManageInterfacesDialog::showPipes()
{
ui->pipeList->clear();
if (global_capture_opts.all_ifaces->len > 0) {
interface_t device;
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
/* Continue if capture device is hidden */
if (device.hidden || device.type != IF_PIPE) {
continue;
}
QTreeWidgetItem *item = new QTreeWidgetItem(ui->pipeList);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setText(col_p_pipe_, device.display_name);
}
}
}
void ManageInterfacesDialog::on_buttonBox_accepted()
{
pipeAccepted();
sourceModel->save();
#ifdef HAVE_PCAP_REMOTE
remoteAccepted();
@ -228,97 +220,37 @@ void ManageInterfacesDialog::on_buttonBox_accepted()
emit ifsChanged();
}
const QString new_pipe_default_ = QObject::tr("New Pipe");
void ManageInterfacesDialog::on_addPipe_clicked()
{
QTreeWidgetItem *item = new QTreeWidgetItem(ui->pipeList);
item->setText(col_p_pipe_, new_pipe_default_);
item->setFlags(item->flags() | Qt::ItemIsEditable);
ui->pipeList->setCurrentItem(item);
ui->pipeList->editItem(item, col_p_pipe_);
}
interface_t * device = g_new0(interface_t, 1);
void ManageInterfacesDialog::pipeAccepted()
{
interface_t device;
// First clear the current pipes
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
/* Continue if capture device is hidden or not a pipe */
if (device.hidden || device.type != IF_PIPE) {
continue;
}
global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
capture_opts_free_interface_t(&device);
}
// Next rebuild a fresh list
QTreeWidgetItemIterator it(ui->pipeList);
while (*it) {
QString pipe_name = (*it)->text(col_p_pipe_);
if (pipe_name.isEmpty() || pipe_name == new_pipe_default_) {
++it;
continue;
}
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
// Instead of just deleting the device we might want to add a hint label
// and let the user know what's going to happen.
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (pipe_name.compare(device.name) == 0) { // Duplicate
++it;
continue;
}
}
memset(&device, 0, sizeof(device));
device.name = qstring_strdup(pipe_name);
device.display_name = g_strdup(device.name);
device.hidden = FALSE;
device.selected = TRUE;
device.type = IF_PIPE;
device.pmode = global_capture_opts.default_options.promisc_mode;
device.has_snaplen = global_capture_opts.default_options.has_snaplen;
device.snaplen = global_capture_opts.default_options.snaplen;
device.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
device.addresses = NULL;
device.no_addresses = 0;
device.last_packets = 0;
device.links = NULL;
device->name = qstring_strdup(tr("New Pipe"));
device->display_name = g_strdup(device->name);
device->hidden = FALSE;
device->selected = TRUE;
device->pmode = global_capture_opts.default_options.promisc_mode;
device->has_snaplen = global_capture_opts.default_options.has_snaplen;
device->snaplen = global_capture_opts.default_options.snaplen;
device->cfilter = g_strdup(global_capture_opts.default_options.cfilter);
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
device.buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
#endif
device.active_dlt = -1;
device.locked = FALSE;
device.if_info.name = g_strdup(device.name);
device.if_info.friendly_name = NULL;
device.if_info.vendor_description = NULL;
device.if_info.addrs = NULL;
device.if_info.loopback = FALSE;
device.if_info.type = IF_PIPE;
#ifdef HAVE_EXTCAP
device.if_info.extcap = NULL;
device.external_cap_args_settings = NULL;
#endif
#if defined(HAVE_PCAP_CREATE)
device.monitor_mode_enabled = FALSE;
device.monitor_mode_supported = FALSE;
#endif
global_capture_opts.num_selected++;
g_array_append_val(global_capture_opts.all_ifaces, device);
++it;
}
device->active_dlt = -1;
device->if_info.name = g_strdup(device->name);
device->if_info.type = IF_PIPE;
sourceModel->addDevice(device);
updateWidgets();
}
void ManageInterfacesDialog::on_delPipe_clicked()
{
// We're just managing a list of strings at this point.
delete ui->pipeList->currentItem();
}
/* Get correct selection and tell the source model to delete the itm. pipe view only
* displays IF_PIPE devices, therefore this will only delete pipes, and this is set
* to only select single items. */
QModelIndex selIndex = ui->pipeView->selectionModel()->selectedIndexes().at(0);
void ManageInterfacesDialog::on_pipeList_currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)
{
sourceModel->deleteDevice( pipeProxyModel->mapToSource(selIndex) );
updateWidgets();
}
@ -638,89 +570,6 @@ void ManageInterfacesDialog::setRemoteSettings(interface_t *iface)
}
#endif // HAVE_PCAP_REMOTE
PathChooserDelegate::PathChooserDelegate(QObject *parent)
: QStyledItemDelegate(parent), tree_(NULL), path_item_(NULL), path_editor_(NULL), path_le_(NULL)
{
}
PathChooserDelegate::~PathChooserDelegate()
{
}
QWidget* PathChooserDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &) const
{
QTreeWidgetItem *item = tree_->currentItem();
if (!item) {
return NULL;
}
path_item_ = item;
path_editor_ = new QWidget(parent);
QHBoxLayout *hbox = new QHBoxLayout(path_editor_);
path_editor_->setLayout(hbox);
path_le_ = new QLineEdit(path_editor_);
QPushButton *pb = new QPushButton(path_editor_);
path_le_->setText(item->text(col_p_pipe_));
pb->setText(QString(tr("Browse" UTF8_HORIZONTAL_ELLIPSIS)));
hbox->setContentsMargins(0, 0, 0, 0);
hbox->addWidget(path_le_);
hbox->addWidget(pb);
hbox->setSizeConstraint(QLayout::SetMinimumSize);
// Grow the item to match the editor. According to the QAbstractItemDelegate
// documenation we're supposed to reimplement sizeHint but this seems to work.
QSize size = option.rect.size();
size.setHeight(qMax(option.rect.height(), hbox->sizeHint().height()));
item->setData(col_p_pipe_, Qt::SizeHintRole, size);
path_le_->selectAll();
path_editor_->setFocusProxy(path_le_);
path_editor_->setFocusPolicy(path_le_->focusPolicy());
connect(path_le_, SIGNAL(destroyed()), this, SLOT(stopEditor()));
connect(pb, SIGNAL(pressed()), this, SLOT(browse_button_clicked()));
return path_editor_;
}
void PathChooserDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
{
QRect rect = option.rect;
// Make sure the editor doesn't get squashed.
editor->adjustSize();
rect.setHeight(qMax(option.rect.height(), editor->height()));
editor->setGeometry(rect);
}
void PathChooserDelegate::stopEditor()
{
path_item_->setData(col_p_pipe_, Qt::SizeHintRole, QVariant());
path_item_->setText(col_p_pipe_, path_le_->text());
}
void PathChooserDelegate::browse_button_clicked()
{
char *open_dir = NULL;
switch (prefs.gui_fileopen_style) {
case FO_STYLE_LAST_OPENED:
open_dir = get_last_open_dir();
break;
case FO_STYLE_SPECIFIED:
if (prefs.gui_fileopen_dir[0] != '\0')
open_dir = prefs.gui_fileopen_dir;
break;
}
QString file_name = QFileDialog::getOpenFileName(tree_, tr("Open Pipe"), open_dir);
if (!file_name.isEmpty()) {
path_le_->setText(file_name);
}
}
#endif /* HAVE_LIBPCAP */
/*

View File

@ -39,31 +39,6 @@ class QStandardItemModel;
class QLineEdit;
class PathChooserDelegate : public QStyledItemDelegate
{
Q_OBJECT
private:
QTreeWidget* tree_;
mutable QTreeWidgetItem *path_item_;
mutable QWidget *path_editor_;
mutable QLineEdit *path_le_;
public:
PathChooserDelegate(QObject *parent = 0);
~PathChooserDelegate();
void setTree(QTreeWidget* tree) { tree_ = tree; }
protected:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void updateEditorGeometry (QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;
private slots:
void stopEditor();
void browse_button_clicked();
};
namespace Ui {
class ManageInterfacesDialog;
@ -79,11 +54,11 @@ public:
private:
Ui::ManageInterfacesDialog *ui;
PathChooserDelegate new_pipe_item_delegate_;
InterfaceTreeCacheModel * sourceModel;
InterfaceSortFilterModel * proxyModel;
void showPipes();
InterfaceSortFilterModel * pipeProxyModel;
void showRemoteInterfaces();
signals:
@ -100,9 +75,8 @@ private slots:
void on_addPipe_clicked();
void on_delPipe_clicked();
void pipeAccepted();
void on_pipeList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void onSelectionChanged(const QItemSelection &sel, const QItemSelection &desel);
#ifdef HAVE_PCAP_REMOTE
void on_addRemote_clicked();

View File

@ -63,7 +63,7 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTreeWidget" name="pipeList">
<widget class="QTreeView" name="pipeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -91,11 +91,6 @@
<property name="itemsExpandable">
<bool>false</bool>
</property>
<column>
<property name="text">
<string>Named Pipe Path</string>
</property>
</column>
</widget>
</item>
<item>

View File

@ -0,0 +1,152 @@
/* path_chooser_delegate.cpp
* Delegate to select a file path for a treeview entry
*
* 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 "epan/prefs.h"
#include "ui/last_open_dir.h"
#include "ui/qt/path_chooser_delegate.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QWidget>
#include <QLineEdit>
PathChooserDelegate::PathChooserDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
QWidget* PathChooserDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &) const
{
QWidget * pathEditor = new QWidget(parent);
QHBoxLayout *hbox = new QHBoxLayout(pathEditor);
pathEditor->setLayout(hbox);
QLineEdit * lineEdit = new QLineEdit(pathEditor);
QPushButton *btnBrowse = new QPushButton(pathEditor);
btnBrowse->setText(tr("Browse"));
hbox->setContentsMargins(0, 0, 0, 0);
hbox->addWidget(lineEdit);
hbox->addWidget(btnBrowse);
hbox->setSizeConstraint(QLayout::SetMinimumSize);
// Grow the item to match the editor. According to the QAbstractItemDelegate
// documenation we're supposed to reimplement sizeHint but this seems to work.
QSize size = option.rect.size();
size.setHeight(qMax(option.rect.height(), hbox->sizeHint().height()));
lineEdit->selectAll();
pathEditor->setFocusProxy(lineEdit);
pathEditor->setFocusPolicy(lineEdit->focusPolicy());
connect(btnBrowse, SIGNAL(pressed()), this, SLOT(browse_button_clicked()));
return pathEditor;
}
void PathChooserDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const
{
QRect rect = option.rect;
// Make sure the editor doesn't get squashed.
editor->adjustSize();
rect.setHeight(qMax(option.rect.height(), editor->height()));
editor->setGeometry(rect);
}
void PathChooserDelegate::browse_button_clicked()
{
char *open_dir = NULL;
switch ( prefs.gui_fileopen_style )
{
case FO_STYLE_LAST_OPENED:
open_dir = get_last_open_dir();
break;
case FO_STYLE_SPECIFIED:
if ( prefs.gui_fileopen_dir[0] != '\0' )
open_dir = prefs.gui_fileopen_dir;
break;
}
QString file_name = QFileDialog::getOpenFileName(new QWidget(), tr("Open Pipe"), open_dir);
if ( !file_name.isEmpty() )
{
QWidget * parent = ((QPushButton *)sender())->parentWidget();
QLineEdit * lineEdit = parent->findChild<QLineEdit*>();
if ( lineEdit )
{
lineEdit->setText(file_name);
emit commitData(parent);
}
}
}
void PathChooserDelegate::setEditorData(QWidget *editor, const QModelIndex &idx) const
{
if ( idx.isValid() )
{
QString content = idx.data().toString();
QLineEdit * lineEdit = editor->findChild<QLineEdit*>();
if ( lineEdit )
{
lineEdit->setText(content);
}
}
else
QStyledItemDelegate::setEditorData(editor, idx);
}
void PathChooserDelegate::setModelData(QWidget *editor, QAbstractItemModel * model, const QModelIndex &idx) const
{
if ( idx.isValid() )
{
QLineEdit * lineEdit = editor->findChild<QLineEdit*>();
if ( lineEdit )
{
model->setData(idx, lineEdit->text());
}
}
else
{
QStyledItemDelegate::setModelData(editor, model, idx);
}
}
/*
* 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:
*/

View File

@ -0,0 +1,58 @@
/* path_chooser_delegate.h
* Delegate to select a file path for a treeview entry
*
* 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 PATH_CHOOSER_DELEGATE_H_
#define PATH_CHOOSER_DELEGATE_H_
#include <QStyledItemDelegate>
class PathChooserDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
PathChooserDelegate(QObject *parent = 0);
protected:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &idx) const;
void updateEditorGeometry (QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & idx) const;
void setEditorData(QWidget *editor, const QModelIndex &idx) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &idx) const;
private slots:
void browse_button_clicked();
};
#endif /* PATH_CHOOSER_DELEGATE_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:
*/