File indexing completed on 2024-04-28 04:38:53

0001 /*
0002     SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de>
0003     SPDX-FileCopyrightText: 2010 Julien Desgats <julien.desgats@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "grepoutputdelegate.h"
0009 #include "grepoutputmodel.h"
0010 
0011 #include <QPainter>
0012 #include <QModelIndex>
0013 #include <QTextDocument>
0014 #include <QTextCursor>
0015 #include <QAbstractTextDocumentLayout>
0016 #include <QTextCharFormat>
0017 #include <QRegExp>
0018 #include <KLocalizedString>
0019 #include <cmath>
0020 #include <algorithm>
0021 
0022 GrepOutputDelegate* GrepOutputDelegate::m_self = nullptr;
0023 
0024 GrepOutputDelegate* GrepOutputDelegate::self()
0025 {
0026     Q_ASSERT(m_self);
0027     return m_self;
0028 }
0029 
0030 GrepOutputDelegate::GrepOutputDelegate( QObject* parent )
0031     : QStyledItemDelegate(parent)
0032 {
0033     Q_ASSERT(!m_self);
0034     m_self = this;
0035 }
0036 
0037 GrepOutputDelegate::~GrepOutputDelegate()
0038 {
0039     m_self = nullptr;
0040 }
0041 
0042 void GrepOutputDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
0043 { 
0044     // there is no function in QString to left-trim. A call to remove this regexp does the job
0045     static const QRegExp leftspaces(QStringLiteral("^\\s*"), Qt::CaseSensitive, QRegExp::RegExp);
0046     
0047     // rich text component
0048     const auto* model = qobject_cast<const GrepOutputModel*>(index.model());
0049     const auto  *item  = dynamic_cast<const GrepOutputItem *>(model->itemFromIndex(index));
0050 
0051     QStyleOptionViewItem options = option;
0052     initStyleOption(&options, index);
0053 
0054     // building item representation
0055     QTextDocument doc;
0056     QTextCursor cur(&doc);
0057     
0058     QPalette::ColorGroup cg = (options.state & QStyle::State_Enabled)
0059                                 ? QPalette::Normal : QPalette::Disabled;
0060     QPalette::ColorRole cr  = (options.state & QStyle::State_Selected)
0061                                 ? QPalette::HighlightedText : QPalette::Text;
0062     QTextCharFormat fmt = cur.charFormat();
0063     fmt.setFont(options.font);
0064 
0065     if(item && item->isText())
0066     {
0067         // Use custom manual highlighting
0068 
0069         const KTextEditor::Range rng = item->change()->m_range;
0070 
0071         // the line number appears grayed
0072         fmt.setForeground(options.palette.brush(QPalette::Disabled, cr));
0073         cur.insertText(i18n("Line %1: ",item->lineNumber()), fmt);
0074         
0075         // switch to normal color
0076         fmt.setForeground(options.palette.brush(cg, cr));
0077         cur.insertText(item->text().left(rng.start().column()).remove(leftspaces), fmt);
0078         
0079         fmt.setFontWeight(QFont::Bold);
0080         if ( !(options.state & QStyle::State_Selected) ) {
0081             QColor bgHighlight = option.palette.color(QPalette::AlternateBase);
0082             fmt.setBackground(bgHighlight);
0083         }
0084         cur.insertText(item->text().mid(rng.start().column(), rng.end().column() - rng.start().column()), fmt);
0085         fmt.clearBackground();
0086         
0087         fmt.setFontWeight(QFont::Normal);
0088         cur.insertText(item->text().mid(rng.end().column()), fmt);
0089     }else{
0090         QString text;
0091         if(item)
0092             text = item->text();
0093         else
0094             text = index.data().toString();
0095         // Simply insert the text as html. We use this for the titles.
0096         doc.setHtml(text);
0097     }
0098     
0099     painter->save();
0100     options.text = QString();  // text will be drawn separately
0101     options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget);
0102 
0103     // set correct draw area
0104     QRect clip = options.widget->style()->subElementRect(QStyle::SE_ItemViewItemText, &options);
0105     QFontMetrics metrics(options.font);
0106     painter->translate(clip.topLeft() - QPoint(0, metrics.descent()));
0107 
0108     // We disable the clipping for now, as it leads to strange clipping errors
0109 //     clip.setTopLeft(QPoint(0,0));
0110     
0111 //     painter->setClipRect(clip);
0112     QAbstractTextDocumentLayout::PaintContext ctx;
0113 //     ctx.clip = clip;
0114     painter->setBackground(Qt::transparent);
0115     doc.documentLayout()->draw(painter, ctx);
0116 
0117     painter->restore();
0118 }
0119 
0120 QSize GrepOutputDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
0121 {
0122     const auto* model = qobject_cast<const GrepOutputModel*>(index.model());
0123     const GrepOutputItem  *item  = model ? dynamic_cast<const GrepOutputItem *>(model->itemFromIndex(index)) : nullptr;
0124 
0125     QSize ret = QStyledItemDelegate::sizeHint(option, index);
0126 
0127     //take account of additional width required for highlighting (bold text)
0128     //and line numbers. These are not included in the default Qt size calculation.
0129     if(item && item->isText())
0130     {
0131         QFont font = option.font;
0132         QFontMetrics metrics(font);
0133         font.setBold(true);
0134         QFontMetrics bMetrics(font);
0135         const KTextEditor::Range rng = item->change()->m_range;
0136         int width = metrics.horizontalAdvance(item->text().left(rng.start().column()))
0137             + metrics.horizontalAdvance(item->text().mid(rng.end().column()))
0138             + bMetrics.horizontalAdvance(
0139                 item->text().mid(rng.start().column(), rng.end().column() - rng.start().column()))
0140             + option.fontMetrics.horizontalAdvance(i18n("Line %1: ", item->lineNumber()))
0141             + std::max(option.decorationSize.width(), 0);
0142         ret.setWidth(width);
0143     }else{
0144         // This is only used for titles, so not very performance critical
0145         QString text;
0146         if(item)
0147             text = item->text();
0148         else
0149             text = index.data().toString();
0150         
0151         QTextDocument doc;
0152         doc.setDocumentMargin(0);
0153         doc.setHtml(text);
0154         QSize newSize = doc.size().toSize();
0155         if(newSize.height() > ret.height())
0156             ret.setHeight(newSize.height());
0157     }
0158     return ret;
0159 }
0160 
0161 #include "moc_grepoutputdelegate.cpp"