File indexing completed on 2024-04-21 03:57:51

0001 /*
0002     SPDX-FileCopyrightText: 2017-18 Friedrich W. H. Kossebau <kossebau@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kateannotationitemdelegate.h"
0008 
0009 #include <ktexteditor/annotationinterface.h>
0010 #include <ktexteditor/view.h>
0011 
0012 #include <QHelpEvent>
0013 #include <QPainter>
0014 #include <QToolTip>
0015 
0016 #include <math.h>
0017 
0018 KateAnnotationItemDelegate::KateAnnotationItemDelegate(QObject *parent)
0019     : KTextEditor::AbstractAnnotationItemDelegate(parent)
0020     , m_cachedDataContentFontMetrics(QFont())
0021 {
0022 }
0023 
0024 KateAnnotationItemDelegate::~KateAnnotationItemDelegate() = default;
0025 
0026 void KateAnnotationItemDelegate::paint(QPainter *painter,
0027                                        const KTextEditor::StyleOptionAnnotationItem &option,
0028                                        KTextEditor::AnnotationModel *model,
0029                                        int line) const
0030 {
0031     Q_ASSERT(painter);
0032     Q_ASSERT(model);
0033     if (!painter || !model) {
0034         return;
0035     }
0036     // TODO: also test line for validity for sake of completeness?
0037 
0038     painter->save();
0039 
0040     const int margin = 3;
0041 
0042     const QVariant background = model->data(line, Qt::BackgroundRole);
0043     // Fill the background
0044     if (background.isValid()) {
0045         painter->fillRect(option.rect, background.value<QBrush>());
0046     }
0047 
0048     const QVariant foreground = model->data(line, Qt::ForegroundRole);
0049     // Set the pen for drawing the foreground
0050     if (foreground.isValid() && foreground.canConvert<QPen>()) {
0051         painter->setPen(foreground.value<QPen>());
0052     }
0053 
0054     // Draw a border around all adjacent entries that have the same text as the currently hovered one
0055     if ((option.state & QStyle::State_MouseOver) && (option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::InGroup)) {
0056         // Use floating point coordinates to support scaled rendering
0057         QRectF rect(option.rect);
0058         rect.adjust(0.5, 0.5, -0.5, -0.5);
0059 
0060         // draw left and right highlight borders
0061         painter->drawLine(rect.topLeft(), rect.bottomLeft());
0062         painter->drawLine(rect.topRight(), rect.bottomRight());
0063 
0064         if ((option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::GroupBegin) && (option.wrappedLine == 0)) {
0065             painter->drawLine(rect.topLeft(), rect.topRight());
0066         }
0067 
0068         if ((option.annotationItemGroupingPosition & KTextEditor::StyleOptionAnnotationItem::GroupEnd)
0069             && (option.wrappedLine == (option.wrappedLineCount - 1))) {
0070             painter->drawLine(rect.bottomLeft(), rect.bottomRight());
0071         }
0072     }
0073     // reset pen
0074     if (foreground.isValid()) {
0075         QPen pen = painter->pen();
0076         pen.setWidth(1);
0077         painter->setPen(pen);
0078     }
0079 
0080     // Now draw the normal text
0081     const QVariant text = model->data(line, Qt::DisplayRole);
0082     if ((option.wrappedLine == 0) && text.isValid() && text.canConvert<QString>()) {
0083         painter->drawText(option.rect.x() + margin,
0084                           option.rect.y(),
0085                           option.rect.width() - 2 * margin,
0086                           option.rect.height(),
0087                           Qt::AlignLeft | Qt::AlignVCenter,
0088                           text.toString());
0089     }
0090 
0091     painter->restore();
0092 }
0093 
0094 bool KateAnnotationItemDelegate::helpEvent(QHelpEvent *event,
0095                                            KTextEditor::View *view,
0096                                            const KTextEditor::StyleOptionAnnotationItem &option,
0097                                            KTextEditor::AnnotationModel *model,
0098                                            int line)
0099 {
0100     Q_UNUSED(option);
0101 
0102     if (!model || event->type() != QEvent::ToolTip) {
0103         return false;
0104     }
0105 
0106     const QVariant data = model->data(line, Qt::ToolTipRole);
0107     if (!data.isValid()) {
0108         return false;
0109     }
0110 
0111     const QString toolTipText = data.toString();
0112     if (toolTipText.isEmpty()) {
0113         return false;
0114     }
0115 
0116     QToolTip::showText(event->globalPos(), toolTipText, view, option.rect);
0117 
0118     return true;
0119 }
0120 
0121 void KateAnnotationItemDelegate::hideTooltip(KTextEditor::View *view)
0122 {
0123     Q_UNUSED(view);
0124     QToolTip::hideText();
0125 }
0126 
0127 QSize KateAnnotationItemDelegate::sizeHint(const KTextEditor::StyleOptionAnnotationItem &option, KTextEditor::AnnotationModel *model, int line) const
0128 {
0129     Q_ASSERT(model);
0130     if (!model) {
0131         return QSize(0, 0);
0132     }
0133 
0134     // recalculate m_maxCharWidth if needed
0135     if (m_maxCharWidth == 0.0 || (option.contentFontMetrics != m_cachedDataContentFontMetrics)) {
0136         // based on old code written when just a hash was shown, could see an update
0137         // Loop to determine the widest numeric character in the current font.
0138         m_maxCharWidth = 0.0;
0139         for (char c = '0'; c <= '9'; ++c) {
0140             const qreal charWidth = ceil(option.contentFontMetrics.horizontalAdvance(QLatin1Char(c)));
0141             m_maxCharWidth = qMax(m_maxCharWidth, charWidth);
0142         }
0143 
0144         m_cachedDataContentFontMetrics = option.contentFontMetrics;
0145     }
0146 
0147     const QString annotationText = model->data(line, Qt::DisplayRole).toString();
0148     return QSize(annotationText.length() * m_maxCharWidth + 8, option.contentFontMetrics.height());
0149 }