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"