aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-03-17 00:51:08 +0100
committerPeter Wu <peter@lekensteyn.nl>2017-03-24 23:02:43 +0000
commit370f3b358cd9ee7dcd2b7274f7ee6c90d5906c7a (patch)
treef71b56580079e13f017bda7e6c504e30eaa61be8 /ui
parentb4bc6c72c79fa121753cf94ae179ea73f1e911dd (diff)
Qt: add cache proxy model for Voip Calls dialog
When a capture file is reloaded, the information stored in VoipCallsInfoModel is invalidated. Add another cache layer to fix this: VoipCallsInfoModel wraps around raw data (invalid on close) CacheProxyModel NEW: use prev. data or cache on close VoipCallsInfoSortedModel provided sorting, etc. VoipCallsDialog actual user of model (callTreeView) This also fixes a UAF after a file was closed, and when a call is selected (that got worse with the last model/view patch and is "fixed" in this patch with the caching layer. Note that the Flow sequence and Play Streams dialog are not that useful when the file is closed). Change-Id: Ib4daff9dc01a54863fe1d943bdbdb876418924ee Reviewed-on: https://code.wireshark.org/review/20574 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/CMakeLists.txt2
-rw-r--r--ui/qt/Makefile.am2
-rw-r--r--ui/qt/cache_proxy_model.cpp112
-rw-r--r--ui/qt/cache_proxy_model.h59
-rw-r--r--ui/qt/voip_calls_dialog.cpp8
-rw-r--r--ui/qt/voip_calls_dialog.h2
6 files changed, 184 insertions, 1 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index d410638711..95e56d9a26 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -35,6 +35,7 @@ set(WIRESHARK_QT_HEADERS
accordion_frame.h
byte_view_tab.h
byte_view_text.h
+ cache_proxy_model.h
capture_file.h
capture_file_dialog.h
capture_file_properties_dialog.h
@@ -208,6 +209,7 @@ set(WIRESHARK_QT_SRC
bluetooth_hci_summary_dialog.cpp
byte_view_tab.cpp
byte_view_text.cpp
+ cache_proxy_model.cpp
capture_file.cpp
capture_file_dialog.cpp
capture_file_properties_dialog.cpp
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index a6ad706a55..846774141f 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -163,6 +163,7 @@ MOC_HDRS = \
bluetooth_hci_summary_dialog.h \
byte_view_tab.h \
byte_view_text.h \
+ cache_proxy_model.h \
capture_file.h \
capture_file_dialog.h \
capture_file_properties_dialog.h \
@@ -449,6 +450,7 @@ WIRESHARK_QT_SRC = \
bluetooth_hci_summary_dialog.cpp \
byte_view_tab.cpp \
byte_view_text.cpp \
+ cache_proxy_model.cpp \
capture_file.cpp \
capture_file_dialog.cpp \
capture_file_properties_dialog.cpp \
diff --git a/ui/qt/cache_proxy_model.cpp b/ui/qt/cache_proxy_model.cpp
new file mode 100644
index 0000000000..63b1aac70c
--- /dev/null
+++ b/ui/qt/cache_proxy_model.cpp
@@ -0,0 +1,112 @@
+/* cache_proxy_model.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 "cache_proxy_model.h"
+
+CacheProxyModel::CacheProxyModel(QObject *parent) : QIdentityProxyModel(parent)
+{
+}
+
+QVariant CacheProxyModel::data(const QModelIndex &index, int role) const
+{
+ QModelIndex dataIndex = cache.index(index.row(), index.column());
+ if (!dataIndex.isValid()) {
+ // index is possibly outside columnCount or rowCount
+ return QVariant();
+ }
+
+ if (hasModel()) {
+ QVariant value = QIdentityProxyModel::data(index, role);
+ cache.setData(dataIndex, value, role);
+ return value;
+ } else {
+ return cache.data(dataIndex, role);
+ }
+}
+
+Qt::ItemFlags CacheProxyModel::flags(const QModelIndex &index) const
+{
+ if (hasModel()) {
+ return QIdentityProxyModel::flags(index);
+ } else {
+ // Override default to prevent editing.
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ }
+}
+
+QVariant CacheProxyModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (hasModel()) {
+ QVariant value = QIdentityProxyModel::headerData(section, orientation, role);
+ cache.setHeaderData(section, orientation, value, role);
+ return value;
+ } else {
+ return cache.headerData(section, orientation, role);
+ }
+}
+
+int CacheProxyModel::rowCount(const QModelIndex &parent) const
+{
+ if (hasModel()) {
+ int count = QIdentityProxyModel::rowCount(parent);
+ cache.setRowCount(count);
+ return count;
+ } else {
+ return cache.rowCount(parent);
+ }
+}
+
+int CacheProxyModel::columnCount(const QModelIndex &parent) const
+{
+ if (hasModel()) {
+ int count = QIdentityProxyModel::columnCount(parent);
+ cache.setColumnCount(count);
+ return count;
+ } else {
+ return cache.columnCount(parent);
+ }
+}
+
+/**
+ * Sets the source model from which data must be pulled. If newSourceModel is
+ * NULL, then the cache will be used.
+ */
+void CacheProxyModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (newSourceModel) {
+ cache.clear();
+ QIdentityProxyModel::setSourceModel(newSourceModel);
+ connect(newSourceModel, SIGNAL(modelReset()),
+ this, SLOT(resetCacheModel()));
+ } else {
+ if (sourceModel()) {
+ // Prevent further updates to source model from invalidating cache.
+ disconnect(sourceModel(), SIGNAL(modelReset()),
+ this, SLOT(resetCacheModel()));
+ }
+ QIdentityProxyModel::setSourceModel(&cache);
+ }
+}
+
+void CacheProxyModel::resetCacheModel() {
+ cache.clear();
+}
diff --git a/ui/qt/cache_proxy_model.h b/ui/qt/cache_proxy_model.h
new file mode 100644
index 0000000000..9163a4695c
--- /dev/null
+++ b/ui/qt/cache_proxy_model.h
@@ -0,0 +1,59 @@
+/* cache_proxy_model.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 CACHE_PROXY_MODEL_H
+#define CACHE_PROXY_MODEL_H
+
+#include <config.h>
+
+#include <QIdentityProxyModel>
+#include <QStandardItemModel>
+
+/**
+ * Caches any data read access to the source model, returning an older copy if
+ * the source model is invalidated.
+ *
+ * Only flat data is supported at the moment, tree models (with parents) are
+ * unsupported.
+ */
+class CacheProxyModel : public QIdentityProxyModel
+{
+ Q_OBJECT
+
+public:
+ CacheProxyModel(QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ void setSourceModel(QAbstractItemModel *newSourceModel);
+
+private:
+ mutable QStandardItemModel cache;
+
+ bool hasModel() const { return sourceModel() != &cache; }
+
+private slots:
+ void resetCacheModel();
+};
+#endif
diff --git a/ui/qt/voip_calls_dialog.cpp b/ui/qt/voip_calls_dialog.cpp
index c1bb74a460..aa989eb8c4 100644
--- a/ui/qt/voip_calls_dialog.cpp
+++ b/ui/qt/voip_calls_dialog.cpp
@@ -64,8 +64,10 @@ VoipCallsDialog::VoipCallsDialog(QWidget &parent, CaptureFile &cf, bool all_flow
// Create the model that stores the actual data and the proxy model that is
// responsible for sorting and filtering data in the display.
call_infos_model_ = new VoipCallsInfoModel(this);
+ cache_model_ = new CacheProxyModel(this);
+ cache_model_->setSourceModel(call_infos_model_);
sorted_model_ = new VoipCallsInfoSortedModel(this);
- sorted_model_->setSourceModel(call_infos_model_);
+ sorted_model_->setSourceModel(cache_model_);
ui->callTreeView->setModel(sorted_model_);
connect(ui->callTreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
@@ -132,6 +134,10 @@ void VoipCallsDialog::endRetapPackets()
void VoipCallsDialog::captureFileClosing()
{
+ // The time formatting is currently provided by VoipCallsInfoModel, but when
+ // the cache is active, the ToD cannot be modified.
+ ui->todCheckBox->setEnabled(false);
+ cache_model_->setSourceModel(NULL);
voip_calls_remove_all_tap_listeners(&tapinfo_);
tapinfo_.session = NULL;
WiresharkDialog::captureFileClosing();
diff --git a/ui/qt/voip_calls_dialog.h b/ui/qt/voip_calls_dialog.h
index f9d1b07092..15285f553c 100644
--- a/ui/qt/voip_calls_dialog.h
+++ b/ui/qt/voip_calls_dialog.h
@@ -29,6 +29,7 @@
#include "ui/voip_calls.h"
#include "voip_calls_info_model.h"
+#include "cache_proxy_model.h"
#include "wireshark_dialog.h"
#include <QMenu>
@@ -68,6 +69,7 @@ protected slots:
private:
Ui::VoipCallsDialog *ui;
VoipCallsInfoModel *call_infos_model_;
+ CacheProxyModel *cache_model_;
QSortFilterProxyModel *sorted_model_;
QWidget &parent_;