diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/qt/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 2 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.cpp | 274 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.h | 12 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.ui | 52 | ||||
-rw-r--r-- | ui/qt/voip_calls_info_model.cpp | 246 | ||||
-rw-r--r-- | ui/qt/voip_calls_info_model.h | 96 |
7 files changed, 399 insertions, 285 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index f70606e1a4..d410638711 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -164,6 +164,7 @@ set(WIRESHARK_QT_HEADERS uat_model.h uat_tree_view.h voip_calls_dialog.h + voip_calls_info_model.h wireless_frame.h wireshark_application.h wireshark_dialog.h @@ -333,6 +334,7 @@ set(WIRESHARK_QT_SRC uat_model.cpp uat_tree_view.cpp voip_calls_dialog.cpp + voip_calls_info_model.cpp wireless_frame.cpp wireshark_application.cpp wireshark_dialog.cpp diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index eb1d77e7a4..a6ad706a55 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -295,6 +295,7 @@ MOC_HDRS = \ uat_model.h \ uat_tree_view.h \ voip_calls_dialog.h \ + voip_calls_info_model.h \ wireless_frame.h \ wireshark_application.h \ wireshark_dialog.h \ @@ -576,6 +577,7 @@ WIRESHARK_QT_SRC = \ uat_model.cpp \ uat_tree_view.cpp \ voip_calls_dialog.cpp \ + voip_calls_info_model.cpp \ wireless_frame.cpp \ wireshark_application.cpp \ wireshark_dialog.cpp diff --git a/ui/qt/voip_calls_dialog.cpp b/ui/qt/voip_calls_dialog.cpp index 439226e9bb..c1bb74a460 100644 --- a/ui/qt/voip_calls_dialog.cpp +++ b/ui/qt/voip_calls_dialog.cpp @@ -28,13 +28,13 @@ #include "epan/dissectors/packet-h225.h" #include "ui/rtp_stream.h" -#include <wsutil/utf8_entities.h> #include "qt_ui_utils.h" #include "rtp_player_dialog.h" #include "sequence_dialog.h" #include "stock_icon.h" #include "wireshark_application.h" +#include "voip_calls_info_model.h" #include <QClipboard> #include <QContextMenuEvent> @@ -45,180 +45,14 @@ // - Don't select on right click // - Player // - Add a screenshot to the user's guide +// - Add filter for quickly searching through list? // Bugs: // - Preparing a filter overwrites the existing filter. The GTK+ UI appends. // We'll probably have to add an "append" parameter to MainWindow::filterPackets. -// VoipCallsTreeWidgetItem -// QTreeWidgetItem subclass that allows sorting - -const int start_time_col_ = 0; -const int stop_time_col_ = 1; -const int initial_speaker_col_ = 2; -const int from_col_ = 3; -const int to_col_ = 4; -const int protocol_col_ = 5; -const int duration_col_ = 6; -const int packets_col_ = 7; -const int state_col_ = 8; -const int comments_col_ = 9; - enum { voip_calls_type_ = 1000 }; -class VoipCallsTreeWidgetItem : public QTreeWidgetItem -{ -public: - VoipCallsTreeWidgetItem(QTreeWidget *tree, voip_calls_info_t *call_info) : - QTreeWidgetItem(tree, voip_calls_type_), - call_info_(call_info), - mTimeOfDay_(false) - { - drawData(); - } - - voip_calls_info_t *callInfo() { - // XXX Not needed? We explicitly pass selected conversations to RtpPlayerDialog. -// call_info_->selected = isSelected() ? TRUE : FALSE; - return call_info_; - } - - void drawData() { - if (!call_info_) { - setText(start_time_col_, QObject::tr("Error")); - return; - } - guint callDuration = nstime_to_sec(&(call_info_->stop_fd->abs_ts)) - nstime_to_sec(&(call_info_->start_fd->abs_ts)); - - if (mTimeOfDay_) { - setText(start_time_col_, QDateTime::fromTime_t(nstime_to_sec(&(call_info_->start_fd->abs_ts))).toTimeSpec(Qt::LocalTime).toString("yyyy-MM-dd hh:mm:ss")); - setText(stop_time_col_, QDateTime::fromTime_t(nstime_to_sec(&(call_info_->stop_fd->abs_ts))).toTimeSpec(Qt::LocalTime).toString("yyyy-MM-dd hh:mm:ss")); - } else { - // XXX Pull digit count from capture file precision - setText(start_time_col_, QString::number(nstime_to_sec(&(call_info_->start_rel_ts)), 'f', 6)); - setText(stop_time_col_, QString::number(nstime_to_sec(&(call_info_->stop_rel_ts)), 'f', 6)); - } - - setText(initial_speaker_col_, address_to_display_qstring(&(call_info_->initial_speaker))); - setText(from_col_, call_info_->from_identity); - setText(to_col_, call_info_->to_identity); - setText(protocol_col_, ((call_info_->protocol == VOIP_COMMON) && call_info_->protocol_name) ? - call_info_->protocol_name : voip_protocol_name[call_info_->protocol]); - setText(duration_col_, QString("%1:%2:%3").arg(callDuration / 3600, 2, 10, QChar('0')).arg((callDuration % 3600) / 60, 2, 10, QChar('0')).arg(callDuration % 60, 2, 10, QChar('0'))); - setText(packets_col_, QString::number(call_info_->npackets)); - setText(state_col_, voip_call_state_name[call_info_->call_state]); - - /* Add comments based on the protocol */ - QString call_comments; - switch (call_info_->protocol) { - case VOIP_ISUP: - { - isup_calls_info_t *isup_info = (isup_calls_info_t *)call_info_->prot_info; - call_comments = QString("%1-%2 %3 %4-%5") - .arg(isup_info->ni) - .arg(isup_info->opc) - .arg(UTF8_RIGHTWARDS_ARROW) - .arg(isup_info->ni) - .arg(isup_info->dpc); - } - break; - case VOIP_H323: - { - h323_calls_info_t *h323_info = (h323_calls_info_t *)call_info_->prot_info; - gboolean flag = FALSE; - static const QString on_str = QObject::tr("On"); - static const QString off_str = QObject::tr("Off"); - if (call_info_->call_state == VOIP_CALL_SETUP) { - flag = h323_info->is_faststart_Setup; - } else { - if ((h323_info->is_faststart_Setup) && (h323_info->is_faststart_Proc)) { - flag = TRUE; - } - } - call_comments = QObject::tr("Tunneling: %1 Fast Start: %2") - .arg(h323_info->is_h245Tunneling ? on_str : off_str) - .arg(flag ? on_str : off_str); - } - break; - case VOIP_COMMON: - default: - call_comments = call_info_->call_comment; - break; - } - setText(comments_col_, call_comments); - } - - // Return a QString, int, double, or invalid QVariant representing the raw column data. - QVariant colData(int col) const { - if (!call_info_) { - return QVariant(); - } - - switch(col) { - case start_time_col_: - return nstime_to_sec(&call_info_->start_rel_ts); - break; - case stop_time_col_: - return nstime_to_sec(&call_info_->stop_rel_ts); - break; - case initial_speaker_col_: - case from_col_: - case to_col_: - case protocol_col_: - case duration_col_: - case state_col_: - case comments_col_: - return text(col); - break; - case packets_col_: - return call_info_->npackets; - break; - default: - break; - } - return QVariant(); - } - - bool operator< (const QTreeWidgetItem &other) const - { - if (other.type() != voip_calls_type_) return QTreeWidgetItem::operator< (other); - const VoipCallsTreeWidgetItem *other_row = static_cast<const VoipCallsTreeWidgetItem *>(&other); - - if (!call_info_ || !other_row->call_info_) { - return QTreeWidgetItem::operator< (other); - } - - switch (treeWidget()->sortColumn()) { - case start_time_col_: - return nstime_cmp(&(call_info_->start_rel_ts), &(other_row->call_info_->start_rel_ts)) < 0; - break; - case stop_time_col_: - return nstime_cmp(&(call_info_->stop_rel_ts), &(other_row->call_info_->stop_rel_ts)) < 0; - break; - case initial_speaker_col_: - return cmp_address(&(call_info_->initial_speaker), &(other_row->call_info_->initial_speaker)) < 0; - break; - case packets_col_: - return call_info_->npackets < other_row->call_info_->npackets; - break; - default: - break; - } - - // Fall back to string comparison - return QTreeWidgetItem::operator <(other); - } - - void setTimeOfDay(bool timeOfDay) - { - mTimeOfDay_ = timeOfDay; - } - -private: - voip_calls_info_t *call_info_; - bool mTimeOfDay_; -}; - VoipCallsDialog::VoipCallsDialog(QWidget &parent, CaptureFile &cf, bool all_flows) : WiresharkDialog(parent, cf), ui(new Ui::VoipCallsDialog), @@ -227,7 +61,16 @@ VoipCallsDialog::VoipCallsDialog(QWidget &parent, CaptureFile &cf, bool all_flow ui->setupUi(this); loadGeometry(parent.width() * 4 / 5, parent.height() * 2 / 3); - ui->callTreeWidget->sortByColumn(start_time_col_, Qt::AscendingOrder); + // Create the model that stores the actual data and the proxy model that is + // responsible for sorting and filtering data in the display. + call_infos_model_ = new VoipCallsInfoModel(this); + sorted_model_ = new VoipCallsInfoSortedModel(this); + sorted_model_->setSourceModel(call_infos_model_); + ui->callTreeView->setModel(sorted_model_); + + connect(ui->callTreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(updateWidgets())); + ui->callTreeView->sortByColumn(VoipCallsInfoModel::StartTime, Qt::AscendingOrder); setWindowSubtitle(all_flows ? tr("SIP Flows") : tr("VoIP Calls")); ctx_menu_.addAction(ui->actionSelect_All); @@ -359,38 +202,24 @@ void VoipCallsDialog::tapDraw(void *tapinfo_ptr) void VoipCallsDialog::updateCalls() { - GList *cur_call = g_queue_peek_nth_link(tapinfo_.callsinfos, ui->callTreeWidget->topLevelItemCount()); - ui->callTreeWidget->setSortingEnabled(false); + ui->callTreeView->setSortingEnabled(false); // Add any missing items - while (cur_call && cur_call->data) { - voip_calls_info_t *call_info = (voip_calls_info_t*) cur_call->data; - new VoipCallsTreeWidgetItem(ui->callTreeWidget, call_info); - cur_call = g_list_next(cur_call); - } - - // Fill in the tree - QTreeWidgetItemIterator iter(ui->callTreeWidget); - while (*iter) { - VoipCallsTreeWidgetItem *vcti = static_cast<VoipCallsTreeWidgetItem*>(*iter); - vcti->setTimeOfDay(ui->todCheckBox->isChecked()); - vcti->drawData(); - ++iter; - } + call_infos_model_->updateCalls(tapinfo_.callsinfos); // Resize columns - for (int i = 0; i < ui->callTreeWidget->columnCount(); i++) { - ui->callTreeWidget->resizeColumnToContents(i); + for (int i = 0; i < call_infos_model_->columnCount(); i++) { + ui->callTreeView->resizeColumnToContents(i); } - ui->callTreeWidget->setSortingEnabled(true); + ui->callTreeView->setSortingEnabled(true); updateWidgets(); } void VoipCallsDialog::updateWidgets() { - bool selected = ui->callTreeWidget->selectedItems().count() > 0 ? true : false; + bool selected = ui->callTreeView->selectionModel()->hasSelection(); bool have_ga_items = false; if (tapinfo_.graph_analysis && tapinfo_.graph_analysis->items) { @@ -412,7 +241,7 @@ void VoipCallsDialog::updateWidgets() void VoipCallsDialog::prepareFilter() { - if (ui->callTreeWidget->selectedItems().count() < 1 || !tapinfo_.graph_analysis) { + if (!ui->callTreeView->selectionModel()->hasSelection() || !tapinfo_.graph_analysis) { return; } @@ -421,9 +250,8 @@ void VoipCallsDialog::prepareFilter() /* Build a new filter based on frame numbers */ const char *or_prepend = ""; - foreach (QTreeWidgetItem *ti, ui->callTreeWidget->selectedItems()) { - VoipCallsTreeWidgetItem *vc_ti = static_cast<VoipCallsTreeWidgetItem *>(ti); - voip_calls_info_t *call_info = vc_ti->callInfo(); + foreach (QModelIndex index, ui->callTreeView->selectionModel()->selectedIndexes()) { + voip_calls_info_t *call_info = VoipCallsInfoModel::indexToCallInfo(index); if (!call_info) { return; } @@ -536,9 +364,8 @@ void VoipCallsDialog::showSequence() if (file_closed_) return; QSet<guint16> selected_calls; - foreach (QTreeWidgetItem *ti, ui->callTreeWidget->selectedItems()) { - VoipCallsTreeWidgetItem *vc_ti = static_cast<VoipCallsTreeWidgetItem *>(ti); - voip_calls_info_t *call_info = vc_ti->callInfo(); + foreach (QModelIndex index, ui->callTreeView->selectionModel()->selectedIndexes()) { + voip_calls_info_t *call_info = VoipCallsInfoModel::indexToCallInfo(index); if (!call_info) { return; } @@ -562,17 +389,19 @@ void VoipCallsDialog::showPlayer() #ifdef QT_MULTIMEDIA_LIB RtpPlayerDialog rtp_player_dialog(*this, cap_file_); - foreach (QTreeWidgetItem *ti, ui->callTreeWidget->selectedItems()) { - VoipCallsTreeWidgetItem *vc_ti = static_cast<VoipCallsTreeWidgetItem *>(ti); + foreach (QModelIndex index, ui->callTreeView->selectionModel()->selectedIndexes()) { + voip_calls_info_t *vci = VoipCallsInfoModel::indexToCallInfo(index); + if (!vci) continue; + for (GList *rsi_entry = g_list_first(tapinfo_.rtp_stream_list); rsi_entry; rsi_entry = g_list_next(rsi_entry)) { rtp_stream_info_t *rsi = (rtp_stream_info_t *)rsi_entry->data; if (!rsi) continue; //VOIP_CALLS_DEBUG("checking call %u, start frame %u == stream call %u, start frame %u, setup frame %u", - // vc_ti->callInfo()->call_num, vc_ti->callInfo()->start_fd->num, + // vci->call_num, vci->start_fd->num, // rsi->call_num, rsi->start_fd->num, rsi->setup_frame_number); - if (vc_ti->callInfo()->call_num == rsi->call_num) { - //VOIP_CALLS_DEBUG("adding call number %u", vc_ti->callInfo()->call_num); + if (vci->call_num == (guint)rsi->call_num) { + //VOIP_CALLS_DEBUG("adding call number %u", vci->call_num); rtp_player_dialog.addRtpStream(rsi); } } @@ -588,57 +417,44 @@ QList<QVariant> VoipCallsDialog::streamRowData(int row) const { QList<QVariant> row_data; - if (row >= ui->callTreeWidget->topLevelItemCount()) { + if (row >= sorted_model_->rowCount()) { return row_data; } - for (int col = 0; col < ui->callTreeWidget->columnCount(); col++) { + for (int col = 0; col < sorted_model_->columnCount(); col++) { if (row < 0) { - row_data << ui->callTreeWidget->headerItem()->text(col); + row_data << sorted_model_->headerData(col, Qt::Horizontal); } else { - VoipCallsTreeWidgetItem *vcti = static_cast<VoipCallsTreeWidgetItem*>(ui->callTreeWidget->topLevelItem(row)); - if (vcti) { - row_data << vcti->colData(col); - } + row_data << sorted_model_->index(row, col).data(); } } return row_data; } -void VoipCallsDialog::on_callTreeWidget_itemActivated(QTreeWidgetItem *item, int) +void VoipCallsDialog::on_callTreeView_activated(const QModelIndex &index) { - VoipCallsTreeWidgetItem *vc_ti = static_cast<VoipCallsTreeWidgetItem *>(item); - voip_calls_info_t *call_info = vc_ti->callInfo(); + voip_calls_info_t *call_info = VoipCallsInfoModel::indexToCallInfo(index); if (!call_info) { return; } emit goToPacket(call_info->start_fd->num); } -void VoipCallsDialog::on_callTreeWidget_itemSelectionChanged() -{ - updateWidgets(); -} - void VoipCallsDialog::on_actionSelect_All_triggered() { - ui->callTreeWidget->selectAll(); + ui->callTreeView->selectAll(); } void VoipCallsDialog::on_actionCopyAsCsv_triggered() { QString csv; QTextStream stream(&csv, QIODevice::Text); - for (int row = -1; row < ui->callTreeWidget->topLevelItemCount(); row++) { + for (int row = -1; row < sorted_model_->rowCount(); row++) { QStringList rdsl; foreach (QVariant v, streamRowData(row)) { - if (!v.isValid()) { - rdsl << "\"\""; - } else if ((int) v.type() == (int) QMetaType::QString) { - rdsl << QString("\"%1\"").arg(v.toString()); - } else { - rdsl << v.toString(); - } + QString strval = v.toString(); + // XXX should quotes (") in strval be stripped/sanitized? + rdsl << QString("\"%1\"").arg(strval); } stream << rdsl.join(",") << endl; } @@ -650,7 +466,7 @@ void VoipCallsDialog::on_actionCopyAsYaml_triggered() QString yaml; QTextStream stream(&yaml, QIODevice::Text); stream << "---" << endl; - for (int row = -1; row < ui->callTreeWidget->topLevelItemCount(); row ++) { + for (int row = -1; row < sorted_model_->rowCount(); row++) { stream << "-" << endl; foreach (QVariant v, streamRowData(row)) { stream << " - " << v.toString() << endl; @@ -675,9 +491,11 @@ void VoipCallsDialog::on_buttonBox_helpRequested() wsApp->helpTopicAction(HELP_TELEPHONY_VOIP_CALLS_DIALOG); } -void VoipCallsDialog::on_todCheckBox_clicked() +void VoipCallsDialog::on_todCheckBox_stateChanged(int state) { - updateCalls(); + call_infos_model_->setTimeOfDay(state == Qt::Checked); + ui->callTreeView->resizeColumnToContents(VoipCallsInfoModel::StartTime); + ui->callTreeView->resizeColumnToContents(VoipCallsInfoModel::StopTime); } /* diff --git a/ui/qt/voip_calls_dialog.h b/ui/qt/voip_calls_dialog.h index f9b9b22e69..f9d1b07092 100644 --- a/ui/qt/voip_calls_dialog.h +++ b/ui/qt/voip_calls_dialog.h @@ -28,6 +28,7 @@ #include "ui/voip_calls.h" +#include "voip_calls_info_model.h" #include "wireshark_dialog.h" #include <QMenu> @@ -35,7 +36,6 @@ struct _capture_file; class QAbstractButton; -class QTreeWidgetItem; class SequenceInfo; @@ -43,7 +43,6 @@ namespace Ui { class VoipCallsDialog; } -class QTreeWidgetItem; class VoipCallsDialog : public WiresharkDialog { Q_OBJECT @@ -68,6 +67,8 @@ protected slots: private: Ui::VoipCallsDialog *ui; + VoipCallsInfoModel *call_infos_model_; + QSortFilterProxyModel *sorted_model_; QWidget &parent_; voip_calls_tapinfo_t tapinfo_; @@ -84,7 +85,6 @@ private: static void tapDraw(void *tapinfo_ptr); void updateCalls(); - void updateWidgets(); void prepareFilter(); void showSequence(); void showPlayer(); @@ -93,14 +93,14 @@ private: private slots: void captureFileClosing(); - void on_callTreeWidget_itemActivated(QTreeWidgetItem *item, int); - void on_callTreeWidget_itemSelectionChanged(); + void on_callTreeView_activated(const QModelIndex &index); void on_actionSelect_All_triggered(); void on_actionCopyAsCsv_triggered(); void on_actionCopyAsYaml_triggered(); void on_buttonBox_clicked(QAbstractButton *button); void on_buttonBox_helpRequested(); - void on_todCheckBox_clicked(); + void on_todCheckBox_stateChanged(int state); + void updateWidgets(); }; #endif // VOIP_CALLS_DIALOG_H diff --git a/ui/qt/voip_calls_dialog.ui b/ui/qt/voip_calls_dialog.ui index 0aae35bf34..1b0b4f09df 100644 --- a/ui/qt/voip_calls_dialog.ui +++ b/ui/qt/voip_calls_dialog.ui @@ -15,7 +15,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QTreeWidget" name="callTreeWidget"> + <widget class="QTreeView" name="callTreeView"> <property name="selectionMode"> <enum>QAbstractItemView::ExtendedSelection</enum> </property> @@ -31,56 +31,6 @@ <property name="itemsExpandable"> <bool>false</bool> </property> - <column> - <property name="text"> - <string>Start Time</string> - </property> - </column> - <column> - <property name="text"> - <string>Stop Time</string> - </property> - </column> - <column> - <property name="text"> - <string>Initial Speaker</string> - </property> - </column> - <column> - <property name="text"> - <string>From</string> - </property> - </column> - <column> - <property name="text"> - <string>To</string> - </property> - </column> - <column> - <property name="text"> - <string>Protocol</string> - </property> - </column> - <column> - <property name="text"> - <string>Duration</string> - </property> - </column> - <column> - <property name="text"> - <string>Packets</string> - </property> - </column> - <column> - <property name="text"> - <string>State</string> - </property> - </column> - <column> - <property name="text"> - <string>Comments</string> - </property> - </column> </widget> </item> <item> diff --git a/ui/qt/voip_calls_info_model.cpp b/ui/qt/voip_calls_info_model.cpp new file mode 100644 index 0000000000..144829411d --- /dev/null +++ b/ui/qt/voip_calls_info_model.cpp @@ -0,0 +1,246 @@ +/* voip_calls_info_model.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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "voip_calls_info_model.h" +#include <wsutil/utf8_entities.h> +#include "qt_ui_utils.h" + +#include <QDateTime> + +VoipCallsInfoModel::VoipCallsInfoModel(QObject *parent) : + QAbstractTableModel(parent), + mTimeOfDay_(false) +{ +} + +voip_calls_info_t *VoipCallsInfoModel::indexToCallInfo(const QModelIndex &index) +{ + return VariantPointer<voip_calls_info_t>::asPtr(index.data(Qt::UserRole)); +} + +QVariant VoipCallsInfoModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + // call_info will be non-NULL since the index is valid + voip_calls_info_t *call_info = static_cast<voip_calls_info_t *>(callinfos_[index.row()]); + + if (role == Qt::UserRole) { + return VariantPointer<voip_calls_info_t>::asQVariant(call_info); + } + + if (role != Qt::DisplayRole) { + return QVariant(); + } + + switch ((Column) index.column()) { + case StartTime: + return timeData(&(call_info->start_fd->abs_ts), &(call_info->start_rel_ts)); + case StopTime: + return timeData(&(call_info->stop_fd->abs_ts), &(call_info->stop_rel_ts)); + case InitialSpeaker: + return address_to_display_qstring(&(call_info->initial_speaker)); + case From: + return call_info->from_identity; + case To: + return call_info->to_identity; + case Protocol: + return ((call_info->protocol == VOIP_COMMON) && call_info->protocol_name) ? + call_info->protocol_name : voip_protocol_name[call_info->protocol]; + case Duration: + { + guint callDuration = nstime_to_sec(&(call_info->stop_fd->abs_ts)) - nstime_to_sec(&(call_info->start_fd->abs_ts)); + return QString("%1:%2:%3").arg(callDuration / 3600, 2, 10, QChar('0')).arg((callDuration % 3600) / 60, 2, 10, QChar('0')).arg(callDuration % 60, 2, 10, QChar('0')); + } + case Packets: + return call_info->npackets; + case State: + return QString(voip_call_state_name[call_info->call_state]); + case Comments: + /* Add comments based on the protocol */ + switch (call_info->protocol) { + case VOIP_ISUP: + { + isup_calls_info_t *isup_info = (isup_calls_info_t *)call_info->prot_info; + return QString("%1-%2 %3 %4-%5") + .arg(isup_info->ni) + .arg(isup_info->opc) + .arg(UTF8_RIGHTWARDS_ARROW) + .arg(isup_info->ni) + .arg(isup_info->dpc); + } + break; + case VOIP_H323: + { + h323_calls_info_t *h323_info = (h323_calls_info_t *)call_info->prot_info; + gboolean flag = FALSE; + static const QString on_str = tr("On"); + static const QString off_str = tr("Off"); + if (call_info->call_state == VOIP_CALL_SETUP) { + flag = h323_info->is_faststart_Setup; + } else { + if ((h323_info->is_faststart_Setup) && (h323_info->is_faststart_Proc)) { + flag = TRUE; + } + } + return tr("Tunneling: %1 Fast Start: %2") + .arg(h323_info->is_h245Tunneling ? on_str : off_str) + .arg(flag ? on_str : off_str); + } + break; + case VOIP_COMMON: + default: + return call_info->call_comment; + } + case ColumnCount: + g_assert_not_reached(); + } + return QVariant(); +} + +QVariant VoipCallsInfoModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch ((Column) section) { + case StartTime: + return tr("Start Time"); + case StopTime: + return tr("Stop Time"); + case InitialSpeaker: + return tr("Initial Speaker"); + case From: + return tr("From"); + case To: + return tr("To"); + case Protocol: + return tr("Protocol"); + case Duration: + return tr("Duration"); + case Packets: + return tr("Packets"); + case State: + return tr("State"); + case Comments: + return tr("Comments"); + case ColumnCount: + g_assert_not_reached(); + } + } + return QVariant(); +} + +int VoipCallsInfoModel::rowCount(const QModelIndex &parent) const +{ + // there are no children + if (parent.isValid()) { + return 0; + } + + return callinfos_.size(); +} + +int VoipCallsInfoModel::columnCount(const QModelIndex &parent) const +{ + // there are no children + if (parent.isValid()) { + return 0; + } + + return ColumnCount; +} + +QVariant VoipCallsInfoModel::timeData(nstime_t *abs_ts, nstime_t *rel_ts) const +{ + if (mTimeOfDay_) { + return QDateTime::fromTime_t(nstime_to_sec(abs_ts)).toTimeSpec(Qt::LocalTime).toString("yyyy-MM-dd hh:mm:ss"); + } else { + // XXX Pull digit count from capture file precision + return QString::number(nstime_to_sec(rel_ts), 'f', 6); + } +} + +void VoipCallsInfoModel::setTimeOfDay(bool timeOfDay) +{ + mTimeOfDay_ = timeOfDay; + if (rowCount() > 0) { + // Update both the start and stop column in all rows. + emit dataChanged(index(0, StartTime), index(rowCount() - 1, StopTime)); + } +} + +void VoipCallsInfoModel::updateCalls(GQueue *callsinfos) +{ + if (callsinfos) { + GList *cur_call = g_queue_peek_nth_link(callsinfos, rowCount()); + guint extra = g_list_length(cur_call); + if (extra > 0) { + beginInsertRows(QModelIndex(), rowCount(), rowCount() + extra - 1); + while (cur_call && cur_call->data) { + voip_calls_info_t *call_info = (voip_calls_info_t*) cur_call->data; + callinfos_.push_back(call_info); + cur_call = g_list_next(cur_call); + } + endInsertRows(); + } + } +} + + +// Proxy model that allows columns to be sorted. +VoipCallsInfoSortedModel::VoipCallsInfoSortedModel(QObject *parent) : + QSortFilterProxyModel(parent) +{ +} + +bool VoipCallsInfoSortedModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +{ + voip_calls_info_t *a = VoipCallsInfoModel::indexToCallInfo(source_left); + voip_calls_info_t *b = VoipCallsInfoModel::indexToCallInfo(source_right); + + if (a && b) { + switch (source_left.column()) { + case VoipCallsInfoModel::StartTime: + return nstime_cmp(&(a->start_rel_ts), &(b->start_rel_ts)) < 0; + case VoipCallsInfoModel::StopTime: + return nstime_cmp(&(a->stop_rel_ts), &(b->stop_rel_ts)) < 0; + case VoipCallsInfoModel::InitialSpeaker: + return cmp_address(&(a->initial_speaker), &(b->initial_speaker)) < 0; + } + } + + // fallback to string cmp on other fields + return QSortFilterProxyModel::lessThan(source_left, source_right); +} + +/* + * 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/voip_calls_info_model.h b/ui/qt/voip_calls_info_model.h new file mode 100644 index 0000000000..025a3c9444 --- /dev/null +++ b/ui/qt/voip_calls_info_model.h @@ -0,0 +1,96 @@ +/* voip_calls_info_model.h + * + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef VOIP_CALLS_INFO_MODEL_H +#define VOIP_CALLS_INFO_MODEL_H + +#include <config.h> +#include <glib.h> + +#include "ui/voip_calls.h" +#include "variant_pointer.h" + +#include <QAbstractTableModel> +#include <QSortFilterProxyModel> + +class VoipCallsInfoModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + VoipCallsInfoModel(QObject *parent = 0); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + void setTimeOfDay(bool timeOfDay); + void updateCalls(GQueue *callsinfos); + + static voip_calls_info_t *indexToCallInfo(const QModelIndex &index); + + enum Column + { + StartTime, + StopTime, + InitialSpeaker, + From, + To, + Protocol, + Duration, + Packets, + State, + Comments, + ColumnCount /* not an actual column, but used to find max. cols. */ + }; + +private: + QList<void *> callinfos_; + bool mTimeOfDay_; + + QVariant timeData(nstime_t *abs_ts, nstime_t *rel_ts) const; +}; + +class VoipCallsInfoSortedModel : public QSortFilterProxyModel +{ + Q_OBJECT; + +public: + VoipCallsInfoSortedModel(QObject *parent = 0); + +protected: + bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const; +}; + +#endif // VOIP_CALLS_INFO_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: + */ |