From bc957229f87bff3567fafbe2718c1e138905ce9a Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Sat, 14 Jan 2012 00:16:16 +0000 Subject: [PATCH] Initial status bar functionality. Promote the main window's status bar to a MainStatusBar. Add a "LabelStack" widget, which MainStatusBar uses to duplicate features in GtkStatusbar. Make the protocol tree a full-blown ProtoTree widget. Move main_cf_callback from main to WiresharkApplication. Duplicate a lot of the cf callbacks as signals and slots. Use Q_UNUSED in a few places. svn path=/trunk/; revision=40488 --- ui/qt/QtShark.pro | 2 + ui/qt/display_filter_edit.cpp | 33 +++--- ui/qt/display_filter_edit.h | 3 + ui/qt/label_stack.cpp | 103 +++++++++++++++++++ ui/qt/label_stack.h | 58 +++++++++++ ui/qt/main.cpp | 48 +-------- ui/qt/main_status_bar.cpp | 173 ++++++++++++++++++++++++-------- ui/qt/main_status_bar.h | 28 +++++- ui/qt/main_window.cpp | 113 +++++++++++++++++---- ui/qt/main_window.h | 11 ++ ui/qt/main_window.ui | 9 +- ui/qt/packet_list.cpp | 18 ++-- ui/qt/packet_list.h | 5 +- ui/qt/proto_tree.cpp | 85 ++++++++++++++-- ui/qt/proto_tree.h | 8 +- ui/qt/wireshark_application.cpp | 51 ++++++++++ ui/qt/wireshark_application.h | 12 +++ 17 files changed, 607 insertions(+), 153 deletions(-) create mode 100644 ui/qt/label_stack.cpp create mode 100644 ui/qt/label_stack.h diff --git a/ui/qt/QtShark.pro b/ui/qt/QtShark.pro index cb5443ee14..2f91b73b22 100644 --- a/ui/qt/QtShark.pro +++ b/ui/qt/QtShark.pro @@ -105,6 +105,7 @@ SOURCES += \ recent_file_status.cpp \ simple_dialog_qt.cpp \ wireshark_application.cpp \ + label_stack.cpp unix:SOURCES += ../../capture-pcap-util-unix.c @@ -137,6 +138,7 @@ HEADERS += \ recent_file_status.h \ simple_dialog_qt.h \ wireshark_application.h \ + label_stack.h FORMS += main_window.ui diff --git a/ui/qt/display_filter_edit.cpp b/ui/qt/display_filter_edit.cpp index ab76014124..84a1b55a48 100644 --- a/ui/qt/display_filter_edit.cpp +++ b/ui/qt/display_filter_edit.cpp @@ -254,11 +254,11 @@ void DisplayFilterEdit::checkFilter(const QString& text) clearButton->setVisible(!text.isEmpty()); + popFilterSyntaxStatus(); + if (fieldNameOnly && (c = proto_check_field_name(text.toUtf8().constData()))) { m_syntaxState = Invalid; -// if (use_statusbar) { -// statusbar_push_filter_msg(" Illegal character in field name: '%c'", c); -// } + emit pushFilterSyntaxStatus(QString().sprintf("Illegal character in field name: '%c'", c)); } else if (dfilter_compile(text.toUtf8().constData(), &dfp)) { if (dfp != NULL) { depr = dfilter_deprecated_tokens(dfp); @@ -268,30 +268,25 @@ void DisplayFilterEdit::checkFilter(const QString& text) } else if (depr) { /* You keep using that word. I do not think it means what you think it means. */ m_syntaxState = Deprecated; -// if (use_statusbar) { -// /* -// * We're being lazy and only printing the first "problem" token. -// * Would it be better to print all of them? -// */ -// statusbar_push_temporary_msg(" \"%s\" may have unexpected results (see the User's Guide)", -// (const char *) g_ptr_array_index(depr, 0)); -// } + /* + * We're being lazy and only printing the first "problem" token. + * Would it be better to print all of them? + */ + emit pushFilterSyntaxWarning(QString().sprintf("\"%s\" may have unexpected results (see the User's Guide)", + (const char *) g_ptr_array_index(depr, 0))); } else { m_syntaxState = Valid; } dfilter_free(dfp); } else { m_syntaxState = Invalid; -// if (use_statusbar) { -// if (dfilter_error_msg) { -// statusbar_push_filter_msg(" Invalid filter: %s", dfilter_error_msg); -// } else { -// statusbar_push_filter_msg(" Invalid filter"); -// } -// } + QString invalidMsg("Invalid filter"); + if (dfilter_error_msg) { + invalidMsg.append(QString().sprintf(": %s", dfilter_error_msg)); + } + emit pushFilterSyntaxStatus(invalidMsg); } - g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: show display filter syntax status in statusbar"); setStyleSheet(syntaxStyleSheet); applyButton->setEnabled(m_syntaxState == Empty || m_syntaxState == Valid); diff --git a/ui/qt/display_filter_edit.h b/ui/qt/display_filter_edit.h index 2d8bffd81d..721a10e193 100644 --- a/ui/qt/display_filter_edit.h +++ b/ui/qt/display_filter_edit.h @@ -59,6 +59,9 @@ private: QToolButton *applyButton; signals: + void pushFilterSyntaxStatus(QString&); + void popFilterSyntaxStatus(); + void pushFilterSyntaxWarning(QString&); public slots: diff --git a/ui/qt/label_stack.cpp b/ui/qt/label_stack.cpp new file mode 100644 index 0000000000..82a7885fbe --- /dev/null +++ b/ui/qt/label_stack.cpp @@ -0,0 +1,103 @@ +/* label_stack.cpp + * + * $Id: mainStatus_bar.cpp 40378 2012-01-04 22:13:01Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "label_stack.h" + +#include + +/* Temporary message timeouts */ +#define TEMPORARY_MSG_TIMEOUT (7 * 1000) +//#define TEMPORARY_FLASH_TIMEOUT (1 * 1000) +//#define TEMPORARY_FLASH_INTERVAL (TEMPORARY_FLASH_TIMEOUT / 4) + +LabelStack::LabelStack(QWidget *parent) : + QLabel(parent) +{ + m_temporaryCtx = -1; + fillLabel(); +} + +void LabelStack::setTemporaryContext(int ctx) { + m_temporaryCtx = ctx; +} + +void LabelStack::fillLabel() { + StackItem *si; + + setStyleSheet( + "QLabel {" + " margin-left: 0.5em;" + "}" + ); + + if (m_labels.isEmpty()) { + clear(); + return; + } + + si = m_labels.first(); + + if (si->ctx == m_temporaryCtx) { + setStyleSheet( + // Tango "Scarlet Red" + "QLabel {" + " margin-left: 0.5em;" + " border-radius: 3px;" + " color: white;" + " background-color: rgba(239, 41, 41, 128);" + "}" + ); + } + + setText(si->text); +} + +void LabelStack::pushText(QString &text, int ctx) { + StackItem *si = new StackItem; + si->text = text; + si->ctx = ctx; + m_labels.prepend(si); + + if (ctx == m_temporaryCtx) { + QTimer::singleShot(TEMPORARY_MSG_TIMEOUT, this, SLOT(popTemporaryText())); + } + + fillLabel(); +} + +void LabelStack::popText(int ctx) { + QMutableListIterator iter(m_labels); + + while (iter.hasNext()) { + if (iter.next()->ctx == ctx) { + iter.remove(); + break; + } + } + + fillLabel(); +} + +void LabelStack::popTemporaryText() { + popText(m_temporaryCtx); +} diff --git a/ui/qt/label_stack.h b/ui/qt/label_stack.h new file mode 100644 index 0000000000..60272f7ade --- /dev/null +++ b/ui/qt/label_stack.h @@ -0,0 +1,58 @@ +/* label_stack.h + * + * $Id: mainStatus_bar.cpp 40378 2012-01-04 22:13:01Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef LABEL_STACK_H +#define LABEL_STACK_H + +#include +#include + +class LabelStack : public QLabel +{ + Q_OBJECT +public: + explicit LabelStack(QWidget *parent = 0); + void setTemporaryContext(int ctx); + void pushText(QString &text, int ctx); + +private: + typedef struct _StackItem { + QString text; + int ctx; + } StackItem; + + int m_temporaryCtx; + QList m_labels; + + void fillLabel(); + +signals: + +public slots: + void popText(int ctx); + +private slots: + void popTemporaryText(); +}; + +#endif // LABEL_STACK_H diff --git a/ui/qt/main.cpp b/ui/qt/main.cpp index bcdbcc2808..60447be151 100644 --- a/ui/qt/main.cpp +++ b/ui/qt/main.cpp @@ -173,52 +173,10 @@ void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, } static void -main_cf_callback(gint event, gpointer data, gpointer user_data _U_) +main_cf_callback(gint event, gpointer data, gpointer user_data ) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: main_cf_callback %d %p", event, data); -// switch(event) { -// case(cf_cb_file_closing): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing"); -// main_cf_cb_file_closing(data); -// break; -// case(cf_cb_file_closed): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed"); -// main_cf_cb_file_closed(data); -// break; -// case(cf_cb_file_read_started): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read started"); -// main_cf_cb_file_read_started(data); -// break; -// case(cf_cb_file_read_finished): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished"); -// main_cf_cb_file_read_finished(data); -// break; -// case(cf_cb_packet_selected): -// main_cf_cb_packet_selected(data); -// break; -// case(cf_cb_packet_unselected): -// main_cf_cb_packet_unselected(data); -// break; -// case(cf_cb_field_unselected): -// main_cf_cb_field_unselected(data); -// break; -// case(cf_cb_file_save_started): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save started"); -// break; -// case(cf_cb_file_save_finished): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save finished"); -// break; -// case(cf_cb_file_save_reload_finished): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Reload finished"); -// main_cf_cb_file_save_reload_finished(data); -// break; -// case(cf_cb_file_save_failed): -// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save failed"); -// break; -// default: -// g_warning("main_cf_callback: event %u unknown", event); -// g_assert_not_reached(); -// } + Q_UNUSED(user_data); + wsApp->captureFileCallback(event, data); } // XXX Copied from gtk/main.c. This should be moved to a common location. diff --git a/ui/qt/main_status_bar.cpp b/ui/qt/main_status_bar.cpp index 4266fb4660..656492134c 100644 --- a/ui/qt/main_status_bar.cpp +++ b/ui/qt/main_status_bar.cpp @@ -29,12 +29,32 @@ #include "main_status_bar.h" -#include "main_statusbar.h" +#include "wireshark_application.h" -/* Temporary message timeouts */ -#define TEMPORARY_MSG_TIMEOUT (7 * 1000) -#define TEMPORARY_FLASH_TIMEOUT (1 * 1000) -#define TEMPORARY_FLASH_INTERVAL (TEMPORARY_FLASH_TIMEOUT / 4) +#include "main_statusbar.h" +#include "globals.h" + +#include + +#ifdef HAVE_LIBPCAP +#define DEF_READY_MESSAGE " Ready to load or capture" +#else +#define DEF_READY_MESSAGE " Ready to load file" +#endif + +// XXX - The GTK+ code assigns priorities to these and pushes/pops accordingly. + +enum StatusContext { + STATUS_CTX_MAIN, + STATUS_CTX_FILE, + STATUS_CTX_FIELD, + STATUS_CTX_FILTER, + STATUS_CTX_TEMPORARY +}; + +// If we ever add support for multiple windows this will need to be replaced. +// See also: main_window.cpp +static MainStatusBar *cur_main_status_bar = NULL; /* * Push a formatted temporary message onto the statusbar. @@ -44,21 +64,18 @@ statusbar_push_temporary_msg(const gchar *msg_format, ...) { va_list ap; gchar *msg; - guint msg_id; + QString pushMsg; + + if (!cur_main_status_bar) return; va_start(ap, msg_format); msg = g_strdup_vprintf(msg_format, ap); va_end(ap); - g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: statusbar_push_temporary_msg: %s", msg); - -// msg_id = gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, msg); + pushMsg.fromUtf8(msg); g_free(msg); -// flash_time = TEMPORARY_FLASH_TIMEOUT - 1; -// g_timeout_add(TEMPORARY_FLASH_INTERVAL, statusbar_flash_temporary_msg, NULL); - -// g_timeout_add(TEMPORARY_MSG_TIMEOUT, statusbar_remove_temporary_msg, GUINT_TO_POINTER(msg_id)); + cur_main_status_bar->pushTemporaryStatus(pushMsg); } /* @@ -67,41 +84,109 @@ statusbar_push_temporary_msg(const gchar *msg_format, ...) void packets_bar_update(void) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: packets_bar_update"); -// if(packets_bar) { -// /* Remove old status */ -// if(packets_str) { -// gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx); -// } else { -// packets_str = g_string_new (""); -// } + QString packetsStr = QString(""); -// /* Do we have any packets? */ -// if(cfile.count) { -// g_string_printf(packets_str, " Packets: %u Displayed: %u Marked: %u", -// cfile.count, cfile.displayed_count, cfile.marked_count); -// if(cfile.drops_known) { -// g_string_append_printf(packets_str, " Dropped: %u", cfile.drops); -// } -// if(cfile.ignored_count > 0) { -// g_string_append_printf(packets_str, " Ignored: %u", cfile.ignored_count); -// } -// if(!cfile.is_tempfile){ -// /* Loading an existing file */ -// gulong computed_elapsed = cf_get_computed_elapsed(); -// g_string_append_printf(packets_str, " Load time: %lu:%02lu.%03lu", -// computed_elapsed/60000, -// computed_elapsed%60000/1000, -// computed_elapsed%1000); -// } -// } else { -// g_string_printf(packets_str, " No Packets"); -// } -// gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str->str); -// } + if (!cur_main_status_bar) return; + + cur_main_status_bar->popPacketStatus(); + + /* Do we have any packets? */ + if (cfile.count) { + packetsStr.append(QString("Packets: %1 Displayed: %2 Marked: %3") + .arg(cfile.count) + .arg(cfile.displayed_count) + .arg(cfile.marked_count)); + if(cfile.drops_known) { + packetsStr.append(QString(" Dropped: %1").arg(cfile.drops)); + } + if(cfile.ignored_count > 0) { + packetsStr.append(QString(" Ignored: %1").arg(cfile.ignored_count)); + } + if(!cfile.is_tempfile) { + /* Loading an existing file */ + gulong computed_elapsed = cf_get_computed_elapsed(); + packetsStr.append(QString().sprintf(" Load time: %lu:%02lu.%03lu", + computed_elapsed/60000, + computed_elapsed%60000/1000, + computed_elapsed%1000)); + } + } else { + packetsStr.append("No Packets"); + } + + cur_main_status_bar->pushPacketStatus(packetsStr); } MainStatusBar::MainStatusBar(QWidget *parent) : QStatusBar(parent) { + QSplitter *splitter = new QSplitter(this); + QString readyMsg(DEF_READY_MESSAGE); + + // XXX - Add the expert level icon + + m_infoStatus.setTemporaryContext(STATUS_CTX_TEMPORARY); + splitter->addWidget(&m_infoStatus); + splitter->addWidget(&m_packetStatus); + splitter->addWidget(&m_profileStatus); + + splitter->setStretchFactor(0, 3); + splitter->setStretchFactor(1, 3); + splitter->setStretchFactor(2, 0); + + addWidget(splitter, 1); + + cur_main_status_bar = this; + + m_infoStatus.pushText(readyMsg, STATUS_CTX_MAIN); + packets_bar_update(); } + +void MainStatusBar::pushTemporaryStatus(QString &message) { + m_infoStatus.pushText(message, STATUS_CTX_TEMPORARY); +} + +void MainStatusBar::popTemporaryStatus() { + m_infoStatus.popText(STATUS_CTX_TEMPORARY); +} + +void MainStatusBar::pushFileStatus(QString &message) { + m_infoStatus.pushText(message, STATUS_CTX_FILE); +} + +void MainStatusBar::popFileStatus() { + m_infoStatus.popText(STATUS_CTX_FILE); +} + +void MainStatusBar::pushFieldStatus(QString &message) { + m_infoStatus.pushText(message, STATUS_CTX_FIELD); +} + +void MainStatusBar::popFieldStatus() { + m_infoStatus.popText(STATUS_CTX_FIELD); +} + +void MainStatusBar::pushFilterStatus(QString &message) { + m_infoStatus.pushText(message, STATUS_CTX_FILTER); +} + +void MainStatusBar::popFilterStatus() { + m_infoStatus.popText(STATUS_CTX_FILTER); +} + +void MainStatusBar::pushPacketStatus(QString &message) { + m_packetStatus.pushText(message, STATUS_CTX_MAIN); +} + +void MainStatusBar::popPacketStatus() { + m_packetStatus.popText(STATUS_CTX_MAIN); +} + +void MainStatusBar::pushProfileStatus(QString &message) { + m_profileStatus.pushText(message, STATUS_CTX_MAIN); +} + +void MainStatusBar::popProfileStatus() { + m_profileStatus.popText(STATUS_CTX_MAIN); +} + diff --git a/ui/qt/main_status_bar.h b/ui/qt/main_status_bar.h index a4e5c074d2..3139de7392 100644 --- a/ui/qt/main_status_bar.h +++ b/ui/qt/main_status_bar.h @@ -1,4 +1,4 @@ -/* main_status_bar.h +/* mainStatus_bar.h * * $Id$ * @@ -21,8 +21,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef MAIN_STATUS_BAR_H -#define MAIN_STATUS_BAR_H +#ifndef MAINStatus_BAR_H +#define MAINStatus_BAR_H + +#include "label_stack.h" #include @@ -32,10 +34,26 @@ class MainStatusBar : public QStatusBar public: explicit MainStatusBar(QWidget *parent = 0); +private: + LabelStack m_infoStatus; + LabelStack m_packetStatus; + LabelStack m_profileStatus; + signals: public slots: - + void pushTemporaryStatus(QString &message); + void popTemporaryStatus(); + void pushFileStatus(QString &message); + void popFileStatus(); + void pushFieldStatus(QString &message); + void popFieldStatus(); + void pushFilterStatus(QString &message); + void popFilterStatus(); + void pushPacketStatus(QString &message); + void popPacketStatus(); + void pushProfileStatus(QString &message); + void popProfileStatus(); }; -#endif // MAIN_STATUS_BAR_H +#endif // MAINStatus_BAR_H diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index ecf83f096a..db15c0a65e 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -24,16 +24,19 @@ #include "main_window.h" #include "ui_main_window.h" -#include "config.h" - -#include +#include "globals.h" +#include #include +#include "main_statusbar.h" + #include "wireshark_application.h" #include "packet_list.h" +#include "proto_tree.h" #include "byte_view_tab.h" #include "capture_file_dialog.h" +#include "display_filter_edit.h" #include "qt_ui_utils.h" @@ -43,8 +46,6 @@ #include #include -#include "globals.h" - //menu_recent_file_write_all // If we ever add support for multiple windows this will need to be replaced. @@ -54,6 +55,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { + capFile = NULL; cur_main_window = this; ui->setupUi(this); @@ -61,6 +63,10 @@ MainWindow::MainWindow(QWidget *parent) : updateRecentFiles(); dfComboBox = new DisplayFilterCombo(); + const DisplayFilterEdit *dfEdit = dynamic_cast(dfComboBox->lineEdit()); + connect(dfEdit, SIGNAL(pushFilterSyntaxStatus(QString&)), ui->statusBar, SLOT(pushFilterStatus(QString&))); + connect(dfEdit, SIGNAL(popFilterSyntaxStatus()), ui->statusBar, SLOT(popFilterStatus())); + connect(dfEdit, SIGNAL(pushFilterSyntaxWarning(QString&)), ui->statusBar, SLOT(pushTemporaryStatus(QString&))); #ifdef _WIN32 // Qt <= 4.7 doesn't seem to style Windows toolbars. If we wanted to be really fancy we could use Blur Behind: @@ -79,7 +85,7 @@ MainWindow::MainWindow(QWidget *parent) : PacketList *packetList = new PacketList(splitterV); - QTreeWidget *protoTree = new QTreeWidget(splitterV); + ProtoTree *protoTree = new ProtoTree(splitterV); protoTree->setHeaderHidden(true); ByteViewTab *byteViewTab = new ByteViewTab(splitterV); @@ -97,7 +103,22 @@ MainWindow::MainWindow(QWidget *parent) : mainWelcome = new MainWelcome(ui->mainStack); ui->mainStack->addWidget(mainWelcome); - connect(mainWelcome, SIGNAL(recentFileActivated(QString&)), this, SLOT(openCaptureFile(QString&))); + connect(mainWelcome, SIGNAL(recentFileActivated(QString&)), + this, SLOT(openCaptureFile(QString&))); + + connect(wsApp, SIGNAL(captureFileReadStarted(const capture_file*)), + this, SLOT(captureFileReadStarted(const capture_file*))); + connect(wsApp, SIGNAL(captureFileReadFinished(const capture_file*)), + this, SLOT(captureFileReadFinished(const capture_file*))); + connect(wsApp, SIGNAL(captureFileClosing(const capture_file*)), + this, SLOT(captureFileClosing(const capture_file*))); + connect(wsApp, SIGNAL(captureFileClosed(const capture_file*)), + this, SLOT(captureFileClosed(const capture_file*))); + + connect(protoTree, SIGNAL(protoItemSelected(QString&)), + ui->statusBar, SLOT(pushFieldStatus(QString&))); + connect(protoTree, SIGNAL(protoItemUnselected()), + ui->statusBar, SLOT(popFieldStatus())); ui->mainStack->setCurrentWidget(mainWelcome); } @@ -107,6 +128,72 @@ MainWindow::~MainWindow() delete ui; } +void MainWindow::keyPressEvent(QKeyEvent *event) { + + if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) { + dfComboBox->setFocus(Qt::ShortcutFocusReason); + return; + } + + QMainWindow::keyPressEvent(event); +} + +void MainWindow::captureFileReadStarted(const capture_file *cf) { + if (cf != capFile) return; +// tap_param_dlg_update(); + + /* Set up main window for a capture file. */ +// main_set_for_capture_file(TRUE); + + ui->statusBar->popFileStatus(); + QString msg = QString().sprintf("Loading: %s", get_basename(cf->filename)); + ui->statusBar->pushFileStatus(msg); +} + +void MainWindow::captureFileReadFinished(const capture_file *cf) { + if (cf != capFile) return; + +// gchar *dir_path; + +// if (!cf->is_tempfile && cf->filename) { +// /* Add this filename to the list of recent files in the "Recent Files" submenu */ +// add_menu_recent_capture_file(cf->filename); + +// /* Remember folder for next Open dialog and save it in recent */ +// dir_path = get_dirname(g_strdup(cf->filename)); +// set_last_open_dir(dir_path); +// g_free(dir_path); +// } +// set_display_filename(cf); + +// /* Enable menu items that make sense if you have a capture file you've +// finished reading. */ +// set_menus_for_capture_file(cf); + +// /* Enable menu items that make sense if you have some captured packets. */ +// set_menus_for_captured_packets(TRUE); + + ui->statusBar->popFileStatus(); + QString msg = QString().sprintf("%s", get_basename(cf->filename)); + ui->statusBar->pushFileStatus(msg); +} + +void MainWindow::captureFileClosing(const capture_file *cf) { + if (cf != capFile) return; + + /* reset expert info indicator */ +// status_expert_hide(); +// gtk_widget_show(expert_info_none); +} + +void MainWindow::captureFileClosed(const capture_file *cf) { + if (cf != capFile) return; + packets_bar_update(); + + ui->statusBar->popFileStatus(); + capFile = NULL; +} + void MainWindow::closeCaptureFile() { cf_close(&cfile); ui->mainStack->setCurrentWidget(mainWelcome); @@ -144,9 +231,11 @@ void MainWindow::openCaptureFile(QString &cfPath) try again. */ if (rfcode != NULL) dfilter_free(rfcode); + capFile = NULL; return; } else { ui->mainStack->setCurrentWidget(splitterV); + capFile = &cfile; cf_read(&cfile, FALSE); } } @@ -217,13 +306,3 @@ void MainWindow::updateRecentFiles() { } } } - -void MainWindow::keyPressEvent(QKeyEvent *event) { - - if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) { - dfComboBox->setFocus(Qt::ShortcutFocusReason); - return; - } - - QMainWindow::keyPressEvent(event); -} diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 98c1950ac2..a43d46dee5 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -26,6 +26,12 @@ #include +#include "config.h" + +#include + +#include "file.h" + #include #include #include "main_welcome.h" @@ -54,8 +60,13 @@ private: QSplitter *splitterV; MainWelcome *mainWelcome; DisplayFilterCombo *dfComboBox; + capture_file *capFile; public slots: + void captureFileReadStarted(const capture_file *cf); + void captureFileReadFinished(const capture_file *cf); + void captureFileClosing(const capture_file *cf); + void captureFileClosed(const capture_file *cf); private slots: void closeCaptureFile(); diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index 6ab73243b4..5043b12560 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -115,7 +115,7 @@ - + toolBar @@ -197,6 +197,13 @@ + + + MainStatusBar + QStatusBar +
main_status_bar.h
+
+
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp index 0b8e0844b2..a00bbc63b8 100644 --- a/ui/qt/packet_list.cpp +++ b/ui/qt/packet_list.cpp @@ -41,6 +41,7 @@ #include "ui_util.h" #include "globals.h" #include "qt_ui_utils.h" +#include "main_statusbar.h" #include "gtk/recent.h" @@ -56,8 +57,11 @@ static gboolean enable_color; static PacketList *cur_packet_list = NULL; guint -new_packet_list_append(column_info *cinfo _U_, frame_data *fdata, packet_info *pinfo _U_) +new_packet_list_append(column_info *cinfo, frame_data *fdata, packet_info *pinfo) { + Q_UNUSED(cinfo); + Q_UNUSED(pinfo); + if (!cur_packet_list) return 0; @@ -200,7 +204,7 @@ new_packet_list_thaw(void) // /* Remove extra reference added by new_packet_list_freeze() */ // g_object_unref(packetlist); -// packets_bar_update(); + packets_bar_update(); } void @@ -288,7 +292,7 @@ PacketList::PacketList(QWidget *parent) : m_byteViewTab = NULL; } -void PacketList::setProtoTree (QTreeWidget *protoTree) { +void PacketList::setProtoTree (ProtoTree *protoTree) { m_protoTree = protoTree; } @@ -301,6 +305,7 @@ PacketListModel *PacketList::packetListModel() const { } void PacketList::showEvent (QShowEvent *event) { + Q_UNUSED(event); // g_log(NULL, G_LOG_LEVEL_DEBUG, "cols: %d", cfile.cinfo.num_cols); for (int i = 0; i < cfile.cinfo.num_cols; i++) { int fmt, col_width; @@ -321,8 +326,6 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS QTreeView::selectionChanged(selected, deselected); if (m_protoTree) { - // Connect signals between the proto tree and byte views. - int row = selected.first().top(); cf_select_packet(&cfile, row); @@ -330,10 +333,9 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS return; } - proto_tree_draw(cfile.edt->tree, m_protoTree); + m_protoTree->fillProtocolTree(cfile.edt->tree); } - g_log(NULL, G_LOG_LEVEL_DEBUG, "bvt: %p", m_byteViewTab); if (m_byteViewTab && cfile.edt) { GSList *src_le; data_source *source; @@ -350,6 +352,7 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS } if (m_protoTree && m_byteViewTab) { + // Connect signals between the proto tree and byte views. connect(m_protoTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), m_byteViewTab, SLOT(protoTreeItemChanged(QTreeWidgetItem*))); } @@ -369,7 +372,6 @@ void PacketList::clear() { // * Reset the sort column, use packetlist as model in case the list is frozen. // */ cur_packet_list->sortByColumn(0, Qt::AscendingOrder); - } void new_packet_list_recent_write_all(FILE *rf) { diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h index 5f78a86a8f..5bd6e5fd74 100644 --- a/ui/qt/packet_list.h +++ b/ui/qt/packet_list.h @@ -25,6 +25,7 @@ #define PACKET_LIST_H #include "packet_list_model.h" +#include "proto_tree.h" #include "byte_view_tab.h" #include @@ -37,7 +38,7 @@ class PacketList : public QTreeView public: explicit PacketList(QWidget *parent = 0); PacketListModel *packetListModel() const; - void setProtoTree(QTreeWidget *protoTree); + void setProtoTree(ProtoTree *protoTree); void setByteViewTab(ByteViewTab *byteViewTab); void clear(); void writeRecent(FILE *rf); @@ -48,7 +49,7 @@ protected: private: PacketListModel *m_packet_list_model; - QTreeWidget *m_protoTree; + ProtoTree *m_protoTree; ByteViewTab *m_byteViewTab; signals: diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp index 74cedbeaac..4d7b5d424e 100644 --- a/ui/qt/proto_tree.cpp +++ b/ui/qt/proto_tree.cpp @@ -21,6 +21,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "proto_tree.h" #include "monospace_font.h" @@ -36,17 +38,6 @@ QColor expert_color_error ( 0xff, 0x5c, 0x5c ); /* pale red * QColor expert_color_foreground ( 0x00, 0x00, 0x00 ); /* black */ QColor hidden_proto_item ( 0x44, 0x44, 0x44 ); /* gray */ -static void -proto_tree_draw_node(proto_node *node, gpointer data); - -void proto_tree_draw(proto_tree *protocol_tree, QTreeWidget *protoTree) { - // Clear out previous tree - protoTree->clear(); - protoTree->setFont(get_monospace_font()); - - proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, protoTree->invisibleRootItem()); -} - /* 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) @@ -152,4 +143,76 @@ ProtoTree::ProtoTree(QWidget *parent) : QTreeWidget(parent) { setAccessibleName("Packet details"); + setFont(get_monospace_font()); + + connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(updateSelectionStatus(QTreeWidgetItem*))); +} + +void ProtoTree::clear() { + updateSelectionStatus(NULL); + QTreeWidget::clear(); +} + +void ProtoTree::fillProtocolTree(proto_tree *protocol_tree) { + // Clear out previous tree + clear(); + + proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, invisibleRootItem()); +} + +void ProtoTree::updateSelectionStatus(QTreeWidgetItem* item) { + + if (item) { + field_info *fi; + QVariant v; + QString itemInfo; + int finfo_length; + + v = item->data(0, Qt::UserRole); + fi = (field_info *) v.value(); + if (!fi || !fi->hfinfo) return; + + if (fi->hfinfo->blurb != NULL && fi->hfinfo->blurb[0] != '\0') { + itemInfo.append(QString().fromUtf8(fi->hfinfo->blurb)); + } else { + itemInfo.append(QString().fromUtf8(fi->hfinfo->name)); + } + + if (!itemInfo.isEmpty()) { + itemInfo.append(" (" + QString().fromUtf8(fi->hfinfo->abbrev) + ")"); + + finfo_length = fi->length + fi->appendix_length; + if (finfo_length == 1) { + itemInfo.append(", 1 byte"); + } else if (finfo_length > 1) { + itemInfo.append(QString(", %1 bytes").arg(finfo_length)); + } + + emit protoItemUnselected(); + emit protoItemSelected(itemInfo); + } // else the GTK+ version pushes an empty string as described below. + /* + * Don't show anything if the field name is zero-length; + * the pseudo-field for "proto_tree_add_text()" is such + * 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. + * + * Or perhaps protocol tree items added with + * "proto_tree_add_text()" 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. + */ + + } else { + emit protoItemUnselected(); + } } diff --git a/ui/qt/proto_tree.h b/ui/qt/proto_tree.h index 7afd278df9..64fb8d3cd9 100644 --- a/ui/qt/proto_tree.h +++ b/ui/qt/proto_tree.h @@ -30,17 +30,23 @@ #include -void proto_tree_draw(proto_tree *protocol_tree, QTreeWidget *protoTree); class ProtoTree : public QTreeWidget { Q_OBJECT public: explicit ProtoTree(QWidget *parent = 0); + void fillProtocolTree(proto_tree *protocol_tree); + void clear(); + +private: signals: + void protoItemSelected(QString &); + void protoItemUnselected(); public slots: + void updateSelectionStatus(QTreeWidgetItem*); }; diff --git a/ui/qt/wireshark_application.cpp b/ui/qt/wireshark_application.cpp index 2918a4d20f..b2b0981f0e 100644 --- a/ui/qt/wireshark_application.cpp +++ b/ui/qt/wireshark_application.cpp @@ -31,6 +31,8 @@ #include "qt_ui_utils.h" +#include "file.h" +#include "log.h" #include "recent_file_status.h" #include @@ -176,6 +178,55 @@ void WiresharkApplication::refreshRecentFiles(void) { } } +void WiresharkApplication::captureFileCallback(int event, void * data) +{ + capture_file *cf = (capture_file *) data; + + switch(event) { + + case(cf_cb_file_closing): + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing"); + emit captureFileClosing(cf); + break; + case(cf_cb_file_closed): + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed"); + emit captureFileClosed(cf); + break; + case(cf_cb_file_read_started): + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read started"); + emit captureFileReadStarted(cf); + break; + case(cf_cb_file_read_finished): + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished"); + emit captureFileReadFinished(cf); + break; + + case(cf_cb_packet_selected): + case(cf_cb_packet_unselected): + case(cf_cb_field_unselected): + // Pure signals and slots + break; + +// case(cf_cb_file_save_started): // data = string +// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save started"); +// break; +// case(cf_cb_file_save_finished): +// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save finished"); +// break; +// case(cf_cb_file_save_reload_finished): +// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Reload finished"); +// main_cf_cb_file_save_reload_finished(data); +// break; +// case(cf_cb_file_save_failed): +// g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save failed"); +// break; + default: + g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: main_cf_callback %d %p", event, data); +// g_warning("main_cf_callback: event %u unknown", event); +// g_assert_not_reached(); + } +} + void WiresharkApplication::clearRecentItems() { recent_item_status *ri; diff --git a/ui/qt/wireshark_application.h b/ui/qt/wireshark_application.h index f4601076c9..25cf33ea54 100644 --- a/ui/qt/wireshark_application.h +++ b/ui/qt/wireshark_application.h @@ -24,6 +24,12 @@ #ifndef WIRESHARK_APPLICATION_H #define WIRESHARK_APPLICATION_H +#include "config.h" + +#include + +#include "file.h" + #include #include #include @@ -49,6 +55,7 @@ public: explicit WiresharkApplication(int &argc, char **argv); QList recent_item_list() const; void addRecentItem(const QString &filename, qint64 size, bool accessible); + void captureFileCallback(int event, void * data); private: QTimer *recentTimer; @@ -56,6 +63,11 @@ private: signals: void updateRecentItemStatus(const QString &filename, qint64 size, bool accessible); + void captureFileReadStarted(const capture_file *cf); + void captureFileReadFinished(const capture_file *cf); + void captureFileClosing(const capture_file *cf); + void captureFileClosed(const capture_file *cf); + public slots: void clearRecentItems();