aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Knall <roland.knall@br-automation.com>2017-11-22 16:54:32 +0100
committerAnders Broman <a.broman58@gmail.com>2017-11-24 05:17:07 +0000
commit73c01d6d0562f138b3aad83b6b2dcf8d3f09dcee (patch)
tree0fb123b90de745730f52c8ec4befeec5744c57a0
parent8fa4a440a8f85ff9078c7c28e3747decede0848e (diff)
Qt: Rewrite the About dialog to use models
Rewrite of the about dialog, to use QTableView and Models instead of HTML files. Everything is now model based, and the model is generic enough to support any variation which can be put into a QStringList row. Change-Id: Ie32bf66b2fe2a7754c0bf07205a7b068d46b0070 Reviewed-on: https://code.wireshark.org/review/24534 Petri-Dish: Roland Knall <rknall@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--ui/qt/CMakeLists.txt6
-rw-r--r--ui/qt/Makefile.am6
-rw-r--r--ui/qt/about_dialog.cpp446
-rw-r--r--ui/qt/about_dialog.h83
-rw-r--r--ui/qt/about_dialog.ui65
-rw-r--r--ui/qt/models/astringlist_list_model.cpp169
-rw-r--r--ui/qt/models/astringlist_list_model.h92
-rw-r--r--ui/qt/models/html_text_delegate.cpp66
-rw-r--r--ui/qt/models/html_text_delegate.h48
-rw-r--r--ui/qt/models/url_link_delegate.cpp68
-rw-r--r--ui/qt/models/url_link_delegate.h35
11 files changed, 843 insertions, 241 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index b3bdbc4703..19496e154a 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -60,9 +60,11 @@ set(WIRESHARK_UTILS_HEADERS
)
set(WIRESHARK_MODEL_HEADERS
+ models/astringlist_list_model.h
models/cache_proxy_model.h
models/decode_as_delegate.h
models/decode_as_model.h
+ models/html_text_delegate.h
models/interface_sort_filter_model.h
models/interface_tree_cache_model.h
models/interface_tree_model.h
@@ -76,6 +78,7 @@ set(WIRESHARK_MODEL_HEADERS
models/sparkline_delegate.h
models/uat_delegate.h
models/uat_model.h
+ models/url_link_delegate.h
models/voip_calls_info_model.h
)
@@ -263,9 +266,11 @@ set(WIRESHARK_UTILS_SRCS
)
set(WIRESHARK_MODEL_SRCS
+ models/astringlist_list_model.cpp
models/cache_proxy_model.cpp
models/decode_as_delegate.cpp
models/decode_as_model.cpp
+ models/html_text_delegate.cpp
models/interface_sort_filter_model.cpp
models/interface_tree_cache_model.cpp
models/interface_tree_model.cpp
@@ -280,6 +285,7 @@ set(WIRESHARK_MODEL_SRCS
models/timeline_delegate.cpp
models/uat_delegate.cpp
models/uat_model.cpp
+ models/url_link_delegate.cpp
models/voip_calls_info_model.cpp
)
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index 3d071657c1..beba9cc8ae 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -189,9 +189,11 @@ MOC_UTILS_HDRS = \
# Files for delegates and models
MOC_MODELS_HDRS = \
+ models/astringlist_list_model.h \
models/cache_proxy_model.h \
models/decode_as_delegate.h \
models/decode_as_model.h \
+ models/html_text_delegate.h \
models/interface_sort_filter_model.h \
models/interface_tree_cache_model.h \
models/interface_tree_model.h \
@@ -205,6 +207,7 @@ MOC_MODELS_HDRS = \
models/sparkline_delegate.h \
models/uat_delegate.h \
models/uat_model.h \
+ models/url_link_delegate.h \
models/voip_calls_info_model.h
@@ -505,9 +508,11 @@ WIRESHARK_QT_UTILS_SRC = \
utils/qt_ui_utils.cpp
WIRESHARK_QT_MODELS_SRCS = \
+ models/astringlist_list_model.cpp \
models/cache_proxy_model.cpp \
models/decode_as_delegate.cpp \
models/decode_as_model.cpp \
+ models/html_text_delegate.cpp \
models/interface_sort_filter_model.cpp \
models/interface_tree_cache_model.cpp \
models/interface_tree_model.cpp \
@@ -521,6 +526,7 @@ WIRESHARK_QT_MODELS_SRCS = \
models/timeline_delegate.cpp \
models/uat_model.cpp \
models/uat_delegate.cpp \
+ models/url_link_delegate.cpp \
models/voip_calls_info_model.cpp
WIRESHARK_QT_SRC = \
diff --git a/ui/qt/about_dialog.cpp b/ui/qt/about_dialog.cpp
index 79b53eb0b6..4b73a990a1 100644
--- a/ui/qt/about_dialog.cpp
+++ b/ui/qt/about_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"
@@ -58,33 +46,66 @@
#endif
#include <ui/qt/utils/qt_ui_utils.h>
+#include <ui/qt/models/astringlist_list_model.h>
+#include <ui/qt/models/url_link_delegate.h>
+#include <ui/qt/models/html_text_delegate.h>
#include <QFontMetrics>
#include <QKeySequence>
#include <QTextStream>
#include <QUrl>
+#include <QRegExp>
+#include <QAbstractItemModel>
+#include <QHash>
+AuthorListModel::AuthorListModel(QObject * parent) :
+AStringListListModel(parent)
+{
+ bool readAck = false;
+ QFile f_authors;
-// To do:
-// - Tweak and enhance ui...
+ f_authors.setFileName(get_datafile_path("AUTHORS-SHORT"));
+ f_authors.open(QFile::ReadOnly | QFile::Text);
+ QTextStream ReadFile_authors(&f_authors);
+ ReadFile_authors.setCodec("UTF-8");
+
+ QRegExp rx("(.*)[<(]([\\s'a-zA-Z0-9._%+-]+(\\[[Aa][Tt]\\])?[a-zA-Z0-9._%+-]+)[>)]");
+ acknowledgement_.clear();
+ while (!ReadFile_authors.atEnd()) {
+ QString line = ReadFile_authors.readLine();
+
+ if ( ! readAck )
+ {
+ if ( line.trimmed().length() == 0 )
+ continue;
+ if ( line.startsWith("------") )
+ continue;
+ }
+
+ if ( line.compare(QStringLiteral("Acknowledgements") ) == 0 )
+ readAck = true;
+ else if ( rx.indexIn(line) != -1 )
+ appendRow( QStringList() << rx.cap(1).trimmed() << rx.cap(2).trimmed());
+
+ if ( readAck )
+ acknowledgement_.append(QString("%1\n").arg(line));
+ }
+ f_authors.close();
+
+}
-const QString AboutDialog::about_folders_row(const char *name, const QString dir, const char *typ_file)
+AuthorListModel::~AuthorListModel() { }
+
+QString AuthorListModel::acknowledgment() const
{
- int one_em = fontMetrics().height();
-
- QString short_dir = fontMetrics().elidedText(dir, Qt::ElideMiddle, one_em * 18); // Arbitrary
-
- // It would be really nice to be able to add a tooltip with the
- // full path here but Qt's rich text doesn't appear to support
- // "a title=".
- return QString("<tr><td>%1</td><td><a href=\"%2\">%3</a></td><td>%4</td></tr>\n")
- .arg(name)
- .arg(QUrl::fromLocalFile(dir).toString())
- .arg(short_dir)
- .arg(typ_file);
+ return acknowledgement_;
+}
+
+QStringList AuthorListModel::headerColumns() const
+{
+ return QStringList() << tr("Name") << tr("E-Mail");
}
-#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
static void plugins_add_description(const char *name, const char *version,
const char *types, const char *filename,
void *user_data)
@@ -93,13 +114,10 @@ static void plugins_add_description(const char *name, const char *version,
QStringList plugin_row = QStringList() << name << version << types << filename;
*plugin_data << plugin_row;
}
-#endif
-const QString AboutDialog::plugins_scan()
+PluginListModel::PluginListModel(QObject * parent) : AStringListListModel(parent)
{
QList<QStringList> plugin_data;
- QString plugin_table;
-
#ifdef HAVE_PLUGINS
plugins_get_descriptions(plugins_add_description, &plugin_data);
#endif
@@ -108,18 +126,6 @@ const QString AboutDialog::plugins_scan()
wslua_plugins_get_descriptions(plugins_add_description, &plugin_data);
#endif
- int one_em = fontMetrics().height();
- QString short_file;
-
- foreach (QStringList plugin_row, plugin_data) {
- short_file = fontMetrics().elidedText(plugin_row[3], Qt::ElideMiddle, one_em * 22); // Arbitrary
- plugin_table += QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td></tr>\n")
- .arg(plugin_row[0]) // Name
- .arg(plugin_row[1]) // Version
- .arg(plugin_row[2]) // Type
- .arg(short_file);
- }
-
#ifdef HAVE_EXTCAP
GHashTable * tools = extcap_loaded_interfaces();
if (tools && g_hash_table_size(tools) > 0) {
@@ -127,215 +133,233 @@ const QString AboutDialog::plugins_scan()
while (walker && walker->data) {
extcap_info * tool = (extcap_info *)g_hash_table_lookup(tools, walker->data);
if (tool) {
- short_file = fontMetrics().elidedText(tool->full_path, Qt::ElideMiddle, one_em*22);
- plugin_table += QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td></tr>\n")
- .arg(tool->basename) // Name
- .arg(tool->version) // Version
- .arg("extcap") // Type
- .arg(short_file);
+ QStringList plugin_row = QStringList() << tool->basename << tool->version << "extcap" << tool->full_path;
+ plugin_data << plugin_row;
}
walker = g_list_next(walker);
}
}
#endif
- return plugin_table;
+ typeNames_ << QString("");
+ foreach(QStringList row, plugin_data)
+ {
+ typeNames_ << row.at(2);
+ appendRow(row);
+ }
+
+ typeNames_.sort();
+ typeNames_.removeDuplicates();
}
-AboutDialog::AboutDialog(QWidget *parent) :
- QDialog(NULL),
- ui(new Ui::AboutDialog)
+QStringList PluginListModel::typeNames() const
{
- ui->setupUi(this);
- setAttribute(Qt::WA_DeleteOnClose, true);
- QFile f_license;
- const char *constpath;
- QString message;
-#if defined(HAVE_LIBSMI) || defined(HAVE_GEOIP) || defined(HAVE_EXTCAP)
-#if defined(HAVE_LIBSMI) || defined(HAVE_GEOIP)
- char *path = NULL;
-#endif
- gint i;
- gchar **resultArray;
-#endif
- GString *comp_info_str = get_compiled_version_info(get_wireshark_qt_compiled_info,
- get_gui_compiled_info);
- GString *runtime_info_str = get_runtime_version_info(get_wireshark_runtime_info);
-
- /* Wireshark tab */
-
- /* Construct the message string */
- message = QString(
- "Version %1\n"
- "\n"
- "%2"
- "\n"
- "%3"
- "\n"
- "%4"
- "\n"
- "Wireshark is Open Source Software released under the GNU General Public License.\n"
- "\n"
- "Check the man page and http://www.wireshark.org for more information.")
- .arg(get_ws_vcs_version_info()).arg(get_copyright_info()).arg(comp_info_str->str)
- .arg(runtime_info_str->str);
-
- ui->label_wireshark->setTextInteractionFlags(Qt::TextSelectableByMouse);
- ui->label_wireshark->setText(message);
-
-/* Check if it is a dev release... (VERSION_MINOR is odd in dev release) */
-#if VERSION_MINOR & 1
- ui->label_logo->setPixmap(QPixmap(":/about/wssplash_dev.png"));
-#endif
+ return typeNames_;
+}
- /* Authors */
- ui->pte_Authors->setFont(wsApp->monospaceFont());
- this->addAuthors(NULL);
+QStringList PluginListModel::headerColumns() const
+{
+ return QStringList() << tr("Name") << tr("Version") << tr("Type") << tr("Path");
+}
- /* Folders */
+ShortcutListModel::ShortcutListModel(QObject * parent):
+ AStringListListModel(parent)
+{
+ QMap<QString, QPair<QString, QString> > shortcuts; // name -> (shortcut, description)
+ foreach (const QWidget *child, wsApp->mainWindow()->findChildren<QWidget *>()) {
+ // Recent items look funny here.
+ if (child->objectName().compare("menuOpenRecentCaptureFile") == 0) continue;
+ foreach (const QAction *action, child->actions()) {
+
+ if (!action->shortcut().isEmpty()) {
+ QString name = action->text();
+ name.replace('&', "");
+ shortcuts[name] = QPair<QString, QString>(action->shortcut().toString(QKeySequence::NativeText), action->toolTip());
+ }
+ }
+ }
- int one_em = fontMetrics().height();
+ QStringList names = shortcuts.keys();
+ names.sort();
+ foreach (const QString &name, names) {
+ QStringList row;
+ row << shortcuts[name].first << name << shortcuts[name].second;
+ appendRow(row);
+ }
+}
- // Couldn't get CSS to work.
- message = QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
- message += "<tr><th align=\"left\">Name</th><th align=\"left\">Location</th><th align=\"left\">Typical Files</th></tr>\n";
+QStringList ShortcutListModel::headerColumns() const
+{
+ return QStringList() << tr("Shortcut") << tr("Name") << tr("Description");
+}
+FolderListModel::FolderListModel(QObject * parent):
+ AStringListListModel(parent)
+{
/* "file open" */
- message += about_folders_row("\"File\" dialogs", get_last_open_dir(), "capture files");
+ appendRow( QStringList() << "\"File\" dialogs" << get_last_open_dir() << "capture files");
/* temp */
- message += about_folders_row("Temp", g_get_tmp_dir(), "untitled capture files");
+ appendRow( QStringList() << "Temp" << g_get_tmp_dir() << "untitled capture files");
/* pers conf */
- message += about_folders_row("Personal configuration",
- gchar_free_to_qstring(get_persconffile_path("", FALSE)),
- "<i>dfilters</i>, <i>preferences</i>, <i>ethers</i>, " UTF8_HORIZONTAL_ELLIPSIS);
+ appendRow( QStringList() << "Personal configuration"
+ << gchar_free_to_qstring(get_persconffile_path("", FALSE))
+ << "<i>dfilters</i>, <i>preferences</i>, <i>ethers</i>, " UTF8_HORIZONTAL_ELLIPSIS);
/* global conf */
- constpath = get_datafile_dir();
- if (constpath != NULL) {
- message += about_folders_row("Global configuration", constpath,
- "<i>dfilters</i>, <i>preferences</i>, <i>manuf</i>, " UTF8_HORIZONTAL_ELLIPSIS);
+ QString dirPath = get_datafile_dir();
+ if (! dirPath.isEmpty()) {
+ appendRow ( QStringList() << "Global configuration" << dirPath
+ << "<i>dfilters</i>, <i>preferences</i>, <i>manuf</i>, " UTF8_HORIZONTAL_ELLIPSIS);
}
/* system */
- message += about_folders_row("System", get_systemfile_dir(), "<i>ethers</i>, <i>ipxnets</i>");
+ appendRow( QStringList() << "System" << get_systemfile_dir() << "<i>ethers</i>, <i>ipxnets</i>");
/* program */
- message += about_folders_row("Program", get_progfile_dir(), "program files");
+ appendRow( QStringList() << "Program" << get_progfile_dir() << "program files");
#ifdef HAVE_PLUGINS
/* pers plugins */
- message += about_folders_row("Personal Plugins", get_plugins_pers_dir_with_version(), "binary plugins");
+ appendRow( QStringList() << "Personal Plugins" << get_plugins_pers_dir_with_version() << "binary plugins");
/* global plugins */
- message += about_folders_row("Global Plugins", get_plugins_dir_with_version(), "binary plugins");
+ appendRow( QStringList() << "Global Plugins" << get_plugins_dir_with_version() << "binary plugins");
#endif
#ifdef HAVE_LUA
/* pers plugins */
- message += about_folders_row("Personal Lua Plugins", get_plugins_pers_dir(), "lua scripts");
+ appendRow( QStringList() << "Personal Lua Plugins" << get_plugins_pers_dir() << "lua scripts");
/* global plugins */
- message += about_folders_row("Global Lua Plugins", get_plugins_dir(), "lua scripts");
+ appendRow( QStringList() << "Global Lua Plugins" << get_plugins_dir() << "lua scripts");
#endif
#ifdef HAVE_EXTCAP
/* Extcap */
- constpath = get_extcap_dir();
+ QStringList extPaths = QString(get_extcap_dir()).split(G_SEARCHPATH_SEPARATOR_S);
- resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10);
+ foreach(QString path, extPaths)
+ appendRow( QStringList() << "Extcap path" << path.trimmed() << "Extcap Plugins search path");
- for(i = 0; resultArray[i]; i++) {
- message += about_folders_row("Extcap path", g_strstrip(resultArray[i]),
- "Extcap Plugins search path");
- }
- g_strfreev(resultArray);
#endif
#ifdef HAVE_GEOIP
/* GeoIP */
- path = geoip_db_get_paths();
-
- resultArray = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 10);
-
- for(i = 0; resultArray[i]; i++) {
- message += about_folders_row("GeoIP path", g_strstrip(resultArray[i]),
- "GeoIP database search path");
- }
- g_strfreev(resultArray);
- g_free(path);
+ QStringList geoIpPaths = QString(geoip_db_get_paths()).split(G_SEARCHPATH_SEPARATOR_S);
+ foreach(QString path, geoIpPaths)
+ appendRow( QStringList() << "GeoIP path" << path.trimmed() << "GeoIP database search path");
#endif
#ifdef HAVE_LIBSMI
/* SMI MIBs/PIBs */
- path = oid_get_default_mib_path();
+ QStringList smiPaths = QString(oid_get_default_mib_path()).split(G_SEARCHPATH_SEPARATOR_S);
+ foreach(QString path, smiPaths)
+ appendRow( QStringList() << "MIB/PIB path" << path.trimmed() << "SMI MIB/PIB search path");
+#endif
+}
+
+QStringList FolderListModel::headerColumns() const
+{
+ return QStringList() << tr("Name") << tr("Location") << tr("Typical Files");
+}
- resultArray = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 10);
+// To do:
+// - Tweak and enhance ui...
- for(i = 0; resultArray[i]; i++) {
- message += about_folders_row("MIB/PIB path", g_strstrip(resultArray[i]),
- "SMI MIB/PIB search path");
- }
- g_strfreev(resultArray);
- g_free(path);
+AboutDialog::AboutDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AboutDialog)
+{
+ ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ QFile f_license;
+ QString message;
+
+ GString *comp_info_str = get_compiled_version_info(get_wireshark_qt_compiled_info,
+ get_gui_compiled_info);
+ GString *runtime_info_str = get_runtime_version_info(get_wireshark_runtime_info);
+
+
+ AuthorListModel * authorModel = new AuthorListModel(this);
+ AStringListListSortFilterProxyModel * proxyAuthorModel = new AStringListListSortFilterProxyModel(this);
+ proxyAuthorModel->setSourceModel(authorModel);
+ proxyAuthorModel->setColumnToFilter(0);
+ proxyAuthorModel->setColumnToFilter(1);
+ ui->tblAuthors->setModel(proxyAuthorModel);
+ ui->pte_Authors->clear();
+ ui->pte_Authors->appendPlainText(authorModel->acknowledgment());
+ ui->pte_Authors->moveCursor(QTextCursor::Start);
+
+ ui->tblAuthors->horizontalHeader()->setStretchLastSection(true);
+ connect(ui->searchAuthors, SIGNAL(textChanged(QString)), proxyAuthorModel, SLOT(setFilter(QString)));
+
+ /* Wireshark tab */
+
+ /* Construct the message string */
+ message = QString(
+ "Version %1\n"
+ "\n"
+ "%2"
+ "\n"
+ "%3"
+ "\n"
+ "%4"
+ "\n"
+ "Wireshark is Open Source Software released under the GNU General Public License.\n"
+ "\n"
+ "Check the man page and http://www.wireshark.org for more information.")
+ .arg(get_ws_vcs_version_info(), get_copyright_info(), comp_info_str->str, runtime_info_str->str);
+
+ ui->label_wireshark->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ ui->label_wireshark->setText(message);
+
+/* Check if it is a dev release... (VERSION_MINOR is odd in dev release) */
+#if VERSION_MINOR & 1
+ ui->label_logo->setPixmap(QPixmap(":/about/wssplash_dev.png"));
#endif
- message += "</table>";
- ui->label_folders->setText(message);
+ /* Folders */
+ FolderListModel * folderModel = new FolderListModel(this);
+ AStringListListSortFilterProxyModel * folderProxyModel = new AStringListListSortFilterProxyModel(this);
+ folderProxyModel->setSourceModel(folderModel);
+ folderProxyModel->setColumnToFilter(1);
+ folderProxyModel->setFilterType(AStringListListSortFilterProxyModel::FilterByStart);
+ ui->tblFolders->setModel(folderProxyModel);
+ ui->tblFolders->setItemDelegateForColumn(1, new UrlLinkDelegate(this));
+ ui->tblFolders->setItemDelegateForColumn(2, new HTMLTextDelegate(this));
+ connect(ui->searchFolders, SIGNAL(textChanged(QString)), folderProxyModel, SLOT(setFilter(QString)));
/* Plugins */
#if defined(HAVE_PLUGINS) || defined(HAVE_LUA) || defined(HAVE_EXTCAP)
- message = QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
- message += "<tr><th align=\"left\">Name</th><th align=\"left\">Version</th><th align=\"left\">Type</th><th align=\"left\">Path</th></tr>\n";
- message += plugins_scan();
+ PluginListModel * pluginModel = new PluginListModel(this);
+ AStringListListSortFilterProxyModel * pluginFilterModel = new AStringListListSortFilterProxyModel(this);
+ pluginFilterModel->setSourceModel(pluginModel);
+ pluginFilterModel->setColumnToFilter(0);
+ AStringListListSortFilterProxyModel * pluginTypeModel = new AStringListListSortFilterProxyModel(this);
+ pluginTypeModel->setSourceModel(pluginFilterModel);
+ pluginTypeModel->setColumnToFilter(2);
+ ui->tblPlugins->setModel(pluginTypeModel);
+ ui->tblPlugins->setItemDelegateForColumn(3, new UrlLinkDelegate(this));
+ ui->cmbType->addItems(pluginModel->typeNames());
+ connect(ui->searchPlugins, SIGNAL(textChanged(QString)), pluginFilterModel, SLOT(setFilter(QString)));
+ connect(ui->cmbType, SIGNAL(currentIndexChanged(QString)), pluginTypeModel, SLOT(setFilter(QString)));
- message += "</table>";
- ui->te_plugins->setHtml(message);
#else
- ui->te_plugins->setVisible(false);
+ ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tab_plugins));
#endif
/* Shortcuts */
- bool have_shortcuts = false;
-
- if (parent) {
- message = "<h3>Main Window Keyboard Shortcuts</h3>\n";
- message += QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
- message += "<tr><th align=\"left\">Shortcut</th><th align=\"left\">Name</th><th align=\"left\">Description</th></tr>\n";
-
- QMap<QString, QPair<QString, QString> > shortcuts; // name -> (shortcut, description)
- foreach (const QWidget *child, parent->findChildren<QWidget *>()) {
- // Recent items look funny here.
- if (child->objectName().compare("menuOpenRecentCaptureFile") == 0) continue;
- foreach (const QAction *action, child->actions()) {
-
- if (!action->shortcut().isEmpty()) {
- QString name = action->text();
- name.replace('&', "");
- shortcuts[name] = QPair<QString, QString>(action->shortcut().toString(QKeySequence::NativeText), action->toolTip());
- }
- }
- }
-
- QStringList names = shortcuts.keys();
- names.sort();
- foreach (const QString &name, names) {
- message += QString("<tr><td>%1</td><td>%2</td><td>%3</td></tr>\n")
- .arg(shortcuts[name].first)
- .arg(name)
- .arg(shortcuts[name].second);
- have_shortcuts = true;
- }
-
- message += "</table>";
- ui->te_shortcuts->setHtml(message);
-
- }
-
- ui->te_shortcuts->setVisible(have_shortcuts);
+ ShortcutListModel * shortcutModel = new ShortcutListModel(this);
+ AStringListListSortFilterProxyModel * shortcutProxyModel = new AStringListListSortFilterProxyModel(this);
+ shortcutProxyModel->setSourceModel(shortcutModel);
+ shortcutProxyModel->setColumnToFilter(1);
+ shortcutProxyModel->setColumnToFilter(2);
+ ui->tblShortcuts->setModel(shortcutProxyModel);
+ connect(ui->searchShortcuts, SIGNAL(textChanged(QString)), shortcutProxyModel, SLOT(setFilter(QString)));
/* License */
@@ -352,36 +376,34 @@ AboutDialog::AboutDialog(QWidget *parent) :
ui->pte_License->insertPlainText(ReadFile_license.readAll());
ui->pte_License->moveCursor(QTextCursor::Start);
- connect(ui->searchAuthors, SIGNAL(textChanged(const QString &)), this, SLOT(updateAuthors(const QString &)));
}
-void AboutDialog::addAuthors(const QString& filter)
+AboutDialog::~AboutDialog()
{
- QFile f_authors;
-
- f_authors.setFileName(get_datafile_path("AUTHORS-SHORT"));
- f_authors.open(QFile::ReadOnly | QFile::Text);
- QTextStream ReadFile_authors(&f_authors);
- ReadFile_authors.setCodec("UTF-8");
-
- ui->pte_Authors->clear();
- ui->pte_Authors->moveCursor(QTextCursor::Start);
- while (!ReadFile_authors.atEnd()) {
- QString line = ReadFile_authors.readLine();
- if (line.contains(filter, Qt::CaseInsensitive))
- ui->pte_Authors->appendPlainText(line);
- }
- ui->pte_Authors->moveCursor(QTextCursor::Start);
+ delete ui;
}
-void AboutDialog::updateAuthors(const QString& filter)
+void AboutDialog::resizeEvent(QResizeEvent * event)
{
- this->addAuthors(filter);
-}
+ QList<QWidget *> pages;
-AboutDialog::~AboutDialog()
-{
- delete ui;
+ pages << ui->tab_authors << ui->tab_folders << ui->tab_plugins << ui->tab_shortcuts;
+
+ foreach ( QWidget * tabPage, pages )
+ {
+ QList<QTableView *> childs = tabPage->findChildren<QTableView*>();
+ if ( childs.count() == 0 )
+ continue;
+
+ QTableView * table = childs.at(0);
+
+ int columnCount = table->model()->columnCount();
+ for ( int cnt = 0; cnt < columnCount; cnt++ )
+ table->setColumnWidth(cnt, tabPage->width() / columnCount);
+ table->horizontalHeader()->setStretchLastSection(true);
+ }
+
+ QDialog::resizeEvent(event);
}
/*
diff --git a/ui/qt/about_dialog.h b/ui/qt/about_dialog.h
index 89d66f5ff7..8a1c9652f5 100644
--- a/ui/qt/about_dialog.h
+++ b/ui/qt/about_dialog.h
@@ -4,30 +4,80 @@
* 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 ABOUT_DIALOG_H
#define ABOUT_DIALOG_H
+#include "config.h"
+
+#include <ui/qt/models/astringlist_list_model.h>
+
#include <QDialog>
+#include <QAbstractItemModel>
+#include <QModelIndex>
+#include <QHash>
+#include <QString>
+#include <QSortFilterProxyModel>
namespace Ui {
class AboutDialog;
}
+class AuthorListModel : public AStringListListModel
+{
+Q_OBJECT
+
+public:
+ explicit AuthorListModel(QObject * parent = Q_NULLPTR);
+ virtual ~AuthorListModel();
+
+ QString acknowledgment() const;
+
+protected:
+ virtual QStringList headerColumns() const;
+
+private:
+ QString acknowledgement_;
+
+};
+
+class PluginListModel : public AStringListListModel
+{
+ Q_OBJECT
+public:
+ explicit PluginListModel(QObject * parent = Q_NULLPTR);
+
+ QStringList typeNames() const;
+
+protected:
+ virtual QStringList headerColumns() const;
+
+private:
+ QStringList typeNames_;
+};
+
+class ShortcutListModel : public AStringListListModel
+{
+ Q_OBJECT
+public:
+ explicit ShortcutListModel(QObject * parent = Q_NULLPTR);
+
+protected:
+ virtual QStringList headerColumns() const;
+};
+
+class FolderListModel : public AStringListListModel
+{
+ Q_OBJECT
+public:
+ explicit FolderListModel(QObject * parent = Q_NULLPTR);
+
+protected:
+ virtual QStringList headerColumns() const;
+};
+
class AboutDialog : public QDialog
{
Q_OBJECT
@@ -36,14 +86,11 @@ public:
explicit AboutDialog(QWidget *parent = 0);
~AboutDialog();
- const QString about_folders_row(const char *, const QString dir, const char *typ_file);
- const QString plugins_scan();
+protected:
+ virtual void resizeEvent(QResizeEvent *);
-public slots:
- void updateAuthors(const QString&);
private:
Ui::AboutDialog *ui;
- void addAuthors(const QString&);
};
#endif // ABOUT_DIALOG_H
diff --git a/ui/qt/about_dialog.ui b/ui/qt/about_dialog.ui
index e517db60f3..8d029382f6 100644
--- a/ui/qt/about_dialog.ui
+++ b/ui/qt/about_dialog.ui
@@ -164,6 +164,13 @@
</widget>
</item>
<item>
+ <widget class="QTableView" name="tblAuthors">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPlainTextEdit" name="pte_Authors">
<property name="readOnly">
<bool>true</bool>
@@ -178,6 +185,20 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
+ <widget class="QLineEdit" name="searchFolders">
+ <property name="placeholderText">
+ <string>Filter by path</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="tblFolders">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="label_folders">
<property name="text">
<string/>
@@ -204,12 +225,30 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
- <widget class="QTextEdit" name="te_plugins">
- <property name="tabChangesFocus">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLineEdit" name="searchPlugins">
+ <property name="placeholderText">
+ <string>Search plugins</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Filter by type:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="cmbType"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTableView" name="tblPlugins">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
@@ -221,12 +260,16 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_shortcuts">
<item>
- <widget class="QTextEdit" name="te_shortcuts">
- <property name="tabChangesFocus">
- <bool>true</bool>
+ <widget class="QLineEdit" name="searchShortcuts">
+ <property name="placeholderText">
+ <string>Search Shortcuts</string>
</property>
- <property name="readOnly">
- <bool>true</bool>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="tblShortcuts">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
diff --git a/ui/qt/models/astringlist_list_model.cpp b/ui/qt/models/astringlist_list_model.cpp
new file mode 100644
index 0000000000..61c6a6e39a
--- /dev/null
+++ b/ui/qt/models/astringlist_list_model.cpp
@@ -0,0 +1,169 @@
+/* astringlist_list_model.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <QSortFilterProxyModel>
+#include <QStringList>
+
+#include <ui/qt/models/astringlist_list_model.h>
+
+AStringListListModel::AStringListListModel(QObject * parent):
+ QAbstractItemModel(parent)
+{}
+
+AStringListListModel::~AStringListListModel() { modelData.clear(); }
+
+void AStringListListModel::appendRow(const QStringList & data, const QModelIndex &parent)
+{
+ QStringList columns = headerColumns();
+ if ( data.count() != columns.count() )
+ return;
+
+ emit beginInsertRows(parent, rowCount(), rowCount());
+ modelData << data;
+ emit endInsertRows();
+}
+
+int AStringListListModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return modelData.count();
+}
+
+int AStringListListModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return headerColumns().count();
+}
+
+QVariant AStringListListModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if ( orientation == Qt::Vertical )
+ return QVariant();
+
+ QStringList columns = headerColumns();
+ if ( role == Qt::DisplayRole && section < columns.count() )
+ return qVariantFromValue(columns[section]);
+
+ return QVariant();
+}
+
+QVariant AStringListListModel::data(const QModelIndex &index, int role) const
+{
+ if ( role != Qt::DisplayRole || ! index.isValid() || index.row() >= rowCount() )
+ return QVariant();
+
+ QStringList data = modelData.at(index.row());
+
+ if ( index.column() < columnCount() )
+ return qVariantFromValue(data.at(index.column()));
+
+ return QVariant();
+}
+
+QModelIndex AStringListListModel::index(int row, int column, const QModelIndex & parent) const
+{
+ Q_UNUSED(parent);
+
+ if ( row >= rowCount() || column >= columnCount() )
+ return QModelIndex();
+
+ return createIndex(row, column);
+}
+
+QModelIndex AStringListListModel::parent(const QModelIndex & parent) const
+{
+ Q_UNUSED(parent);
+
+ return QModelIndex();
+}
+
+AStringListListSortFilterProxyModel::AStringListListSortFilterProxyModel(QObject * parent)
+: QSortFilterProxyModel(parent)
+{
+ filter_ = QString();
+ type_ = FilterByContains;
+}
+
+bool AStringListListSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+ QString leftData = sourceModel()->data(left).toStringList().join(",");
+ QString rightData = sourceModel()->data(right).toStringList().join(",");
+
+ return QString::localeAwareCompare(leftData, rightData) < 0;
+}
+
+void AStringListListSortFilterProxyModel::setFilter(const QString & filter)
+{
+ filter_ = filter;
+ invalidateFilter();
+}
+
+bool AStringListListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ bool check = false;
+
+ if ( columnsToFilter_.count() == 0 )
+ return true;
+
+ foreach(int column, columnsToFilter_)
+ {
+ if ( column >= columnCount() )
+ continue;
+
+ QModelIndex chkIdx = sourceModel()->index(sourceRow, column, sourceParent);
+ if ( type_ == FilterByContains && sourceModel()->data(chkIdx).toString().contains(filter_) )
+ check = true;
+ else if ( type_ == FilterByStart && sourceModel()->data(chkIdx).toString().startsWith(filter_) )
+ check = true;
+
+ if ( check )
+ break;
+ }
+
+ return check;
+}
+
+void AStringListListSortFilterProxyModel::setFilterType(AStringListListFilterType type)
+{
+ if ( type != type_ )
+ {
+ type_ = type;
+ invalidateFilter();
+ }
+}
+
+void AStringListListSortFilterProxyModel::setColumnToFilter(int column)
+{
+ if ( column < columnCount() && ! columnsToFilter_.contains(column) )
+ {
+ columnsToFilter_.append(column);
+ invalidateFilter();
+ }
+}
+
+void AStringListListSortFilterProxyModel::clearColumnsToFilter()
+{
+ columnsToFilter_.clear();
+ invalidateFilter();
+}
+
+/*
+ * 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/astringlist_list_model.h b/ui/qt/models/astringlist_list_model.h
new file mode 100644
index 0000000000..12250b1d45
--- /dev/null
+++ b/ui/qt/models/astringlist_list_model.h
@@ -0,0 +1,92 @@
+/* astringlist_list_model.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef ASTRINGLIST_LIST_MODEL_H
+#define ASTRINGLIST_LIST_MODEL_H
+
+#include <config.h>
+
+#include <QAbstractItemModel>
+#include <QModelIndex>
+#include <QList>
+#include <QStringList>
+#include <QSortFilterProxyModel>
+
+class AStringListListModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit AStringListListModel(QObject * parent = Q_NULLPTR);
+ virtual ~AStringListListModel();
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+ virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
+ virtual QModelIndex parent(const QModelIndex & parent = QModelIndex()) const;
+
+protected:
+ virtual void appendRow(const QStringList &, const QModelIndex &parent = QModelIndex());
+
+ virtual QStringList headerColumns() const = 0;
+
+private:
+ QList<QStringList> modelData;
+};
+
+class AStringListListSortFilterProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+
+ enum AStringListListFilterType
+ {
+ FilterByContains = 0,
+ FilterByStart = 1
+ };
+
+ explicit AStringListListSortFilterProxyModel(QObject * parent = Q_NULLPTR);
+
+ virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+ void setFilterType(AStringListListFilterType type);
+
+ void setColumnToFilter(int);
+ void clearColumnsToFilter();
+
+public slots:
+ void setFilter(const QString&);
+
+private:
+
+ QString filter_;
+ AStringListListFilterType type_;
+ QList<int> columnsToFilter_;
+};
+
+
+
+#endif // ASTRINGLIST_LIST_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:
+ */
diff --git a/ui/qt/models/html_text_delegate.cpp b/ui/qt/models/html_text_delegate.cpp
new file mode 100644
index 0000000000..b906ac2d17
--- /dev/null
+++ b/ui/qt/models/html_text_delegate.cpp
@@ -0,0 +1,66 @@
+/* html_text_delegate.cpp
+ * Delegates for displaying links as links, including elide model
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <ui/qt/models/html_text_delegate.h>
+
+#include <QComboBox>
+#include <QEvent>
+#include <QLineEdit>
+#include <QPainter>
+#include <QTextDocument>
+#include <QRect>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+#include <QString>
+
+HTMLTextDelegate::HTMLTextDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{}
+
+void HTMLTextDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
+ QStyleOptionViewItem options = option;
+ initStyleOption(&options, index);
+
+ painter->save();
+
+ QTextDocument doc;
+ doc.setHtml(options.text);
+
+ options.text = QStringLiteral("");
+ options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &option, painter);
+
+ painter->translate(options.rect.left(), options.rect.top());
+ QRect clip(0, 0, options.rect.width(), options.rect.height());
+ doc.drawContents(painter, clip);
+
+ painter->restore();
+}
+
+QSize HTMLTextDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
+ QStyleOptionViewItem options = option;
+ initStyleOption(&options, index);
+
+ QTextDocument doc;
+ doc.setHtml(options.text);
+ doc.setTextWidth(options.rect.width());
+ return QSize(doc.idealWidth(), doc.size().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/models/html_text_delegate.h b/ui/qt/models/html_text_delegate.h
new file mode 100644
index 0000000000..e8e2ffd308
--- /dev/null
+++ b/ui/qt/models/html_text_delegate.h
@@ -0,0 +1,48 @@
+/* html_text_delegate.h
+ * Delegates for displaying links as links, including elide model
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef HTML_TEXT_DELEGATE_H
+#define HTML_TEXT_DELEGATE_H
+
+#include <config.h>
+
+#include <QWidget>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+#include <QModelIndex>
+#include <QAbstractItemModel>
+
+class HTMLTextDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ explicit HTMLTextDelegate(QObject *parent = Q_NULLPTR);
+
+protected:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+
+};
+#endif // HTML_TEXT_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:
+ */
diff --git a/ui/qt/models/url_link_delegate.cpp b/ui/qt/models/url_link_delegate.cpp
new file mode 100644
index 0000000000..fccb0e3071
--- /dev/null
+++ b/ui/qt/models/url_link_delegate.cpp
@@ -0,0 +1,68 @@
+/* url_link.cpp
+ * Delegates for displaying links as links, including elide model
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <ui/qt/models/url_link_delegate.h>
+
+#include <QComboBox>
+#include <QEvent>
+#include <QLineEdit>
+#include <QPainter>
+#include <QTextDocument>
+#include <QRect>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+#include <QTextEdit>
+
+UrlLinkDelegate::UrlLinkDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{}
+
+void UrlLinkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
+ QStyleOptionViewItem options = option;
+ initStyleOption(&options, index);
+
+ QString text = options.text;
+ if (text.isEmpty())
+ return;
+
+ int one_em = painter->fontMetrics().height();
+ QString short_dir = painter->fontMetrics().elidedText(text, Qt::ElideMiddle, one_em * 10);
+
+ painter->save();
+ QFont font = option.font;
+ font.setUnderline(true);
+ painter->setFont(font);
+ painter->setPen(option.palette.link().color());
+ painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, short_dir);
+
+ painter->restore();
+}
+
+QSize UrlLinkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
+ QStyleOptionViewItem options = option;
+ initStyleOption(&options, index);
+
+ QTextDocument doc;
+ doc.setHtml(options.text);
+ doc.setTextWidth(options.rect.width());
+ return QSize(doc.idealWidth(), doc.size().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/models/url_link_delegate.h b/ui/qt/models/url_link_delegate.h
new file mode 100644
index 0000000000..3977fbfe43
--- /dev/null
+++ b/ui/qt/models/url_link_delegate.h
@@ -0,0 +1,35 @@
+/* url_link_delegate.h
+ * Delegates for displaying links as links, including elide model
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef URL_LINK_DELEGATE_H
+#define URL_LINK_DELEGATE_H
+
+#include <config.h>
+
+#include <QWidget>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
+#include <QModelIndex>
+#include <QAbstractItemModel>
+
+class UrlLinkDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ explicit UrlLinkDelegate(QObject *parent = Q_NULLPTR);
+
+protected:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+
+};
+#endif // URL_LINK_DELEGATE_H