diff options
-rw-r--r-- | ui/qt/sequence_diagram.cpp | 47 | ||||
-rw-r--r-- | ui/qt/sequence_diagram.h | 10 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.cpp | 140 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.h | 7 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.ui | 24 |
5 files changed, 176 insertions, 52 deletions
diff --git a/ui/qt/sequence_diagram.cpp b/ui/qt/sequence_diagram.cpp index fa1ace2d54..0dd6629277 100644 --- a/ui/qt/sequence_diagram.cpp +++ b/ui/qt/sequence_diagram.cpp @@ -58,7 +58,8 @@ SequenceDiagram::SequenceDiagram(QCPAxis *keyAxis, QCPAxis *valueAxis, QCPAxis * comment_axis_(commentAxis), data_(NULL), sainfo_(NULL), - selected_packet_(0) + selected_packet_(0), + selected_key_(-1.0) { data_ = new WSCPSeqDataMap(); // xaxis (value): Address @@ -103,6 +104,46 @@ SequenceDiagram::~SequenceDiagram() delete data_; } +int SequenceDiagram::adjacentPacket(bool next) +{ + int adjacent_packet = -1; + WSCPSeqDataMap::const_iterator it; + + if (data_->size() < 1) return adjacent_packet; + + if (selected_packet_ < 1) { + WSCPSeqData &data = next ? data_->first() : data_->last(); + return data.value->frame_number; + } + + if (next) { + for (it = data_->constBegin(); it != data_->constEnd(); ++it) { + if (it.value().value->frame_number == selected_packet_) { + ++it; + if (it != data_->constEnd()) { + adjacent_packet = it.value().value->frame_number; + selected_key_ = it.value().key; + } + break; + } + } + } else { + it = data_->constEnd(); + --it; + while (it != data_->constBegin()) { + guint32 prev_frame = it.value().value->frame_number; + --it; + if (prev_frame == selected_packet_) { + adjacent_packet = it.value().value->frame_number; + selected_key_ = it.value().key; + break; + } + } + } + + return adjacent_packet; +} + void SequenceDiagram::setData(_seq_analysis_info *sainfo) { data_->clear(); @@ -154,6 +195,7 @@ void SequenceDiagram::setData(_seq_analysis_info *sainfo) void SequenceDiagram::setSelectedPacket(int selected_packet) { + selected_key_ = -1; if (selected_packet > 0) { selected_packet_ = selected_packet; } else { @@ -215,6 +257,7 @@ void SequenceDiagram::draw(QCPPainter *painter) QPalette sel_pal; fg_pen.setColor(sel_pal.color(QPalette::HighlightedText)); bg_color = sel_pal.color(QPalette::Highlight); + selected_key_ = cur_key; } else { fg_pen.setColor(Qt::black); bg_color = ColorUtils::sequenceColor(sai->conv_num); @@ -339,7 +382,7 @@ QCPRange SequenceDiagram::getValueRange(bool &validRange, QCPAbstractPlottable:: if (sainfo_) { range.lower = 0; - range.upper = sainfo_->num_nodes; + range.upper = data_->size(); valid = true; } validRange = valid; diff --git a/ui/qt/sequence_diagram.h b/ui/qt/sequence_diagram.h index 3ef72b604f..7a5a45f0c9 100644 --- a/ui/qt/sequence_diagram.h +++ b/ui/qt/sequence_diagram.h @@ -35,7 +35,7 @@ struct _seq_analysis_info; struct _seq_analysis_item; -// Most of this is probably unnecessary +// Some of this is probably unnecessary class WSCPSeqData { public: @@ -44,11 +44,8 @@ public: double key; struct _seq_analysis_item *value; }; -Q_DECLARE_TYPEINFO(WSCPSeqData, Q_MOVABLE_TYPE); typedef QMap<double, WSCPSeqData> WSCPSeqDataMap; -typedef QMapIterator<double, WSCPSeqData> WSCPSeqDataMapIterator; -typedef QMutableMapIterator<double, WSCPSeqData> WSCPSeqDataMutableMapIterator; class SequenceDiagram : public QCPAbstractPlottable { @@ -58,6 +55,10 @@ public: virtual ~SequenceDiagram(); // getters: + // Next / previous packet. + int adjacentPacket(bool next); + + double selectedKey() { return selected_key_; } // setters: void setData(struct _seq_analysis_info *sainfo); @@ -85,6 +86,7 @@ private: WSCPSeqDataMap *data_; struct _seq_analysis_info *sainfo_; guint32 selected_packet_; + double selected_key_; }; #endif // SEQUENCE_DIAGRAM_H diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp index e948acfc8a..145196542f 100644 --- a/ui/qt/sequence_dialog.cpp +++ b/ui/qt/sequence_dialog.cpp @@ -39,8 +39,7 @@ // To do: // - Add zoom controls. -// - Limit dragging to valid ranges. -// - Handle trackpad and mouse wheel scrolling. +// - Show + hide the Time and Comment axes. // - Add UTF8 to text dump // - Save to XMI? http://www.umlgraph.org/ // - Time: abs vs delta @@ -51,6 +50,9 @@ // - Create WSGraph subclasses with common behavior. // - Help button and text +static const double min_top_ = -1.0; +static const double min_left_ = -0.5; + SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *info) : WiresharkDialog(parent, cf), ui(new Ui::SequenceDialog), @@ -76,7 +78,11 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i seq_diagram_ = new SequenceDiagram(sp->yAxis, sp->xAxis2, sp->yAxis2); sp->addPlottable(seq_diagram_); - sp->axisRect()->setRangeDragAxes(sp->xAxis2, sp->yAxis); + + // When dragging is enabled it's easy to drag past the lower and upper + // bounds of each axis. Disable it for now. + //sp->axisRect()->setRangeDragAxes(sp->xAxis2, sp->yAxis); + //sp->setInteractions(QCP::iRangeDrag); sp->xAxis->setVisible(false); sp->xAxis->setPadding(0); @@ -96,7 +102,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i key_text_->setText(tr("Time")); sp->addItem(key_text_); - key_text_->setPositionAlignment(Qt::AlignRight | Qt::AlignBottom); + key_text_->setPositionAlignment(Qt::AlignRight | Qt::AlignVCenter); key_text_->position->setType(QCPItemPosition::ptAbsolute); key_text_->setClipToAxisRect(false); @@ -104,7 +110,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i comment_text_->setText(tr("Comment")); sp->addItem(comment_text_); - comment_text_->setPositionAlignment(Qt::AlignLeft | Qt::AlignBottom); + comment_text_->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter); comment_text_->position->setType(QCPItemPosition::ptAbsolute); comment_text_->setClipToAxisRect(false); @@ -112,8 +118,6 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i ui->horizontalScrollBar->setSingleStep(100 / one_em_); ui->verticalScrollBar->setSingleStep(100 / one_em_); - sp->setInteractions(QCP::iRangeDrag); - ui->gridLayout->setSpacing(0); connect(sp->yAxis, SIGNAL(rangeChanged(QCPRange)), sp->yAxis2, SLOT(setRange(QCPRange))); @@ -129,6 +133,8 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i ctx_menu_.addAction(ui->actionMoveDown1); ctx_menu_.addSeparator(); ctx_menu_.addAction(ui->actionGoToPacket); + ctx_menu_.addAction(ui->actionGoToNextPacket); + ctx_menu_.addAction(ui->actionGoToPreviousPacket); ui->showComboBox->setCurrentIndex(0); ui->addressComboBox->setCurrentIndex(0); @@ -155,7 +161,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i connect(sp->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisChanged(QCPRange))); connect(sp, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(diagramClicked(QMouseEvent*))); connect(sp, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoved(QMouseEvent*))); - connect(sp, SIGNAL(mouseRelease(QMouseEvent*)), this, SLOT(mouseReleased(QMouseEvent*))); + connect(sp, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheeled(QWheelEvent*))); connect(this, SIGNAL(goToPacket(int)), seq_diagram_, SLOT(setSelectedPacket(int))); disconnect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); @@ -215,16 +221,17 @@ void SequenceDialog::keyPressEvent(QKeyEvent *event) case Qt::Key_G: on_actionGoToPacket_triggered(); break; + case Qt::Key_N: + on_actionGoToNextPacket_triggered(); + break; + case Qt::Key_P: + on_actionGoToPreviousPacket_triggered(); + break; } QDialog::keyPressEvent(event); } -void SequenceDialog::mouseReleaseEvent(QMouseEvent *event) -{ - mouseReleased(event); -} - void SequenceDialog::hScrollBarChanged(int value) { if (qAbs(ui->sequencePlot->xAxis2->range().center()-value/100.0) > 0.01) { @@ -255,33 +262,22 @@ void SequenceDialog::yAxisChanged(QCPRange range) void SequenceDialog::diagramClicked(QMouseEvent *event) { - QCustomPlot *sp = ui->sequencePlot; - - if (event->button() == Qt::RightButton) { + switch (event->button()) { + case Qt::LeftButton: + on_actionGoToPacket_triggered(); + break; + case Qt::RightButton: // XXX We should find some way to get sequenceDiagram to handle a // contextMenuEvent instead. ctx_menu_.exec(event->globalPos()); - } else if (sp->axisRect()->rect().contains(event->pos())) { - sp->setCursor(QCursor(Qt::ClosedHandCursor)); + break; + default: + break; } - on_actionGoToPacket_triggered(); } void SequenceDialog::mouseMoved(QMouseEvent *event) { - QCustomPlot *sp = ui->sequencePlot; - Qt::CursorShape shape = Qt::ArrowCursor; - if (event) { - if (event->buttons().testFlag(Qt::LeftButton)) { - shape = Qt::ClosedHandCursor; - } else { - if (sp->axisRect()->rect().contains(event->pos())) { - shape = Qt::OpenHandCursor; - } - } - } - sp->setCursor(QCursor(shape)); - packet_num_ = 0; QString hint; if (event) { @@ -307,11 +303,17 @@ void SequenceDialog::mouseMoved(QMouseEvent *event) ui->hintLabel->setText(hint); } -void SequenceDialog::mouseReleased(QMouseEvent *) +void SequenceDialog::mouseWheeled(QWheelEvent *event) { - if (ui->sequencePlot->cursor().shape() == Qt::ClosedHandCursor) { - ui->sequencePlot->setCursor(QCursor(Qt::OpenHandCursor)); + int scroll_delta = event->delta() * -1 / 15; + if (event->orientation() == Qt::Vertical) { + scroll_delta *= ui->verticalScrollBar->singleStep(); + ui->verticalScrollBar->setValue(ui->verticalScrollBar->value() + scroll_delta); + } else { + scroll_delta *= ui->horizontalScrollBar->singleStep(); + ui->horizontalScrollBar->setValue(ui->horizontalScrollBar->value() + scroll_delta); } + event->accept(); } void SequenceDialog::on_buttonBox_accepted() @@ -374,8 +376,7 @@ void SequenceDialog::fillDiagram() seq_diagram_->setData(info_->sainfo()); } - QFontMetrics fm = QFontMetrics(sp->xAxis2->labelFont()); - sequence_w_ = fm.height() * 15 ; // Arbitrary + sequence_w_ = one_em_ * 15 ; // Arbitrary mouseMoved(NULL); resetAxes(); @@ -386,18 +387,32 @@ void SequenceDialog::fillDiagram() void SequenceDialog::panAxes(int x_pixels, int y_pixels) { + // We could simplify this quite a bit if we set the scroll bar values instead. + if (!info_->sainfo()) return; + QCustomPlot *sp = ui->sequencePlot; double h_pan = 0.0; double v_pan = 0.0; h_pan = sp->xAxis2->range().size() * x_pixels / sp->xAxis2->axisRect()->width(); + if (h_pan < 0) { + h_pan = qMax(h_pan, min_left_ - sp->xAxis2->range().lower); + } else { + h_pan = qMin(h_pan, info_->sainfo()->num_nodes - sp->xAxis2->range().upper); + } + v_pan = sp->yAxis->range().size() * y_pixels / sp->yAxis->axisRect()->height(); - // The GTK+ version won't pan unless we're zoomed. Should we do the same here? - if (h_pan) { + if (v_pan < 0) { + v_pan = qMax(v_pan, min_top_ - sp->yAxis->range().lower); + } else { + v_pan = qMin(v_pan, num_items_ - sp->yAxis->range().upper); + } + + if (h_pan && !(sp->xAxis2->range().contains(min_left_) && sp->xAxis2->range().contains(info_->sainfo()->num_nodes))) { sp->xAxis2->moveRange(h_pan); sp->replot(); } - if (v_pan) { + if (v_pan && !(sp->yAxis->range().contains(min_top_) && sp->yAxis->range().contains(num_items_))) { sp->yAxis->moveRange(v_pan); sp->replot(); } @@ -410,7 +425,7 @@ void SequenceDialog::resetAxes(bool keep_lower) QCustomPlot *sp = ui->sequencePlot; // Allow space for labels on the top and port numbers on the left. - double top_pos = -1.0, left_pos = -0.5; + double top_pos = min_top_, left_pos = min_left_; if (keep_lower) { top_pos = sp->yAxis->range().lower; left_pos = sp->xAxis2->range().lower; @@ -440,16 +455,17 @@ void SequenceDialog::resetAxes(bool keep_lower) sp->replot(QCustomPlot::rpQueued); QRect axis_rect = sp->axisRect()->rect(); + key_text_->position->setCoords(axis_rect.left() - sp->yAxis->padding() - sp->yAxis->tickLabelPadding() - sp->yAxis->offset(), - axis_rect.top()); + axis_rect.top() / 2); comment_text_->position->setCoords(axis_rect.right() + sp->yAxis2->padding() + sp->yAxis2->tickLabelPadding() + sp->yAxis2->offset(), - axis_rect.top()); + axis_rect.top() / 2); sp->replot(QCustomPlot::rpHint); } @@ -466,6 +482,44 @@ void SequenceDialog::on_actionGoToPacket_triggered() } } +void SequenceDialog::goToAdjacentPacket(bool next) +{ + if (file_closed_) return; + int old_key = seq_diagram_->selectedKey(); + int adjacent_packet = seq_diagram_->adjacentPacket(next); + int new_key = seq_diagram_->selectedKey(); + + if (adjacent_packet > 0) { + if (old_key >= 0 && new_key >= 0) { + // Scroll if we're at our scroll margin and we haven't reached + // the end of our range. + // XXX We should probably ensure the selected packet is visible as well. + QCustomPlot *sp = ui->sequencePlot; + double range_offset = new_key - old_key; + double scroll_margin = 3.0; // Lines + if (next) { + if (new_key + scroll_margin < sp->yAxis->range().upper) { + range_offset = 0.0; + } + while (range_offset > 0 && range_offset + sp->yAxis->range().upper > num_items_) { + range_offset--; + } + } else { + if (new_key - scroll_margin > sp->yAxis->range().lower) { + range_offset = 0.0; + } + + double slop_top = min_top_ * 1.1; + while (range_offset < 0 && range_offset + sp->yAxis->range().lower < slop_top) { + range_offset++; + } + } + sp->yAxis->moveRange(range_offset); + } + emit goToPacket(adjacent_packet); + } +} + void SequenceDialog::on_showComboBox_activated(int index) { if (!info_->sainfo()) return; diff --git a/ui/qt/sequence_dialog.h b/ui/qt/sequence_dialog.h index e091b583b0..7113319959 100644 --- a/ui/qt/sequence_dialog.h +++ b/ui/qt/sequence_dialog.h @@ -71,7 +71,6 @@ protected: void showEvent(QShowEvent *event); void resizeEvent(QResizeEvent *event); void keyPressEvent(QKeyEvent *event); - void mouseReleaseEvent(QMouseEvent *event); private slots: void updateWidgets(); @@ -81,13 +80,15 @@ private slots: void yAxisChanged(QCPRange range); void diagramClicked(QMouseEvent *event); void mouseMoved(QMouseEvent *event); - void mouseReleased(QMouseEvent *event); + void mouseWheeled(QWheelEvent *event); void fillDiagram(); void on_buttonBox_accepted(); void on_resetButton_clicked(); void on_actionGoToPacket_triggered(); + void on_actionGoToNextPacket_triggered() { goToAdjacentPacket(true); } + void on_actionGoToPreviousPacket_triggered() { goToAdjacentPacket(false); } void on_showComboBox_activated(int index); void on_flowComboBox_activated(int index); void on_addressComboBox_activated(int index); @@ -115,7 +116,7 @@ private: void panAxes(int x_pixels, int y_pixels); void resetAxes(bool keep_lower = false); - + void goToAdjacentPacket(bool next); }; #endif // SEQUENCE_DIALOG_H diff --git a/ui/qt/sequence_dialog.ui b/ui/qt/sequence_dialog.ui index 5638e486ef..dcca122502 100644 --- a/ui/qt/sequence_dialog.ui +++ b/ui/qt/sequence_dialog.ui @@ -62,6 +62,8 @@ <tr><th><i>Shift+</i>↓</th><td>Move down 1 pixel</td></th> <tr><th>g</th><td>Go to packet under cursor</td></th> +<tr><th>n</th><td>Go to the next packet</td></th> +<tr><th>p</th><td>Go to the previous packet</td></th> </tbody></table> </body></html></string> @@ -347,6 +349,28 @@ <string>1</string> </property> </action> + <action name="actionGoToNextPacket"> + <property name="text"> + <string>Go To Next Packet</string> + </property> + <property name="toolTip"> + <string>Go to the next packet</string> + </property> + <property name="shortcut"> + <string>N</string> + </property> + </action> + <action name="actionGoToPreviousPacket"> + <property name="text"> + <string>Go To Previous Packet</string> + </property> + <property name="toolTip"> + <string>Go to the previous packet</string> + </property> + <property name="shortcut"> + <string>P</string> + </property> + </action> </widget> <customwidgets> <customwidget> |