2012-01-04 22:13:01 +00:00
|
|
|
/* proto_tree.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
|
2012-06-28 22:56:06 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2012-01-04 22:13:01 +00:00
|
|
|
*/
|
|
|
|
|
2012-01-14 00:16:16 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
#include "proto_tree.h"
|
|
|
|
|
2012-08-19 23:52:08 +00:00
|
|
|
#include <epan/ftypes/ftypes.h>
|
2012-01-04 22:13:01 +00:00
|
|
|
#include <epan/prefs.h>
|
|
|
|
|
2015-03-11 22:22:20 +00:00
|
|
|
#include "color_utils.h"
|
|
|
|
|
2014-09-23 20:35:10 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QContextMenuEvent>
|
|
|
|
#include <QDesktopServices>
|
2012-01-04 22:13:01 +00:00
|
|
|
#include <QHeaderView>
|
2016-03-10 20:43:59 +00:00
|
|
|
#include <QScrollBar>
|
2012-08-14 04:12:56 +00:00
|
|
|
#include <QTreeWidgetItemIterator>
|
2012-08-19 23:52:08 +00:00
|
|
|
#include <QUrl>
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-07-23 19:53:45 +00:00
|
|
|
// To do:
|
|
|
|
// - Fix "apply as filter" behavior.
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
/* Fill a single protocol tree item with its string value and set its color. */
|
|
|
|
static void
|
|
|
|
proto_tree_draw_node(proto_node *node, gpointer data)
|
|
|
|
{
|
|
|
|
field_info *fi = PNODE_FINFO(node);
|
2015-05-12 23:28:39 +00:00
|
|
|
QString label;
|
2012-11-01 17:30:10 +00:00
|
|
|
gboolean is_branch;
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2012-09-05 01:44:09 +00:00
|
|
|
/* dissection with an invisible proto tree? */
|
|
|
|
g_assert(fi);
|
2012-01-04 22:13:01 +00:00
|
|
|
|
|
|
|
if (PROTO_ITEM_IS_HIDDEN(node) && !prefs.display_hidden_proto_items)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Fill in our label
|
|
|
|
/* was a free format label produced? */
|
|
|
|
if (fi->rep) {
|
2015-05-12 23:28:39 +00:00
|
|
|
label = fi->rep->representation;
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
else { /* no, make a generic label */
|
2015-05-12 23:28:39 +00:00
|
|
|
gchar label_str[ITEM_LABEL_LENGTH];
|
2012-01-04 22:13:01 +00:00
|
|
|
proto_item_fill_label(fi, label_str);
|
2015-05-12 23:28:39 +00:00
|
|
|
label = label_str;
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (node->first_child != NULL) {
|
2012-11-01 17:30:10 +00:00
|
|
|
is_branch = TRUE;
|
2012-01-04 22:13:01 +00:00
|
|
|
g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
|
|
|
|
}
|
|
|
|
else {
|
2012-11-01 17:30:10 +00:00
|
|
|
is_branch = FALSE;
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PROTO_ITEM_IS_GENERATED(node)) {
|
|
|
|
if (PROTO_ITEM_IS_HIDDEN(node)) {
|
2015-05-12 23:28:39 +00:00
|
|
|
label = QString("<[%1]>").arg(label);
|
2012-01-04 22:13:01 +00:00
|
|
|
} else {
|
2015-05-12 23:28:39 +00:00
|
|
|
label = QString("[%1]").arg(label);
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
} else if (PROTO_ITEM_IS_HIDDEN(node)) {
|
2015-05-12 23:28:39 +00:00
|
|
|
label = QString("<%1>").arg(label);
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QTreeWidgetItem *parentItem = (QTreeWidgetItem *)data;
|
|
|
|
QTreeWidgetItem *item;
|
2013-07-08 16:54:18 +00:00
|
|
|
ProtoTree *proto_tree = qobject_cast<ProtoTree *>(parentItem->treeWidget());
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
item = new QTreeWidgetItem(parentItem, 0);
|
|
|
|
|
|
|
|
// Set our colors.
|
|
|
|
QPalette pal = QApplication::palette();
|
2016-07-02 21:05:24 +00:00
|
|
|
if (fi->hfinfo) {
|
2012-01-04 22:13:01 +00:00
|
|
|
if(fi->hfinfo->type == FT_PROTOCOL) {
|
2014-10-29 00:10:45 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, pal.window());
|
|
|
|
item->setData(0, Qt::ForegroundRole, pal.windowText());
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if((fi->hfinfo->type == FT_FRAMENUM) ||
|
2012-08-19 20:47:11 +00:00
|
|
|
(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type))) {
|
|
|
|
QFont font = item->font(0);
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
item->setData(0, Qt::ForegroundRole, pal.link());
|
2012-08-19 20:47:11 +00:00
|
|
|
font.setUnderline(true);
|
|
|
|
item->setData(0, Qt::FontRole, font);
|
2013-07-08 16:54:18 +00:00
|
|
|
|
|
|
|
if (fi->hfinfo->type == FT_FRAMENUM) {
|
2015-02-24 01:56:14 +00:00
|
|
|
ft_framenum_type_t framenum_type = (ft_framenum_type_t)GPOINTER_TO_INT(fi->hfinfo->strings);
|
|
|
|
proto_tree->emitRelatedFrame(fi->value.value.uinteger, framenum_type);
|
2013-07-08 16:54:18 +00:00
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX - Add routines to get our severity colors.
|
|
|
|
if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
|
|
|
|
switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
|
2012-10-11 12:31:39 +00:00
|
|
|
case(PI_COMMENT):
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, ColorUtils::expert_color_comment);
|
2012-10-11 12:31:39 +00:00
|
|
|
break;
|
2012-01-04 22:13:01 +00:00
|
|
|
case(PI_CHAT):
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, ColorUtils::expert_color_chat);
|
2012-01-04 22:13:01 +00:00
|
|
|
break;
|
|
|
|
case(PI_NOTE):
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, ColorUtils::expert_color_note);
|
2012-01-04 22:13:01 +00:00
|
|
|
break;
|
|
|
|
case(PI_WARN):
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, ColorUtils::expert_color_warn);
|
2012-01-04 22:13:01 +00:00
|
|
|
break;
|
|
|
|
case(PI_ERROR):
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::BackgroundRole, ColorUtils::expert_color_error);
|
2012-01-04 22:13:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
2015-03-11 22:22:20 +00:00
|
|
|
item->setData(0, Qt::ForegroundRole, ColorUtils::expert_color_foreground);
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 23:28:39 +00:00
|
|
|
item->setText(0, label);
|
2012-08-19 20:47:11 +00:00
|
|
|
item->setData(0, Qt::UserRole, qVariantFromValue(fi));
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2012-11-01 17:30:10 +00:00
|
|
|
if (is_branch) {
|
2013-07-07 16:33:49 +00:00
|
|
|
if (tree_expanded(fi->tree_type)) {
|
2012-11-01 17:30:10 +00:00
|
|
|
item->setExpanded(true);
|
|
|
|
} else {
|
|
|
|
item->setExpanded(false);
|
|
|
|
}
|
2012-08-19 20:47:11 +00:00
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
proto_tree_children_foreach(node, proto_tree_draw_node, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ProtoTree::ProtoTree(QWidget *parent) :
|
2013-12-10 21:07:26 +00:00
|
|
|
QTreeWidget(parent),
|
2016-03-10 20:43:59 +00:00
|
|
|
decode_as_(NULL),
|
|
|
|
column_resize_timer_(0)
|
2012-01-04 22:13:01 +00:00
|
|
|
{
|
2012-03-07 10:16:33 +00:00
|
|
|
setAccessibleName(tr("Packet details"));
|
2015-05-12 23:28:39 +00:00
|
|
|
// Leave the uniformRowHeights property as-is (false) since items might
|
|
|
|
// have multiple lines (e.g. packet comments). If this slows things down
|
|
|
|
// too much we should add a custom delegate which handles SizeHintRole
|
|
|
|
// similar to PacketListModel::data.
|
2015-02-11 23:00:27 +00:00
|
|
|
setHeaderHidden(true);
|
|
|
|
|
|
|
|
if (window()->findChild<QAction *>("actionViewExpandSubtrees")) {
|
|
|
|
// Assume we're a child of the main window.
|
|
|
|
// XXX We might want to reimplement setParent() and fill in the context
|
|
|
|
// menu there.
|
2015-07-29 23:24:39 +00:00
|
|
|
QMenu *main_menu_item, *submenu;
|
2015-07-23 19:53:45 +00:00
|
|
|
QAction *action;
|
|
|
|
|
2015-02-11 23:00:27 +00:00
|
|
|
ctx_menu_.addAction(window()->findChild<QAction *>("actionViewExpandSubtrees"));
|
|
|
|
ctx_menu_.addAction(window()->findChild<QAction *>("actionViewExpandAll"));
|
|
|
|
ctx_menu_.addAction(window()->findChild<QAction *>("actionViewCollapseAll"));
|
|
|
|
ctx_menu_.addSeparator();
|
2015-03-09 07:11:13 +00:00
|
|
|
|
|
|
|
action = window()->findChild<QAction *>("actionAnalyzeCreateAColumn");
|
|
|
|
ctx_menu_.addAction(action);
|
|
|
|
ctx_menu_.addSeparator();
|
|
|
|
|
2015-07-27 22:28:50 +00:00
|
|
|
main_menu_item = window()->findChild<QMenu *>("menuApplyAsFilter");
|
|
|
|
submenu = new QMenu(main_menu_item->title());
|
2015-07-23 19:53:45 +00:00
|
|
|
ctx_menu_.addMenu(submenu);
|
2015-02-11 23:00:27 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFNotSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndNotSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrNotSelected"));
|
|
|
|
|
2015-07-27 22:28:50 +00:00
|
|
|
main_menu_item = window()->findChild<QMenu *>("menuPrepareAFilter");
|
|
|
|
submenu = new QMenu(main_menu_item->title());
|
2015-07-23 19:53:45 +00:00
|
|
|
ctx_menu_.addMenu(submenu);
|
2015-02-11 23:00:27 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFNotSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndNotSelected"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrNotSelected"));
|
2013-12-21 16:55:43 +00:00
|
|
|
|
2014-08-08 10:59:42 +00:00
|
|
|
QMenu *main_conv_menu = window()->findChild<QMenu *>("menuConversationFilter");
|
|
|
|
conv_menu_.setTitle(main_conv_menu->title());
|
|
|
|
ctx_menu_.addMenu(&conv_menu_);
|
|
|
|
|
2015-07-30 23:15:40 +00:00
|
|
|
colorize_menu_.setTitle(tr("Colorize with Filter"));
|
|
|
|
ctx_menu_.addMenu(&colorize_menu_);
|
2015-07-30 20:55:46 +00:00
|
|
|
|
|
|
|
main_menu_item = window()->findChild<QMenu *>("menuFollow");
|
|
|
|
submenu = new QMenu(main_menu_item->title());
|
|
|
|
ctx_menu_.addMenu(submenu);
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTCPStream"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowSSLStream"));
|
2016-01-02 13:58:08 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
|
2015-02-11 23:00:27 +00:00
|
|
|
ctx_menu_.addSeparator();
|
|
|
|
|
2015-07-29 23:24:39 +00:00
|
|
|
main_menu_item = window()->findChild<QMenu *>("menuEditCopy");
|
|
|
|
submenu = new QMenu(main_menu_item->title());
|
2015-07-24 01:39:30 +00:00
|
|
|
ctx_menu_.addMenu(submenu);
|
2015-03-23 11:04:36 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionCopyAllVisibleItems"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionCopyAllVisibleSelectedTreeItems"));
|
2015-02-11 23:00:27 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionEditCopyDescription"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionEditCopyFieldName"));
|
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionEditCopyValue"));
|
|
|
|
submenu->addSeparator();
|
|
|
|
|
2015-07-30 19:23:03 +00:00
|
|
|
submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
|
2015-07-29 23:24:39 +00:00
|
|
|
submenu->addSeparator();
|
|
|
|
|
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesHexTextDump");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesHexDump");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesPrintableText");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesHexStream");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesBinary");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
2016-09-14 03:33:54 +00:00
|
|
|
action = window()->findChild<QAction *>("actionContextCopyBytesEscapedString");
|
|
|
|
submenu->addAction(action);
|
|
|
|
copy_actions_ << action;
|
2015-07-29 23:24:39 +00:00
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
action = window()->findChild<QAction *>("actionContextShowPacketBytes");
|
|
|
|
ctx_menu_.addAction(action);
|
2015-07-30 20:55:46 +00:00
|
|
|
action = window()->findChild<QAction *>("actionFileExportPacketBytes");
|
|
|
|
ctx_menu_.addAction(action);
|
|
|
|
|
|
|
|
ctx_menu_.addSeparator();
|
|
|
|
|
2015-07-31 23:52:37 +00:00
|
|
|
action = window()->findChild<QAction *>("actionContextWikiProtocolPage");
|
|
|
|
ctx_menu_.addAction(action);
|
|
|
|
action = window()->findChild<QAction *>("actionContextFilterFieldReference");
|
|
|
|
ctx_menu_.addAction(action);
|
2012-12-07 01:46:20 +00:00
|
|
|
// " <menuitem name='ProtocolHelp' action='/ProtocolHelp'/>\n"
|
2015-06-17 00:24:19 +00:00
|
|
|
ctx_menu_.addMenu(&proto_prefs_menu_);
|
|
|
|
ctx_menu_.addSeparator();
|
2015-02-11 23:00:27 +00:00
|
|
|
decode_as_ = window()->findChild<QAction *>("actionAnalyzeDecodeAs");
|
|
|
|
ctx_menu_.addAction(decode_as_);
|
2012-12-07 01:46:20 +00:00
|
|
|
// " <menuitem name='ResolveName' action='/ResolveName'/>\n"
|
2015-07-31 23:52:37 +00:00
|
|
|
ctx_menu_.addAction(window()->findChild<QAction *>("actionGoGoToLinkedPacket"));
|
|
|
|
ctx_menu_.addAction(window()->findChild<QAction *>("actionContextShowLinkedPacketInNewWindow"));
|
2015-02-11 23:00:27 +00:00
|
|
|
} else {
|
|
|
|
ctx_menu_.clear();
|
|
|
|
}
|
2012-12-07 01:46:20 +00:00
|
|
|
|
2012-01-14 00:16:16 +00:00
|
|
|
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
|
|
|
|
this, SLOT(updateSelectionStatus(QTreeWidgetItem*)));
|
2012-08-19 20:47:11 +00:00
|
|
|
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(expand(QModelIndex)));
|
|
|
|
connect(this, SIGNAL(collapsed(QModelIndex)), this, SLOT(collapse(QModelIndex)));
|
2012-08-19 23:52:08 +00:00
|
|
|
connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
|
|
|
|
this, SLOT(itemDoubleClick(QTreeWidgetItem*, int)));
|
2015-06-17 00:24:19 +00:00
|
|
|
|
|
|
|
connect(&proto_prefs_menu_, SIGNAL(showProtocolPreferences(QString)),
|
|
|
|
this, SIGNAL(showProtocolPreferences(QString)));
|
2015-06-17 15:41:41 +00:00
|
|
|
connect(&proto_prefs_menu_, SIGNAL(editProtocolPreference(preference*,pref_module*)),
|
|
|
|
this, SIGNAL(editProtocolPreference(preference*,pref_module*)));
|
2016-03-10 20:43:59 +00:00
|
|
|
|
|
|
|
// resizeColumnToContents checks 1000 items by default. The user might
|
|
|
|
// have scrolled to an area with a different width at this point.
|
|
|
|
connect(verticalScrollBar(), SIGNAL(sliderReleased()),
|
|
|
|
this, SLOT(updateContentWidth()));
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 17:18:07 +00:00
|
|
|
void ProtoTree::closeContextMenu()
|
|
|
|
{
|
|
|
|
ctx_menu_.close();
|
|
|
|
}
|
|
|
|
|
2012-01-14 00:16:16 +00:00
|
|
|
void ProtoTree::clear() {
|
|
|
|
updateSelectionStatus(NULL);
|
|
|
|
QTreeWidget::clear();
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 01:46:20 +00:00
|
|
|
void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
|
|
|
|
{
|
2015-02-11 23:00:27 +00:00
|
|
|
if (ctx_menu_.isEmpty()) return; // We're in a PacketDialog
|
|
|
|
|
2014-08-08 10:59:42 +00:00
|
|
|
QMenu *main_conv_menu = window()->findChild<QMenu *>("menuConversationFilter");
|
|
|
|
conv_menu_.clear();
|
|
|
|
foreach (QAction *action, main_conv_menu->actions()) {
|
|
|
|
conv_menu_.addAction(action);
|
|
|
|
}
|
|
|
|
|
2015-07-29 23:24:39 +00:00
|
|
|
field_info *fi = NULL;
|
2015-06-17 00:24:19 +00:00
|
|
|
const char *module_name = NULL;
|
|
|
|
if (selectedItems().count() > 0) {
|
2015-07-29 23:24:39 +00:00
|
|
|
fi = selectedItems()[0]->data(0, Qt::UserRole).value<field_info *>();
|
2015-06-17 00:24:19 +00:00
|
|
|
if (fi && fi->hfinfo) {
|
|
|
|
if (fi->hfinfo->parent == -1) {
|
|
|
|
module_name = fi->hfinfo->abbrev;
|
|
|
|
} else {
|
|
|
|
module_name = proto_registrar_get_abbrev(fi->hfinfo->parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
proto_prefs_menu_.setModule(module_name);
|
|
|
|
|
2015-07-29 23:24:39 +00:00
|
|
|
foreach (QAction *action, copy_actions_) {
|
|
|
|
action->setData(QVariant::fromValue<field_info *>(fi));
|
|
|
|
}
|
|
|
|
|
2013-12-10 21:07:26 +00:00
|
|
|
decode_as_->setData(qVariantFromValue(true));
|
2015-07-29 23:24:39 +00:00
|
|
|
|
|
|
|
// Set menu sensitivity and action data.
|
|
|
|
emit protoItemSelected(fi);
|
2012-12-07 01:46:20 +00:00
|
|
|
ctx_menu_.exec(event->globalPos());
|
2013-12-10 21:07:26 +00:00
|
|
|
decode_as_->setData(QVariant());
|
2012-12-07 01:46:20 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 20:43:59 +00:00
|
|
|
void ProtoTree::timerEvent(QTimerEvent *event)
|
|
|
|
{
|
|
|
|
if (event->timerId() == column_resize_timer_) {
|
|
|
|
killTimer(column_resize_timer_);
|
|
|
|
column_resize_timer_ = 0;
|
|
|
|
resizeColumnToContents(0);
|
2016-03-14 20:29:21 +00:00
|
|
|
} else {
|
|
|
|
QTreeWidget::timerEvent(event);
|
2016-03-10 20:43:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// resizeColumnToContents checks 1000 items by default. The user might
|
|
|
|
// have scrolled to an area with a different width at this point.
|
|
|
|
void ProtoTree::keyReleaseEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
if (event->isAutoRepeat()) return;
|
|
|
|
|
|
|
|
switch(event->key()) {
|
|
|
|
case Qt::Key_Up:
|
|
|
|
case Qt::Key_Down:
|
|
|
|
case Qt::Key_PageUp:
|
|
|
|
case Qt::Key_PageDown:
|
|
|
|
case Qt::Key_Home:
|
|
|
|
case Qt::Key_End:
|
|
|
|
updateContentWidth();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProtoTree::updateContentWidth()
|
|
|
|
{
|
|
|
|
if (column_resize_timer_ == 0) {
|
|
|
|
column_resize_timer_ = startTimer(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-23 20:35:10 +00:00
|
|
|
void ProtoTree::setMonospaceFont(const QFont &mono_font)
|
|
|
|
{
|
|
|
|
mono_font_ = mono_font;
|
|
|
|
setFont(mono_font_);
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
2012-01-14 00:16:16 +00:00
|
|
|
void ProtoTree::fillProtocolTree(proto_tree *protocol_tree) {
|
|
|
|
clear();
|
2014-09-23 20:35:10 +00:00
|
|
|
setFont(mono_font_);
|
2012-01-14 00:16:16 +00:00
|
|
|
|
|
|
|
proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, invisibleRootItem());
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
|
|
|
|
2015-02-24 01:56:14 +00:00
|
|
|
void ProtoTree::emitRelatedFrame(int related_frame, ft_framenum_type_t framenum_type)
|
2013-07-08 16:54:18 +00:00
|
|
|
{
|
2015-02-24 01:56:14 +00:00
|
|
|
emit relatedFrame(related_frame, framenum_type);
|
2013-07-08 16:54:18 +00:00
|
|
|
}
|
|
|
|
|
2015-03-11 22:22:20 +00:00
|
|
|
// XXX We select the first match, which might not be the desired item.
|
|
|
|
void ProtoTree::goToField(int hf_id)
|
|
|
|
{
|
|
|
|
if (hf_id < 0) return;
|
|
|
|
|
|
|
|
QTreeWidgetItemIterator iter(this);
|
|
|
|
while (*iter) {
|
|
|
|
field_info *fi = (*iter)->data(0, Qt::UserRole).value<field_info *>();
|
|
|
|
|
|
|
|
if (fi && fi->hfinfo) {
|
|
|
|
if (fi->hfinfo->id == hf_id) {
|
|
|
|
setCurrentItem(*iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-05-23 19:49:51 +00:00
|
|
|
++iter;
|
2015-03-11 22:22:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 06:46:43 +00:00
|
|
|
void ProtoTree::updateSelectionStatus(QTreeWidgetItem* item)
|
|
|
|
{
|
2012-01-14 00:16:16 +00:00
|
|
|
if (item) {
|
|
|
|
field_info *fi;
|
2012-11-06 21:49:16 +00:00
|
|
|
QString item_info;
|
2012-01-14 00:16:16 +00:00
|
|
|
|
2012-08-19 20:47:11 +00:00
|
|
|
fi = item->data(0, Qt::UserRole).value<field_info *>();
|
2012-01-14 00:16:16 +00:00
|
|
|
if (!fi || !fi->hfinfo) return;
|
|
|
|
|
|
|
|
if (fi->hfinfo->blurb != NULL && fi->hfinfo->blurb[0] != '\0') {
|
2012-11-06 21:49:16 +00:00
|
|
|
item_info.append(QString().fromUtf8(fi->hfinfo->blurb));
|
2012-01-14 00:16:16 +00:00
|
|
|
} else {
|
2012-11-06 21:49:16 +00:00
|
|
|
item_info.append(QString().fromUtf8(fi->hfinfo->name));
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:49:16 +00:00
|
|
|
if (!item_info.isEmpty()) {
|
2012-10-13 01:29:29 +00:00
|
|
|
int finfo_length;
|
2012-11-06 21:49:16 +00:00
|
|
|
item_info.append(" (" + QString().fromUtf8(fi->hfinfo->abbrev) + ")");
|
2012-01-14 00:16:16 +00:00
|
|
|
|
|
|
|
finfo_length = fi->length + fi->appendix_length;
|
|
|
|
if (finfo_length == 1) {
|
2012-11-06 21:49:16 +00:00
|
|
|
item_info.append(tr(", 1 byte"));
|
2012-01-14 00:16:16 +00:00
|
|
|
} else if (finfo_length > 1) {
|
2012-11-06 21:49:16 +00:00
|
|
|
item_info.append(QString(tr(", %1 bytes")).arg(finfo_length));
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
|
|
|
|
2016-03-29 22:47:12 +00:00
|
|
|
saveSelectedField(item);
|
|
|
|
|
2015-09-15 06:46:43 +00:00
|
|
|
emit protoItemSelected("");
|
2012-10-16 00:01:23 +00:00
|
|
|
emit protoItemSelected(NULL);
|
2012-11-06 21:49:16 +00:00
|
|
|
emit protoItemSelected(item_info);
|
2012-10-16 00:01:23 +00:00
|
|
|
emit protoItemSelected(fi);
|
2012-01-14 00:16:16 +00:00
|
|
|
} // else the GTK+ version pushes an empty string as described below.
|
|
|
|
/*
|
|
|
|
* Don't show anything if the field name is zero-length;
|
2015-09-11 21:41:13 +00:00
|
|
|
* the pseudo-field for text-only items is such
|
2012-01-14 00:16:16 +00:00
|
|
|
* a field, and we don't want "Text (text)" showing up
|
|
|
|
* on the status line if you've selected such a field.
|
|
|
|
*
|
|
|
|
* XXX - there are zero-length fields for which we *do*
|
|
|
|
* want to show the field name.
|
|
|
|
*
|
|
|
|
* XXX - perhaps the name and abbrev field should be null
|
|
|
|
* pointers rather than null strings for that pseudo-field,
|
|
|
|
* but we'd have to add checks for null pointers in some
|
|
|
|
* places if we did that.
|
|
|
|
*
|
2015-09-11 21:41:13 +00:00
|
|
|
* Or perhaps text-only items should have -1 as the field
|
|
|
|
* index, with no pseudo-field being used, but that might
|
|
|
|
* also require special checks for -1 to be added.
|
2012-01-14 00:16:16 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
} else {
|
2015-09-15 06:46:43 +00:00
|
|
|
emit protoItemSelected("");
|
2012-10-16 00:01:23 +00:00
|
|
|
emit protoItemSelected(NULL);
|
2012-01-14 00:16:16 +00:00
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
2012-08-14 04:12:56 +00:00
|
|
|
|
2012-08-19 20:47:11 +00:00
|
|
|
void ProtoTree::expand(const QModelIndex & index) {
|
|
|
|
field_info *fi;
|
|
|
|
|
|
|
|
fi = index.data(Qt::UserRole).value<field_info *>();
|
2015-03-09 21:19:37 +00:00
|
|
|
if (!fi) return;
|
2012-08-19 20:47:11 +00:00
|
|
|
|
|
|
|
if(prefs.gui_auto_scroll_on_expand) {
|
|
|
|
ScrollHint scroll_hint = PositionAtTop;
|
|
|
|
if (prefs.gui_auto_scroll_percentage > 66) {
|
|
|
|
scroll_hint = PositionAtBottom;
|
|
|
|
} else if (prefs.gui_auto_scroll_percentage >= 33) {
|
|
|
|
scroll_hint = PositionAtCenter;
|
|
|
|
}
|
|
|
|
scrollTo(index, scroll_hint);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Nodes with "finfo->tree_type" of -1 have no ett_ value, and
|
|
|
|
* are thus presumably leaf nodes and cannot be expanded.
|
|
|
|
*/
|
|
|
|
if (fi->tree_type != -1) {
|
|
|
|
g_assert(fi->tree_type >= 0 &&
|
|
|
|
fi->tree_type < num_tree_types);
|
2013-07-07 16:33:49 +00:00
|
|
|
tree_expanded_set(fi->tree_type, TRUE);
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
2016-01-13 19:27:11 +00:00
|
|
|
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProtoTree::collapse(const QModelIndex & index) {
|
|
|
|
field_info *fi;
|
|
|
|
|
|
|
|
fi = index.data(Qt::UserRole).value<field_info *>();
|
2015-03-09 21:19:37 +00:00
|
|
|
if (!fi) return;
|
2012-08-19 20:47:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Nodes with "finfo->tree_type" of -1 have no ett_ value, and
|
|
|
|
* are thus presumably leaf nodes and cannot be collapsed.
|
|
|
|
*/
|
|
|
|
if (fi->tree_type != -1) {
|
|
|
|
g_assert(fi->tree_type >= 0 &&
|
|
|
|
fi->tree_type < num_tree_types);
|
2013-07-07 16:33:49 +00:00
|
|
|
tree_expanded_set(fi->tree_type, FALSE);
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
2012-08-14 04:12:56 +00:00
|
|
|
|
|
|
|
void ProtoTree::expandSubtrees()
|
|
|
|
{
|
2012-11-06 21:49:16 +00:00
|
|
|
QTreeWidgetItem *top_sel;
|
2012-08-14 04:12:56 +00:00
|
|
|
|
2012-08-14 16:35:52 +00:00
|
|
|
if (selectedItems().length() < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:49:16 +00:00
|
|
|
top_sel = selectedItems()[0];
|
2012-08-14 16:35:52 +00:00
|
|
|
|
2012-11-06 21:49:16 +00:00
|
|
|
if (!top_sel) {
|
2012-08-14 16:35:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:49:16 +00:00
|
|
|
while (top_sel->parent()) {
|
|
|
|
top_sel = top_sel->parent();
|
2012-08-14 16:35:52 +00:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:49:16 +00:00
|
|
|
QTreeWidgetItemIterator iter(top_sel);
|
2012-08-14 16:35:52 +00:00
|
|
|
while (*iter) {
|
2012-11-06 21:49:16 +00:00
|
|
|
if ((*iter) != top_sel && (*iter)->parent() == NULL) {
|
2012-08-14 16:35:52 +00:00
|
|
|
// We found the next top-level item
|
|
|
|
break;
|
2012-08-14 04:12:56 +00:00
|
|
|
}
|
2012-08-14 16:35:52 +00:00
|
|
|
(*iter)->setExpanded(true);
|
2016-05-23 19:49:51 +00:00
|
|
|
++iter;
|
2012-08-14 04:12:56 +00:00
|
|
|
}
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-08-14 04:12:56 +00:00
|
|
|
}
|
|
|
|
|
2012-08-19 20:47:11 +00:00
|
|
|
void ProtoTree::expandAll()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i=0; i < num_tree_types; i++) {
|
2013-07-07 16:33:49 +00:00
|
|
|
tree_expanded_set(i, TRUE);
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
|
|
|
QTreeWidget::expandAll();
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProtoTree::collapseAll()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i=0; i < num_tree_types; i++) {
|
2013-07-07 16:33:49 +00:00
|
|
|
tree_expanded_set(i, FALSE);
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
|
|
|
QTreeWidget::collapseAll();
|
2016-03-10 20:43:59 +00:00
|
|
|
updateContentWidth();
|
2012-08-19 20:47:11 +00:00
|
|
|
}
|
2012-08-19 23:52:08 +00:00
|
|
|
|
2015-07-07 06:24:50 +00:00
|
|
|
void ProtoTree::itemDoubleClick(QTreeWidgetItem *item, int) {
|
2012-08-19 23:52:08 +00:00
|
|
|
field_info *fi;
|
|
|
|
|
|
|
|
fi = item->data(0, Qt::UserRole).value<field_info *>();
|
2015-03-09 21:19:37 +00:00
|
|
|
if (!fi || !fi->hfinfo) return;
|
2012-08-19 23:52:08 +00:00
|
|
|
|
|
|
|
if(fi->hfinfo->type == FT_FRAMENUM) {
|
2015-02-14 17:49:36 +00:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
2015-02-13 16:36:53 +00:00
|
|
|
if (QApplication::queryKeyboardModifiers() & Qt::ShiftModifier) {
|
2015-02-14 17:49:36 +00:00
|
|
|
#else
|
|
|
|
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
|
|
|
|
#endif
|
2015-02-13 16:36:53 +00:00
|
|
|
emit openPacketInNewWindow(true);
|
|
|
|
} else {
|
|
|
|
emit goToPacket(fi->value.value.uinteger);
|
|
|
|
}
|
2012-08-19 23:52:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type)) {
|
2012-10-13 01:29:29 +00:00
|
|
|
gchar *url;
|
2016-05-10 20:04:14 +00:00
|
|
|
url = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
|
2012-08-19 23:52:08 +00:00
|
|
|
if(url){
|
|
|
|
// browser_open_url(url);
|
|
|
|
QDesktopServices::openUrl(QUrl(url));
|
2016-05-10 20:04:14 +00:00
|
|
|
wmem_free(NULL, url);
|
2012-08-19 23:52:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 08:18:31 +00:00
|
|
|
|
2016-02-23 08:30:48 +00:00
|
|
|
void ProtoTree::selectField(field_info *fi)
|
|
|
|
{
|
|
|
|
QTreeWidgetItemIterator iter(this);
|
|
|
|
while (*iter) {
|
|
|
|
if (fi == (*iter)->data(0, Qt::UserRole).value<field_info *>()) {
|
|
|
|
setCurrentItem(*iter);
|
|
|
|
scrollToItem(*iter);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-23 19:49:51 +00:00
|
|
|
++iter;
|
2016-02-23 08:30:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-29 22:47:12 +00:00
|
|
|
// Remember the currently focussed field based on:
|
|
|
|
// - current hf_id (obviously)
|
|
|
|
// - parent items (to avoid selecting a text item in a different tree)
|
|
|
|
// - position within a tree if there are multiple items (wishlist)
|
|
|
|
static QList<int> serializeAsPath(QTreeWidgetItem *item)
|
|
|
|
{
|
|
|
|
QList<int> path;
|
|
|
|
do {
|
|
|
|
field_info *fi = item->data(0, Qt::UserRole).value<field_info *>();
|
|
|
|
path.prepend(fi->hfinfo->id);
|
|
|
|
} while ((item = item->parent()));
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
void ProtoTree::saveSelectedField(QTreeWidgetItem *item)
|
|
|
|
{
|
|
|
|
selected_field_path_ = serializeAsPath(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to focus a tree item which was previously also visible
|
|
|
|
void ProtoTree::restoreSelectedField()
|
|
|
|
{
|
|
|
|
if (selected_field_path_.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int last_hf_id = selected_field_path_.last();
|
|
|
|
QTreeWidgetItemIterator iter(this);
|
|
|
|
while (*iter) {
|
|
|
|
field_info *fi = (*iter)->data(0, Qt::UserRole).value<field_info *>();
|
|
|
|
if (last_hf_id == fi->hfinfo->id &&
|
|
|
|
serializeAsPath(*iter) == selected_field_path_) {
|
|
|
|
setCurrentItem(*iter);
|
|
|
|
scrollToItem(*iter);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-23 19:49:51 +00:00
|
|
|
++iter;
|
2016-03-29 22:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-04 08:18:31 +00:00
|
|
|
/*
|
|
|
|
* 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:
|
|
|
|
*/
|