wireshark/ui/qt/models/timeline_delegate.cpp

129 lines
5.0 KiB
C++
Raw Normal View History

/* timeline_delegate.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <ui/qt/models/timeline_delegate.h>
#include <ui/qt/models/atap_data_model.h>
#include <ui/qt/utils/color_utils.h>
#include <QApplication>
#include <QPainter>
#include <QTreeView>
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
2023-02-16 12:31:31 +00:00
#include <QAbstractProxyModel>
// XXX We might want to move this to conversation_dialog.cpp.
// PercentBarDelegate uses a stronger blend value, but its bars are also
// more of a prominent feature. Make the blend weaker here so that we don't
// obscure our text.
static const double bar_blend_ = 0.08;
TimelineDelegate::TimelineDelegate(QWidget *parent) :
QStyledItemDelegate(parent)
{
_dataRole = Qt::UserRole;
}
void TimelineDelegate::setDataRole(int dataRole)
{
_dataRole = dataRole;
}
void TimelineDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyleOptionViewItem option_vi = option;
QStyledItemDelegate::initStyleOption(&option_vi, index);
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
2023-02-16 12:31:31 +00:00
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;
QTreeView * tree = qobject_cast<QTreeView *>(parent());
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
2023-02-16 12:31:31 +00:00
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);
}
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
2023-02-16 12:31:31 +00:00
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;
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
2023-02-16 12:31:31 +00:00
if (index.column() == colStart) {
drawBar = true;
} else if (index.column() == colDuration) {
drawBar = true;
span_px.start -= start_px;
}
}
}
}
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
2023-02-16 12:31:31 +00:00
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.
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
2023-02-16 12:31:31 +00:00
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
// doesn't appear to be a more general way to do this.
option_vi.palette.setColor(QPalette::All, QPalette::HighlightedText,
option_vi.palette.color(QPalette::Active, QPalette::Text));
}
QPalette::ColorGroup cg = option_vi.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
QColor text_color = option_vi.palette.color(cg, QPalette::Text);
QColor bar_color = ColorUtils::alphaBlend(option_vi.palette.windowText(),
option_vi.palette.window(), bar_blend_);
if (cg == QPalette::Normal && !(option_vi.state & QStyle::State_Active))
cg = QPalette::Inactive;
if (option_vi.state & QStyle::State_Selected) {
text_color = option_vi.palette.color(cg, QPalette::HighlightedText);
bar_color = ColorUtils::alphaBlend(option_vi.palette.color(cg, QPalette::Window),
option_vi.palette.color(cg, QPalette::Highlight),
bar_blend_);
}
painter->save();
int border_radius = 3; // We use 3 px elsewhere, e.g. filter combos.
QRect timeline_rect = option.rect;
timeline_rect.adjust(span_px.start, 1, 0, -1);
timeline_rect.setWidth(span_px.width);
painter->setClipRect(option.rect);
painter->setPen(Qt::NoPen);
painter->setBrush(bar_color);
painter->drawRoundedRect(timeline_rect, border_radius, border_radius);
painter->restore();
painter->save();
painter->setPen(text_color);
painter->drawText(option.rect, Qt::AlignCenter, index.data(Qt::DisplayRole).toString());
painter->restore();
}