1/*
2 SPDX-FileCopyrightText: 2017-18 Friedrich W. H. Kossebau <kossebau@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "kateannotationitemdelegate.h"
8
9#include <ktexteditor/annotationinterface.h>
10#include <ktexteditor/view.h>
11
12#include <QHelpEvent>
13#include <QPainter>
14#include <QToolTip>
15
16#include <math.h>
17
18KateAnnotationItemDelegate::KateAnnotationItemDelegate(QObject *parent)
19 : KTextEditor::AbstractAnnotationItemDelegate(parent)
20 , m_cachedDataContentFontMetrics(QFont())
21{
22}
23
24KateAnnotationItemDelegate::~KateAnnotationItemDelegate() = default;
25
26void KateAnnotationItemDelegate::paint(QPainter *painter,
27 const KTextEditor::StyleOptionAnnotationItem &option,
28 KTextEditor::AnnotationModel *model,
29 int line) const
30{
31 Q_ASSERT(painter);
32 Q_ASSERT(model);
33 if (!painter || !model) {
34 return;
35 }
36 // TODO: also test line for validity for sake of completeness?
37
38 painter->save();
39
40 const int margin = 3;
41
42 const QVariant background = model->data(line, role: Qt::BackgroundRole);
43 // Fill the background
44 if (background.isValid()) {
45 painter->fillRect(option.rect, background.value<QBrush>());
46 }
47
48 const QVariant foreground = model->data(line, role: Qt::ForegroundRole);
49 // Set the pen for drawing the foreground
50 if (foreground.isValid() && foreground.canConvert<QPen>()) {
51 painter->setPen(foreground.value<QPen>());
52 }
53
54 // Draw a border around all adjacent entries that have the same text as the currently hovered one
55 if ((option.state & QStyle::State_MouseOver) && (option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::InGroup)) {
56 // Use floating point coordinates to support scaled rendering
57 QRectF rect(option.rect);
58 rect.adjust(xp1: 0.5, yp1: 0.5, xp2: -0.5, yp2: -0.5);
59
60 // draw left and right highlight borders
61 painter->drawLine(p1: rect.topLeft(), p2: rect.bottomLeft());
62 painter->drawLine(p1: rect.topRight(), p2: rect.bottomRight());
63
64 if ((option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::GroupBegin) && (option.wrappedLine == 0)) {
65 painter->drawLine(p1: rect.topLeft(), p2: rect.topRight());
66 }
67
68 if ((option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::GroupEnd)
69 && (option.wrappedLine == (option.wrappedLineCount - 1))) {
70 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
71 }
72 }
73 // reset pen
74 if (foreground.isValid()) {
75 QPen pen = painter->pen();
76 pen.setWidth(1);
77 painter->setPen(pen);
78 }
79
80 // Now draw the normal text
81 const QVariant text = model->data(line, role: Qt::DisplayRole);
82 if ((option.wrappedLine == 0) && text.isValid() && text.canConvert<QString>()) {
83 painter->drawText(x: option.rect.x() + margin,
84 y: option.rect.y(),
85 w: option.rect.width() - 2 * margin,
86 h: option.rect.height(),
87 flags: Qt::AlignLeft | Qt::AlignVCenter,
88 str: text.toString());
89 }
90
91 painter->restore();
92}
93
94bool KateAnnotationItemDelegate::helpEvent(QHelpEvent *event,
95 KTextEditor::View *view,
96 const KTextEditor::StyleOptionAnnotationItem &option,
97 KTextEditor::AnnotationModel *model,
98 int line)
99{
100 Q_UNUSED(option);
101
102 if (!model || event->type() != QEvent::ToolTip) {
103 return false;
104 }
105
106 const QVariant data = model->data(line, role: Qt::ToolTipRole);
107 if (!data.isValid()) {
108 return false;
109 }
110
111 const QString toolTipText = data.toString();
112 if (toolTipText.isEmpty()) {
113 return false;
114 }
115
116 QToolTip::showText(pos: event->globalPos(), text: toolTipText, w: view, rect: option.rect);
117
118 return true;
119}
120
121void KateAnnotationItemDelegate::hideTooltip(KTextEditor::View *view)
122{
123 Q_UNUSED(view);
124 QToolTip::hideText();
125}
126
127QSize KateAnnotationItemDelegate::sizeHint(const KTextEditor::StyleOptionAnnotationItem &option, KTextEditor::AnnotationModel *model, int line) const
128{
129 Q_ASSERT(model);
130 if (!model) {
131 return QSize(0, 0);
132 }
133
134 // recalculate m_maxCharWidth if needed
135 if (m_maxCharWidth == 0.0 || (option.contentFontMetrics != m_cachedDataContentFontMetrics)) {
136 // based on old code written when just a hash was shown, could see an update
137 // Loop to determine the widest numeric character in the current font.
138 m_maxCharWidth = 0.0;
139 for (char c = '0'; c <= '9'; ++c) {
140 const qreal charWidth = ceil(x: option.contentFontMetrics.horizontalAdvance(QLatin1Char(c)));
141 m_maxCharWidth = qMax(a: m_maxCharWidth, b: charWidth);
142 }
143
144 m_cachedDataContentFontMetrics = option.contentFontMetrics;
145 }
146
147 const QString annotationText = model->data(line, role: Qt::DisplayRole).toString();
148 return QSize(annotationText.length() * m_maxCharWidth + 8, option.contentFontMetrics.height());
149}
150

source code of ktexteditor/src/view/kateannotationitemdelegate.cpp