diff options
author | Gerald Combs <gerald@wireshark.org> | 2017-11-29 17:25:53 -0800 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2017-12-05 18:27:23 +0000 |
commit | abcb7ec8750a263d0307bc41d86b798e5ae02966 (patch) | |
tree | 6d37d9e65a4e93ae9f775b664d429b1fde064796 /ui | |
parent | 5eb07b35d430b68c6d816476190035e0774f18d2 (diff) |
Convert the file set dialog treewidget to a treeview+model.
Add a FilesetEntryModel and use it in FileSetDialog. This should be
faster than using a QTreeWidget. Move dialog updates and date
calculations out of the "add file" loop.
Bug: 11280
Bug: 14242
Change-Id: I702cef4fe91e739695fe805dc5e496bf3db411f1
Reviewed-on: https://code.wireshark.org/review/24708
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gtk/fileset_dlg.c | 16 | ||||
-rw-r--r-- | ui/qt/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 2 | ||||
-rw-r--r-- | ui/qt/file_set_dialog.cpp | 172 | ||||
-rw-r--r-- | ui/qt/file_set_dialog.h | 26 | ||||
-rw-r--r-- | ui/qt/file_set_dialog.ui | 26 | ||||
-rw-r--r-- | ui/qt/models/fileset_entry_model.cpp | 177 | ||||
-rw-r--r-- | ui/qt/models/fileset_entry_model.h | 64 |
8 files changed, 327 insertions, 158 deletions
diff --git a/ui/gtk/fileset_dlg.c b/ui/gtk/fileset_dlg.c index 540da82fdd..aa2945edfc 100644 --- a/ui/gtk/fileset_dlg.c +++ b/ui/gtk/fileset_dlg.c @@ -5,19 +5,7 @@ * 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. + * SPDX-License-Identifier: GPL-2.0+ */ #include "config.h" @@ -249,6 +237,8 @@ fileset_dlg_add_file(fileset_entry *entry, void *window _U_) { g_free(size); } +void fileset_dlg_begin_add_file(void *window _U_) { } // Qt only +void fileset_dlg_end_add_file(void *window _U_) { } // Qt only /* init the fileset table */ static void diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index 19496e154a..7be83ddbe4 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -64,6 +64,7 @@ set(WIRESHARK_MODEL_HEADERS models/cache_proxy_model.h models/decode_as_delegate.h models/decode_as_model.h + models/fileset_entry_model.h models/html_text_delegate.h models/interface_sort_filter_model.h models/interface_tree_cache_model.h @@ -270,6 +271,7 @@ set(WIRESHARK_MODEL_SRCS models/cache_proxy_model.cpp models/decode_as_delegate.cpp models/decode_as_model.cpp + models/fileset_entry_model.cpp models/html_text_delegate.cpp models/interface_sort_filter_model.cpp models/interface_tree_cache_model.cpp diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index beba9cc8ae..04b014bafe 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -193,6 +193,7 @@ MOC_MODELS_HDRS = \ models/cache_proxy_model.h \ models/decode_as_delegate.h \ models/decode_as_model.h \ + models/fileset_entry_model.h \ models/html_text_delegate.h \ models/interface_sort_filter_model.h \ models/interface_tree_cache_model.h \ @@ -512,6 +513,7 @@ WIRESHARK_QT_MODELS_SRCS = \ models/cache_proxy_model.cpp \ models/decode_as_delegate.cpp \ models/decode_as_model.cpp \ + models/fileset_entry_model.cpp \ models/html_text_delegate.cpp \ models/interface_sort_filter_model.cpp \ models/interface_tree_cache_model.cpp \ diff --git a/ui/qt/file_set_dialog.cpp b/ui/qt/file_set_dialog.cpp index 808163a1b0..042e24d843 100644 --- a/ui/qt/file_set_dialog.cpp +++ b/ui/qt/file_set_dialog.cpp @@ -4,19 +4,7 @@ * 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. + * SPDX-License-Identifier: GPL-2.0+ */ #include "config.h" @@ -28,12 +16,11 @@ #include "ui/help_url.h" -#include <ui/qt/utils/variant_pointer.h> - #include <wsutil/str_util.h> #include "file_set_dialog.h" #include <ui_file_set_dialog.h> +#include "models/fileset_entry_model.h" #include "wireshark_application.h" #include <QDialogButtonBox> @@ -44,7 +31,17 @@ #include <QTreeWidgetItem> #include <QUrl> -/* this file is a part of the current file set, add it to the dialog */ +// To do: +// - We might want to rename this to FilesetDialog / fileset_dialog.{cpp,h}. + +void +fileset_dlg_begin_add_file(void *window) { + FileSetDialog *fs_dlg = static_cast<FileSetDialog *>(window); + + if (fs_dlg) fs_dlg->beginAddFile(); +} + +/* This file is a part of the current file set. Add it to our model. */ void fileset_dlg_add_file(fileset_entry *entry, void *window) { FileSetDialog *fs_dlg = static_cast<FileSetDialog *>(window); @@ -52,147 +49,112 @@ fileset_dlg_add_file(fileset_entry *entry, void *window) { if (fs_dlg) fs_dlg->addFile(entry); } +void +fileset_dlg_end_add_file(void *window) { + FileSetDialog *fs_dlg = static_cast<FileSetDialog *>(window); + + if (fs_dlg) fs_dlg->endAddFile(); +} + FileSetDialog::FileSetDialog(QWidget *parent) : GeometryStateDialog(parent), fs_ui_(new Ui::FileSetDialog), + fileset_entry_model_(new FilesetEntryModel(this)), close_button_(NULL) { fs_ui_->setupUi(this); loadGeometry (); - fs_ui_->fileSetTree->headerItem(); + fs_ui_->fileSetTree->setModel(fileset_entry_model_); + + fs_ui_->fileSetTree->setFocus(); close_button_ = fs_ui_->buttonBox->button(QDialogButtonBox::Close); + + connect(fs_ui_->fileSetTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(selectionChanged(QItemSelection,QItemSelection))); + + beginAddFile(); addFile(); + endAddFile(); } FileSetDialog::~FileSetDialog() { + fileset_entry_model_->clear(); delete fs_ui_; } /* a new capture file was opened, browse the dir and look for files matching the given file set */ void FileSetDialog::fileOpened(const capture_file *cf) { if (!cf) return; - fs_ui_->fileSetTree->clear(); + fileset_entry_model_->clear(); fileset_add_dir(cf->filename, this); } /* the capture file was closed */ void FileSetDialog::fileClosed() { - fileset_delete(); - fs_ui_->fileSetTree->clear(); + fileset_entry_model_->clear(); } -#include <QDebug> void FileSetDialog::addFile(fileset_entry *entry) { - QString created; - QString modified; - QString dir_name; - QString elided_dir_name; - QTreeWidgetItem *entry_item; - gchar *size_str; - - if (!entry) { - setWindowTitle(wsApp->windowTitleString(tr("No files in Set"))); - fs_ui_->directoryLabel->setText(tr("No capture loaded")); - fs_ui_->directoryLabel->setEnabled(false); - return; - } + if (!entry) return; - created = nameToDate(entry->name); - if(created.length() < 1) { - /* if this file doesn't follow the file set pattern, */ - /* use the creation time of that file if available */ - /* http://en.wikipedia.org/wiki/ISO_8601 */ - /* - * macOS provides 0 if the file system doesn't support the - * creation time; FreeBSD provides -1. - * - * If this OS doesn't provide the creation time with stat(), - * it will be 0. - */ - if (entry->ctime > 0) - created = QDateTime::fromTime_t(uint(entry->ctime)).toLocalTime().toString("yyyy-MM-dd HH:mm:ss"); - else - created = "Not available"; + if (entry->current) { + cur_idx_ = fileset_entry_model_->entryCount(); } + fileset_entry_model_->appendEntry(entry); +} - modified = QDateTime::fromTime_t(uint(entry->mtime)).toLocalTime().toString("yyyy-MM-dd HH:mm:ss"); - - size_str = format_size(entry->size, format_size_unit_bytes|format_size_prefix_si); - - entry_item = new QTreeWidgetItem(fs_ui_->fileSetTree); - entry_item->setToolTip(0, QString(tr("Open this capture file"))); - entry_item->setData(0, Qt::UserRole, VariantPointer<fileset_entry>::asQVariant(entry)); - - entry_item->setText(0, entry->name); - entry_item->setText(1, created); - entry_item->setText(2, modified); - entry_item->setText(3, size_str); - g_free(size_str); - // Not perfect but better than nothing. - entry_item->setTextAlignment(3, Qt::AlignRight); +void FileSetDialog::beginAddFile() +{ + cur_idx_ = -1; + setWindowTitle(wsApp->windowTitleString(tr("No files in Set"))); + fs_ui_->directoryLabel->setText(tr("No capture loaded")); + fs_ui_->directoryLabel->setEnabled(false); +} - setWindowTitle(wsApp->windowTitleString(tr("%Ln File(s) in Set", "", - fs_ui_->fileSetTree->topLevelItemCount()))); +void FileSetDialog::endAddFile() +{ + if (fileset_entry_model_->entryCount() > 0) { + setWindowTitle(wsApp->windowTitleString(tr("%Ln File(s) in Set", "", + fileset_entry_model_->entryCount()))); + } - dir_name = fileset_get_dirname(); + QString dir_name = fileset_get_dirname(); fs_ui_->directoryLabel->setText(dir_name); fs_ui_->directoryLabel->setUrl(QUrl::fromLocalFile(dir_name).toString()); fs_ui_->directoryLabel->setEnabled(true); - if(entry->current) { - fs_ui_->fileSetTree->setCurrentItem(entry_item); + if(cur_idx_ >= 0) { + fs_ui_->fileSetTree->setCurrentIndex(fileset_entry_model_->index(cur_idx_, 0)); + } + + for (int col = 0; col < 4; col++) { + fs_ui_->fileSetTree->resizeColumnToContents(col); } if (close_button_) close_button_->setEnabled(true); - - fs_ui_->fileSetTree->addTopLevelItem(entry_item); - for (int i = 0; i < fs_ui_->fileSetTree->columnCount(); i++) - fs_ui_->fileSetTree->resizeColumnToContents(i); - fs_ui_->fileSetTree->setFocus(); -} - -QString FileSetDialog::nameToDate(const char *name) { - QString dn; - - if (!fileset_filename_match_pattern(name)) - return NULL; - - dn = name; - dn.remove(QRegExp(".*_")); - dn.truncate(14); - dn.insert(4, '-'); - dn.insert(7, '-'); - dn.insert(10, ' '); - dn.insert(13, ':'); - dn.insert(16, ':'); - return dn; -} - -void FileSetDialog::on_buttonBox_helpRequested() -{ - wsApp->helpTopicAction(HELP_FILESET_DIALOG); } -void FileSetDialog::on_fileSetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *) +void FileSetDialog::selectionChanged(const QItemSelection &selected, const QItemSelection &) { - fileset_entry *entry; - - if (!current) - return; - - entry = VariantPointer<fileset_entry>::asPtr(current->data(0, Qt::UserRole)); + const fileset_entry *entry = fileset_entry_model_->getRowEntry(selected.first().top()); if (!entry || entry->current) return; QString new_cf_path = entry->fullname; - if (new_cf_path.length() > 0) + if (new_cf_path.length() > 0) { emit fileSetOpenCaptureFile(new_cf_path); + } +} + +void FileSetDialog::on_buttonBox_helpRequested() +{ + wsApp->helpTopicAction(HELP_FILESET_DIALOG); } /* diff --git a/ui/qt/file_set_dialog.h b/ui/qt/file_set_dialog.h index 7d8ec5f95a..a619f9154e 100644 --- a/ui/qt/file_set_dialog.h +++ b/ui/qt/file_set_dialog.h @@ -4,19 +4,7 @@ * 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. + * SPDX-License-Identifier: GPL-2.0+ */ #ifndef FILE_SET_DIALOG_H @@ -31,12 +19,16 @@ #include "geometry_state_dialog.h" +#include <QItemSelection> + class QTreeWidgetItem; namespace Ui { class FileSetDialog; } +class FilesetEntryModel; + class FileSetDialog : public GeometryStateDialog { Q_OBJECT @@ -48,19 +40,21 @@ public: void fileOpened(const capture_file *cf); void fileClosed(); void addFile(fileset_entry *entry = NULL); + void beginAddFile(); + void endAddFile(); signals: void fileSetOpenCaptureFile(QString); private slots: + void selectionChanged(const QItemSelection &selected, const QItemSelection &); void on_buttonBox_helpRequested(); - void on_fileSetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); private: - QString nameToDate(const char *name); - Ui::FileSetDialog *fs_ui_; + FilesetEntryModel *fileset_entry_model_; QPushButton *close_button_; + int cur_idx_; }; #endif // FILE_SET_DIALOG_H diff --git a/ui/qt/file_set_dialog.ui b/ui/qt/file_set_dialog.ui index 901e7ac4d0..3c61433227 100644 --- a/ui/qt/file_set_dialog.ui +++ b/ui/qt/file_set_dialog.ui @@ -63,7 +63,7 @@ </widget> </item> <item row="0" column="0" colspan="2"> - <widget class="QTreeWidget" name="fileSetTree"> + <widget class="QTreeView" name="fileSetTree"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -85,29 +85,6 @@ <property name="expandsOnDoubleClick"> <bool>false</bool> </property> - <property name="columnCount"> - <number>4</number> - </property> - <column> - <property name="text"> - <string>Filename</string> - </property> - </column> - <column> - <property name="text"> - <string>Created</string> - </property> - </column> - <column> - <property name="text"> - <string>Modified</string> - </property> - </column> - <column> - <property name="text"> - <string>Size</string> - </property> - </column> </widget> </item> </layout> @@ -121,6 +98,7 @@ <header>widgets/elided_label.h</header> </customwidget> </customwidgets> + <resources/> <connections> <connection> <sender>buttonBox</sender> diff --git a/ui/qt/models/fileset_entry_model.cpp b/ui/qt/models/fileset_entry_model.cpp new file mode 100644 index 0000000000..c613a5cc35 --- /dev/null +++ b/ui/qt/models/fileset_entry_model.cpp @@ -0,0 +1,177 @@ +/* fileset_entry_model.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <ui/qt/models/fileset_entry_model.h> + +#include "wsutil/utf8_entities.h" + +#include <ui/qt/utils/qt_ui_utils.h> + +FilesetEntryModel::FilesetEntryModel(QObject * parent) : + QAbstractItemModel(parent) +{} + +QModelIndex FilesetEntryModel::index(int row, int column, const QModelIndex &) const +{ + if (row >= entries_.count() || row < 0 || column > ColumnCount) { + return QModelIndex(); + } + +DIAG_OFF(cast-qual) + return createIndex(row, column, (void *)entries_.at(row)); +DIAG_ON(cast-qual) +} + +int FilesetEntryModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return entries_.count(); +} + +QVariant FilesetEntryModel::data(const QModelIndex &index, int role) const +{ + if ( ! index.isValid() || index.row() >= rowCount() ) + return QVariant(); + + fileset_entry *entry = static_cast<fileset_entry*>(index.internalPointer()); + if (role == Qt::DisplayRole && entry) { + switch (index.column()) { + case Name: + return QString(entry->name); + break; + case Created: + { + QString created = nameToDate(entry->name); + if(created.length() < 1) { + /* if this file doesn't follow the file set pattern, */ + /* use the creation time of that file if available */ + /* http://en.wikipedia.org/wiki/ISO_8601 */ + /* + * macOS provides 0 if the file system doesn't support the + * creation time; FreeBSD provides -1. + * + * If this OS doesn't provide the creation time with stat(), + * it will be 0. + */ + if (entry->ctime > 0) { + created = time_tToString(entry->ctime); + } else { + created = UTF8_EM_DASH; + } + } + return created; + break; + } + case Modified: + return time_tToString(entry->mtime); + break; + case Size: + return file_size_to_qstring(entry->size); + break; + default: + break; + } + } else if (role == Qt::ToolTipRole) { + return QString(tr("Open this capture file")); + } else if (role == Qt::TextAlignmentRole) { + switch (index.column()) { + case Size: + // Not perfect but better than nothing. + return Qt::AlignRight; + default: + return Qt::AlignLeft; + } + } + return QVariant(); +} + +QVariant FilesetEntryModel::headerData(int section, Qt::Orientation, int role) const +{ + if (role != Qt::DisplayRole) return QVariant(); + + switch (section) { + case Name: + return tr("Filename"); + break; + case Created: + return tr("Created"); + break; + case Modified: + return tr("Modified"); + break; + case Size: + return tr("Size"); + break; + default: + break; + } + return QVariant(); +} + +void FilesetEntryModel::appendEntry(const fileset_entry *entry) +{ + emit beginInsertRows(QModelIndex(), rowCount(), rowCount()); + entries_ << entry; + emit endInsertRows(); +} + +void FilesetEntryModel::clear() +{ + fileset_delete(); + beginResetModel(); + entries_.clear(); + endResetModel(); +} + +QString FilesetEntryModel::nameToDate(const char *name) const { + QString dn; + + if (!fileset_filename_match_pattern(name)) + return NULL; + + dn = name; + dn.remove(QRegExp(".*_")); + dn.truncate(14); + dn.insert(4, '-'); + dn.insert(7, '-'); + dn.insert(10, ' '); + dn.insert(13, ':'); + dn.insert(16, ':'); + return dn; +} + +QString FilesetEntryModel::time_tToString(time_t clock) const +{ + struct tm *local = localtime(&clock); + if (!local) return UTF8_EM_DASH; + + // yyyy-MM-dd HH:mm:ss + // The equivalent QDateTime call is pretty slow here, possibly related to QTBUG-21678 + // and/or QTBUG-41714. + return QString("%1-%2-%3 %4:%5:%6") + .arg(local->tm_year + 1900, 4, 10, QChar('0')) + .arg(local->tm_mon+1, 2, 10, QChar('0')) + .arg(local->tm_mday, 2, 10, QChar('0')) + .arg(local->tm_hour, 2, 10, QChar('0')) + .arg(local->tm_min, 2, 10, QChar('0')) + .arg(local->tm_sec, 2, 10, QChar('0')); +} + +/* + * 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/models/fileset_entry_model.h b/ui/qt/models/fileset_entry_model.h new file mode 100644 index 0000000000..ad740680b3 --- /dev/null +++ b/ui/qt/models/fileset_entry_model.h @@ -0,0 +1,64 @@ +/* fileset_entry_model.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef FILESET_ENTRY_MODEL_H +#define FILESET_ENTRY_MODEL_H + +#include <config.h> + +#include <glib.h> + +#include <fileset.h> + +#include <QAbstractItemModel> +#include <QModelIndex> + +class FilesetEntryModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit FilesetEntryModel(QObject * parent = 0); + + QModelIndex index(int row, int column, const QModelIndex & = QModelIndex()) const; + // Everything is under the root. + virtual QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &) const { return ColumnCount; } + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const; + + virtual void appendEntry(const fileset_entry *entry); + const fileset_entry *getRowEntry(int row) const { return entries_.value(row, NULL); } + int entryCount() const { return entries_.count(); } + // Calls fileset_delete and clears our model data. + void clear(); + +private: + QVector<const fileset_entry *> entries_; + enum Column { Name, Created, Modified, Size, ColumnCount }; + + QString nameToDate(const char *name) const ; + QString time_tToString(time_t clock) const; +}; + +#endif // FILESET_ENTRY_MODEL_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: + */ |