add parameter dcerpc_info to PIDL_dissect_ipv?address()
[wireshark-wip.git] / ui / qt / proto_tree.cpp
blobf47f41c2a567eabfa055fe5ac571f8b854dd87ac
1 /* proto_tree.cpp
3 * $Id$
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <stdio.h>
26 #include "proto_tree.h"
28 #include <epan/ftypes/ftypes.h>
29 #include <epan/prefs.h>
31 #include "wireshark_application.h"
32 #include <QHeaderView>
33 #include <QTreeWidgetItemIterator>
34 #include <QDesktopServices>
35 #include <QUrl>
36 #include <QContextMenuEvent>
37 #include <QMainWindow>
39 QColor expert_color_comment ( 0xb7, 0xf7, 0x74 ); /* Green */
40 QColor expert_color_chat ( 0x80, 0xb7, 0xf7 ); /* light blue */
41 QColor expert_color_note ( 0xa0, 0xff, 0xff ); /* bright turquoise */
42 QColor expert_color_warn ( 0xf7, 0xf2, 0x53 ); /* yellow */
43 QColor expert_color_error ( 0xff, 0x5c, 0x5c ); /* pale red */
44 QColor expert_color_foreground ( 0x00, 0x00, 0x00 ); /* black */
45 QColor hidden_proto_item ( 0x44, 0x44, 0x44 ); /* gray */
47 /* Fill a single protocol tree item with its string value and set its color. */
48 static void
49 proto_tree_draw_node(proto_node *node, gpointer data)
51 field_info *fi = PNODE_FINFO(node);
52 gchar label_str[ITEM_LABEL_LENGTH];
53 gchar *label_ptr;
54 gboolean is_branch;
56 /* dissection with an invisible proto tree? */
57 g_assert(fi);
59 if (PROTO_ITEM_IS_HIDDEN(node) && !prefs.display_hidden_proto_items)
60 return;
62 // Fill in our label
63 /* was a free format label produced? */
64 if (fi->rep) {
65 label_ptr = fi->rep->representation;
67 else { /* no, make a generic label */
68 label_ptr = label_str;
69 proto_item_fill_label(fi, label_str);
72 if (node->first_child != NULL) {
73 is_branch = TRUE;
74 g_assert(fi->tree_type >= 0 && fi->tree_type < num_tree_types);
76 else {
77 is_branch = FALSE;
80 if (PROTO_ITEM_IS_GENERATED(node)) {
81 if (PROTO_ITEM_IS_HIDDEN(node)) {
82 label_ptr = g_strdup_printf("<[%s]>", label_ptr);
83 } else {
84 label_ptr = g_strdup_printf("[%s]", label_ptr);
86 } else if (PROTO_ITEM_IS_HIDDEN(node)) {
87 label_ptr = g_strdup_printf("<%s>", label_ptr);
90 QTreeWidgetItem *parentItem = (QTreeWidgetItem *)data;
91 QTreeWidgetItem *item;
92 ProtoTree *proto_tree = qobject_cast<ProtoTree *>(parentItem->treeWidget());
94 item = new QTreeWidgetItem(parentItem, 0);
96 // Set our colors.
97 QPalette pal = QApplication::palette();
98 if (fi && fi->hfinfo) {
99 if(fi->hfinfo->type == FT_PROTOCOL) {
100 item->setData(0, Qt::BackgroundRole, pal.alternateBase());
103 if((fi->hfinfo->type == FT_FRAMENUM) ||
104 (FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type))) {
105 QFont font = item->font(0);
107 item->setData(0, Qt::ForegroundRole, pal.link());
108 font.setUnderline(true);
109 item->setData(0, Qt::FontRole, font);
111 if (fi->hfinfo->type == FT_FRAMENUM) {
112 proto_tree->emitRelatedFrame(fi->value.value.uinteger);
117 // XXX - Add routines to get our severity colors.
118 if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
119 switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) {
120 case(PI_COMMENT):
121 item->setData(0, Qt::BackgroundRole, expert_color_comment);
122 break;
123 case(PI_CHAT):
124 item->setData(0, Qt::BackgroundRole, expert_color_chat);
125 break;
126 case(PI_NOTE):
127 item->setData(0, Qt::BackgroundRole, expert_color_note);
128 break;
129 case(PI_WARN):
130 item->setData(0, Qt::BackgroundRole, expert_color_warn);
131 break;
132 case(PI_ERROR):
133 item->setData(0, Qt::BackgroundRole, expert_color_error);
134 break;
135 default:
136 g_assert_not_reached();
138 item->setData(0, Qt::ForegroundRole, expert_color_foreground);
141 item->setText(0, label_ptr);
142 item->setData(0, Qt::UserRole, qVariantFromValue(fi));
144 if (PROTO_ITEM_IS_GENERATED(node) || PROTO_ITEM_IS_HIDDEN(node)) {
145 g_free(label_ptr);
148 if (is_branch) {
149 if (tree_expanded(fi->tree_type)) {
150 item->setExpanded(true);
151 } else {
152 item->setExpanded(false);
155 proto_tree_children_foreach(node, proto_tree_draw_node, item);
159 ProtoTree::ProtoTree(QWidget *parent) :
160 QTreeWidget(parent)
162 QMenu *submenu, *subsubmenu;
164 setAccessibleName(tr("Packet details"));
165 setUniformRowHeights(true);
167 // XXX We might want to reimplement setParent() and fill in the context
168 // menu there.
169 ctx_menu_.addAction(window()->findChild<QAction *>("actionViewExpandSubtrees"));
170 ctx_menu_.addAction(window()->findChild<QAction *>("actionViewExpandAll"));
171 ctx_menu_.addAction(window()->findChild<QAction *>("actionViewCollapseAll"));
172 ctx_menu_.addSeparator();
173 // " <menuitem name='ApplyasColumn' action='/Apply as Column'/>\n"
174 ctx_menu_.addSeparator();
175 submenu = new QMenu(tr("Apply as Filter"));
176 ctx_menu_.addMenu(submenu);
177 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFSelected"));
178 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFNotSelected"));
179 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndSelected"));
180 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrSelected"));
181 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndNotSelected"));
182 submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrNotSelected"));
183 submenu = new QMenu(tr("Prepare a Filter"));
184 ctx_menu_.addMenu(submenu);
185 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFSelected"));
186 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFNotSelected"));
187 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndSelected"));
188 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrSelected"));
189 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndNotSelected"));
190 submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrNotSelected"));
191 submenu = new QMenu(tr("Colorize with Filter"));
192 ctx_menu_.addMenu(submenu);
193 // " <menuitem name='Color1' action='/Colorize with Filter/Color 1'/>\n"
194 // " <menuitem name='Color2' action='/Colorize with Filter/Color 2'/>\n"
195 // " <menuitem name='Color3' action='/Colorize with Filter/Color 3'/>\n"
196 // " <menuitem name='Color4' action='/Colorize with Filter/Color 4'/>\n"
197 // " <menuitem name='Color5' action='/Colorize with Filter/Color 5'/>\n"
198 // " <menuitem name='Color6' action='/Colorize with Filter/Color 6'/>\n"
199 // " <menuitem name='Color7' action='/Colorize with Filter/Color 7'/>\n"
200 // " <menuitem name='Color8' action='/Colorize with Filter/Color 8'/>\n"
201 // " <menuitem name='Color9' action='/Colorize with Filter/Color 9'/>\n"
202 // " <menuitem name='Color10' action='/Colorize with Filter/Color 10'/>\n"
203 // " <menuitem name='NewColoringRule' action='/Colorize with Filter/New Coloring Rule'/>\n"
204 // " </menu>\n"
205 // " <menuitem name='FollowTCPStream' action='/Follow TCP Stream'/>\n"
206 // " <menuitem name='FollowUDPStream' action='/Follow UDP Stream'/>\n"
207 // " <menuitem name='FollowSSLStream' action='/Follow SSL Stream'/>\n"
208 ctx_menu_.addSeparator();
209 submenu = new QMenu(tr("Copy"));
210 ctx_menu_.addMenu(submenu);
211 submenu->addAction(window()->findChild<QAction *>("actionEditCopyDescription"));
212 submenu->addAction(window()->findChild<QAction *>("actionEditCopyFieldName"));
213 submenu->addAction(window()->findChild<QAction *>("actionEditCopyValue"));
214 submenu->addSeparator();
215 submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
216 subsubmenu = new QMenu(tr("Bytes"));
217 submenu->addMenu(subsubmenu);
218 subsubmenu->addSeparator();
219 // " <menu name= 'Bytes' action='/Copy/Bytes'>\n"
220 // " <menuitem name='OffsetHexText' action='/Copy/Bytes/OffsetHexText'/>\n"
221 // " <menuitem name='OffsetHex' action='/Copy/Bytes/OffsetHex'/>\n"
222 // " <menuitem name='PrintableTextOnly' action='/Copy/Bytes/PrintableTextOnly'/>\n"
223 // " <separator/>\n"
224 // " <menuitem name='HexStream' action='/Copy/Bytes/HexStream'/>\n"
225 // " <menuitem name='BinaryStream' action='/Copy/Bytes/BinaryStream'/>\n"
226 // " </menu>\n"
227 // " </menu>\n"
228 // " <menuitem name='ExportSelectedPacketBytes' action='/ExportSelectedPacketBytes'/>\n"
229 ctx_menu_.addSeparator();
230 // " <menuitem name='WikiProtocolPage' action='/WikiProtocolPage'/>\n"
231 // " <menuitem name='FilterFieldReference' action='/FilterFieldReference'/>\n"
232 // " <menuitem name='ProtocolHelp' action='/ProtocolHelp'/>\n"
233 // " <menuitem name='ProtocolPreferences' action='/ProtocolPreferences'/>\n"
234 ctx_menu_.addSeparator();
235 // " <menuitem name='DecodeAs' action='/DecodeAs'/>\n"
236 // " <menuitem name='DisableProtocol' action='/DisableProtocol'/>\n"
237 // " <menuitem name='ResolveName' action='/ResolveName'/>\n"
238 // " <menuitem name='GotoCorrespondingPacket' action='/GotoCorrespondingPacket'/>\n"
240 connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
241 this, SLOT(updateSelectionStatus(QTreeWidgetItem*)));
242 connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(expand(QModelIndex)));
243 connect(this, SIGNAL(collapsed(QModelIndex)), this, SLOT(collapse(QModelIndex)));
244 connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
245 this, SLOT(itemDoubleClick(QTreeWidgetItem*, int)));
248 void ProtoTree::clear() {
249 updateSelectionStatus(NULL);
250 QTreeWidget::clear();
253 void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
255 ctx_menu_.exec(event->globalPos());
258 void ProtoTree::fillProtocolTree(proto_tree *protocol_tree) {
259 clear();
260 setFont(wsApp->monospaceFont());
262 proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, invisibleRootItem());
265 void ProtoTree::emitRelatedFrame(int related_frame)
267 emit relatedFrame(related_frame);
270 void ProtoTree::updateSelectionStatus(QTreeWidgetItem* item) {
272 if (item) {
273 field_info *fi;
274 QString item_info;
276 fi = item->data(0, Qt::UserRole).value<field_info *>();
277 if (!fi || !fi->hfinfo) return;
279 if (fi->hfinfo->blurb != NULL && fi->hfinfo->blurb[0] != '\0') {
280 item_info.append(QString().fromUtf8(fi->hfinfo->blurb));
281 } else {
282 item_info.append(QString().fromUtf8(fi->hfinfo->name));
285 if (!item_info.isEmpty()) {
286 int finfo_length;
287 item_info.append(" (" + QString().fromUtf8(fi->hfinfo->abbrev) + ")");
289 finfo_length = fi->length + fi->appendix_length;
290 if (finfo_length == 1) {
291 item_info.append(tr(", 1 byte"));
292 } else if (finfo_length > 1) {
293 item_info.append(QString(tr(", %1 bytes")).arg(finfo_length));
296 emit protoItemSelected(*new QString());
297 emit protoItemSelected(NULL);
298 emit protoItemSelected(item_info);
299 emit protoItemSelected(fi);
300 } // else the GTK+ version pushes an empty string as described below.
302 * Don't show anything if the field name is zero-length;
303 * the pseudo-field for "proto_tree_add_text()" is such
304 * a field, and we don't want "Text (text)" showing up
305 * on the status line if you've selected such a field.
307 * XXX - there are zero-length fields for which we *do*
308 * want to show the field name.
310 * XXX - perhaps the name and abbrev field should be null
311 * pointers rather than null strings for that pseudo-field,
312 * but we'd have to add checks for null pointers in some
313 * places if we did that.
315 * Or perhaps protocol tree items added with
316 * "proto_tree_add_text()" should have -1 as the field index,
317 * with no pseudo-field being used, but that might also
318 * require special checks for -1 to be added.
321 } else {
322 emit protoItemSelected(*new QString());
323 emit protoItemSelected(NULL);
327 void ProtoTree::expand(const QModelIndex & index) {
328 field_info *fi;
330 fi = index.data(Qt::UserRole).value<field_info *>();
331 g_assert(fi);
333 if(prefs.gui_auto_scroll_on_expand) {
334 ScrollHint scroll_hint = PositionAtTop;
335 if (prefs.gui_auto_scroll_percentage > 66) {
336 scroll_hint = PositionAtBottom;
337 } else if (prefs.gui_auto_scroll_percentage >= 33) {
338 scroll_hint = PositionAtCenter;
340 scrollTo(index, scroll_hint);
344 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
345 * are thus presumably leaf nodes and cannot be expanded.
347 if (fi->tree_type != -1) {
348 g_assert(fi->tree_type >= 0 &&
349 fi->tree_type < num_tree_types);
350 tree_expanded_set(fi->tree_type, TRUE);
354 void ProtoTree::collapse(const QModelIndex & index) {
355 field_info *fi;
357 fi = index.data(Qt::UserRole).value<field_info *>();
358 g_assert(fi);
361 * Nodes with "finfo->tree_type" of -1 have no ett_ value, and
362 * are thus presumably leaf nodes and cannot be collapsed.
364 if (fi->tree_type != -1) {
365 g_assert(fi->tree_type >= 0 &&
366 fi->tree_type < num_tree_types);
367 tree_expanded_set(fi->tree_type, FALSE);
371 void ProtoTree::expandSubtrees()
373 QTreeWidgetItem *top_sel;
375 if (selectedItems().length() < 1) {
376 return;
379 top_sel = selectedItems()[0];
381 if (!top_sel) {
382 return;
385 while (top_sel->parent()) {
386 top_sel = top_sel->parent();
389 QTreeWidgetItemIterator iter(top_sel);
390 while (*iter) {
391 if ((*iter) != top_sel && (*iter)->parent() == NULL) {
392 // We found the next top-level item
393 break;
395 (*iter)->setExpanded(true);
396 iter++;
400 void ProtoTree::expandAll()
402 int i;
403 for(i=0; i < num_tree_types; i++) {
404 tree_expanded_set(i, TRUE);
406 QTreeWidget::expandAll();
409 void ProtoTree::collapseAll()
411 int i;
412 for(i=0; i < num_tree_types; i++) {
413 tree_expanded_set(i, FALSE);
415 QTreeWidget::collapseAll();
418 void ProtoTree::itemDoubleClick(QTreeWidgetItem *item, int column) {
419 Q_UNUSED(column);
421 field_info *fi;
423 fi = item->data(0, Qt::UserRole).value<field_info *>();
425 if(fi->hfinfo->type == FT_FRAMENUM) {
426 emit goToFrame(fi->value.value.uinteger);
429 if(FI_GET_FLAG(fi, FI_URL) && IS_FT_STRING(fi->hfinfo->type)) {
430 gchar *url;
431 url = fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, NULL);
432 if(url){
433 // browser_open_url(url);
434 QDesktopServices::openUrl(QUrl(url));
435 g_free(url);
441 * Editor modelines
443 * Local Variables:
444 * c-basic-offset: 4
445 * tab-width: 8
446 * indent-tabs-mode: nil
447 * End:
449 * ex: set shiftwidth=4 tabstop=8 expandtab:
450 * :indentSize=4:tabSize=8:noTabs=true: