Qt: Fix conversation dialog timeline graph columns
Remove the separate copy of the conversation column type enum in ConversationDialog. It doesn't correspond to the enum in ATapDataModel, because it doesn't include the Conversation ID and Total columns. Delegates set to the Traffic Tree (a QTreeView) apply to the displayed column number, not the what is displayed in the column. That is, when columns are hidden (filtered), the delegates stay with the old column number and end up being displayed on new content. That's not what we want; we want to always have the timeline graph on the Start and Duration columns. Moving around the Delegate depending on which columns are filtered is complicated; just set the TimeLine delegate to the entire TrafficTree, and use the default paint if we're on any column other than Start or Duration. This does mean that we don't need to store a map of Delegates. Use a slightly different way to get TimelineDelegate to paint the rect with no text using the current style, so we can use the default paint with text for other columns. The timeline graph needs to get the value of the Start and Duration columns as filtered by the proxy column, so have the model pass in indices so that they can be mapped to the current displayed column. Have the timeline graph apply to just the Start or just the Duration column if only one is visible. Together these compute the proper pixel values to apply the timeline graph to the Start and Duration columns regardless of which columns are displayed and which are filtered, in any tab, regardless of what optional columns appear in that tab. Fix #18860
This commit is contained in:
parent
a2b584b8bd
commit
33493cb602
|
@ -50,25 +50,6 @@
|
|||
// - The value of 'Rel start' and 'Duration' in "Conversations" no need too precise https://gitlab.com/wireshark/wireshark/-/issues/12803
|
||||
|
||||
|
||||
typedef enum {
|
||||
CONV_COLUMN_SRC_ADDR,
|
||||
CONV_COLUMN_SRC_PORT,
|
||||
CONV_COLUMN_DST_ADDR,
|
||||
CONV_COLUMN_DST_PORT,
|
||||
CONV_COLUMN_PACKETS,
|
||||
CONV_COLUMN_BYTES,
|
||||
CONV_COLUMN_PKT_AB,
|
||||
CONV_COLUMN_BYTES_AB,
|
||||
CONV_COLUMN_PKT_BA,
|
||||
CONV_COLUMN_BYTES_BA,
|
||||
CONV_COLUMN_START,
|
||||
CONV_COLUMN_DURATION,
|
||||
CONV_COLUMN_BPS_AB,
|
||||
CONV_COLUMN_BPS_BA,
|
||||
CONV_NUM_COLUMNS,
|
||||
CONV_INDEX_COLUMN = CONV_NUM_COLUMNS
|
||||
} conversation_column_type_e;
|
||||
|
||||
static const QString table_name_ = QObject::tr("Conversation");
|
||||
|
||||
static ATapDataModel * createModel(int protoId, QString filter)
|
||||
|
@ -91,8 +72,8 @@ ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) :
|
|||
trafficList()->setProtocolInfo(table_name_, &(recent.conversation_tabs));
|
||||
|
||||
trafficTab()->setProtocolInfo(table_name_, trafficList(), &(recent.conversation_tabs_columns), &createModel);
|
||||
trafficTab()->setDelegate(CONV_COLUMN_START, &createDelegate);
|
||||
trafficTab()->setDelegate(CONV_COLUMN_DURATION, &createDelegate);
|
||||
trafficTab()->setDelegate(&createDelegate);
|
||||
trafficTab()->setDelegate(&createDelegate);
|
||||
trafficTab()->setFilter(cf.displayFilter());
|
||||
|
||||
connect(trafficTab(), &TrafficTab::filterAction, this, &ConversationDialog::filterAction);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QTreeView>
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
// XXX We might want to move this to conversation_dialog.cpp.
|
||||
|
||||
|
@ -40,26 +41,52 @@ void TimelineDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
|||
QStyleOptionViewItem option_vi = option;
|
||||
QStyledItemDelegate::initStyleOption(&option_vi, index);
|
||||
|
||||
bool drawBar = false;
|
||||
struct timeline_span span_px = index.data(_dataRole).value<struct timeline_span>();
|
||||
if (_dataRole == ATapDataModel::TIMELINE_DATA) {
|
||||
double span_s = span_px.maxRelTime - span_px.minRelTime;
|
||||
if (qobject_cast<QTreeView *>(parent()) == nullptr)
|
||||
return;
|
||||
QTreeView * tree = qobject_cast<QTreeView *>(parent());
|
||||
int start_px = tree->columnWidth(span_px.colStart);
|
||||
int column_px = start_px + tree->columnWidth(span_px.colDuration);
|
||||
if (tree) {
|
||||
QAbstractProxyModel * proxy = qobject_cast<QAbstractProxyModel *>(tree->model());
|
||||
if (proxy && proxy->sourceModel()) {
|
||||
QModelIndex indexStart = proxy->mapFromSource(proxy->sourceModel()->index(0, span_px.colStart));
|
||||
int colStart = -1;
|
||||
int start_px = 0;
|
||||
if (indexStart.isValid()) {
|
||||
colStart = indexStart.column();
|
||||
start_px = tree->columnWidth(colStart);
|
||||
}
|
||||
int colDuration = -1;
|
||||
int column_px = start_px;
|
||||
QModelIndex indexDuration = proxy->mapFromSource(proxy->sourceModel()->index(0, span_px.colDuration));
|
||||
if (indexDuration.isValid()) {
|
||||
colDuration = indexDuration.column();
|
||||
column_px += tree->columnWidth(colDuration);
|
||||
}
|
||||
|
||||
span_px.start = ((span_px.startTime - span_px.minRelTime) * column_px) / span_s;
|
||||
span_px.width = ((span_px.stopTime - span_px.startTime) * column_px) / span_s;
|
||||
span_px.start = ((span_px.startTime - span_px.minRelTime) * column_px) / span_s;
|
||||
span_px.width = ((span_px.stopTime - span_px.startTime) * column_px) / span_s;
|
||||
|
||||
if (index.column() == span_px.colDuration) {
|
||||
span_px.start -= start_px;
|
||||
if (index.column() == colStart) {
|
||||
drawBar = true;
|
||||
} else if (index.column() == colDuration) {
|
||||
drawBar = true;
|
||||
span_px.start -= start_px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!drawBar) {
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Paint our rect with no text using the current style, then draw our
|
||||
// bar and text over it.
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
option_vi.text = QString();
|
||||
QStyle *style = option_vi.widget ? option_vi.widget->style() : QApplication::style();
|
||||
style->drawControl(QStyle::CE_ItemViewItem, &option_vi, painter, option_vi.widget);
|
||||
|
||||
if (QApplication::style()->objectName().contains("vista")) {
|
||||
// QWindowsVistaStyle::drawControl does this internally. Unfortunately there
|
||||
|
|
|
@ -53,9 +53,6 @@ class TimelineDelegate : public QStyledItemDelegate
|
|||
public:
|
||||
TimelineDelegate(QWidget *parent = 0);
|
||||
|
||||
// Make sure QStyledItemDelegate::paint doesn't draw any text.
|
||||
virtual QString displayText(const QVariant &, const QLocale &) const { return QString(); }
|
||||
|
||||
void setDataRole(int role);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -69,6 +69,7 @@ TrafficTab::TrafficTab(QWidget * parent) :
|
|||
DetachableTabWidget(parent)
|
||||
{
|
||||
_createModel = nullptr;
|
||||
_createDelegate = nullptr;
|
||||
_disableTaps = false;
|
||||
_nameResolution = false;
|
||||
setTabBasename(QString());
|
||||
|
@ -90,29 +91,19 @@ void TrafficTab::setProtocolInfo(QString tableName, TrafficTypesList * trafficLi
|
|||
setOpenTabs(trafficList->protocols(true));
|
||||
}
|
||||
|
||||
void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
|
||||
void TrafficTab::setDelegate(ATapCreateDelegate createDelegate)
|
||||
{
|
||||
if (! createDelegate || column < 0)
|
||||
if (! createDelegate)
|
||||
return;
|
||||
|
||||
if (_createDelegates.keys().contains(column))
|
||||
_createDelegates.remove(column);
|
||||
_createDelegates.insert(column, createDelegate);
|
||||
_createDelegate = createDelegate;
|
||||
|
||||
|
||||
for (int idx = 0; idx < count(); idx++) {
|
||||
int setColumn = column;
|
||||
ATapDataModel * model = modelForTabIndex(idx);
|
||||
if (model->portsAreHidden()) {
|
||||
if (model->modelType() == ATapDataModel::DATAMODEL_ENDPOINT && column > EndpointDataModel::ENDP_COLUMN_PORT)
|
||||
setColumn -= 1;
|
||||
else if (model->modelType() == ATapDataModel::DATAMODEL_CONVERSATION && column > ConversationDataModel::CONV_COLUMN_DST_PORT)
|
||||
setColumn -= 2;
|
||||
}
|
||||
if (qobject_cast<QTreeView *>(widget(idx)))
|
||||
{
|
||||
QTreeView * tree = qobject_cast<QTreeView *>(widget(idx));
|
||||
tree->setItemDelegateForColumn(setColumn, createDelegate(tree));
|
||||
tree->setItemDelegate(createDelegate(tree));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,13 +119,9 @@ QTreeView * TrafficTab::createTree(int protoId)
|
|||
|
||||
model->enableTap();
|
||||
|
||||
foreach(int col, _createDelegates.keys())
|
||||
if (_createDelegate)
|
||||
{
|
||||
if (_createDelegates[col])
|
||||
{
|
||||
ATapCreateDelegate creator = _createDelegates[col];
|
||||
tree->setItemDelegateForColumn(col, creator(tree));
|
||||
}
|
||||
tree->setItemDelegate(_createDelegate(tree));
|
||||
}
|
||||
|
||||
TrafficDataFilterProxy * proxyModel = new TrafficDataFilterProxy(tree);
|
||||
|
|
|
@ -97,15 +97,14 @@ public:
|
|||
void setProtocolInfo(QString tableName, TrafficTypesList * trafficList, GList ** recentColumnList, ATapModelCallback createModel);
|
||||
|
||||
/**
|
||||
* @brief Set the Delegate object for a specific column
|
||||
* @brief Set the Delegate object for the tab. It will apply for all
|
||||
* models residing in this tab object
|
||||
*
|
||||
* @param column the column to set the delegate for. It will apply for all models
|
||||
* residing inside this tab object
|
||||
* @param createDelegate the callback for the delegate creation
|
||||
*
|
||||
* @see ATapCreateDelegate
|
||||
*/
|
||||
void setDelegate(int column, ATapCreateDelegate createDelegate);
|
||||
void setDelegate(ATapCreateDelegate createDelegate);
|
||||
|
||||
/**
|
||||
* @brief Set the filter or remove it by providing an empty filter
|
||||
|
@ -221,7 +220,7 @@ private:
|
|||
QList<int> _allProtocols;
|
||||
QMap<int, int> _tabs;
|
||||
ATapModelCallback _createModel;
|
||||
QMap<int, ATapCreateDelegate> _createDelegates;
|
||||
ATapCreateDelegate _createDelegate;
|
||||
GList ** _recentColumnList;
|
||||
|
||||
bool _disableTaps;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QTreeView>
|
||||
#include <QMenu>
|
||||
#include <QHeaderView>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <QWidgetAction>
|
||||
#include <QLineEdit>
|
||||
|
|
Loading…
Reference in New Issue