File indexing completed on 2024-04-14 03:55:01

0001 /*
0002     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2022 Waqar Ahmed <waqar.17a@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "katecompletiondelegate.h"
0009 
0010 #include <ktexteditor/codecompletionmodel.h>
0011 
0012 #include "katecompletionmodel.h"
0013 #include "katepartdebug.h"
0014 
0015 #include <QApplication>
0016 #include <QPainter>
0017 
0018 KateCompletionDelegate::KateCompletionDelegate(QObject *parent)
0019     : QStyledItemDelegate(parent)
0020 {
0021 }
0022 
0023 static void paintItemViewText(QPainter *p, const QString &text, const QStyleOptionViewItem &options, QList<QTextLayout::FormatRange> formats)
0024 {
0025     // set formats
0026     QTextLayout textLayout(text, options.font, p->device());
0027     auto fmts = textLayout.formats();
0028     formats.append(fmts);
0029     textLayout.setFormats(formats);
0030 
0031     // set alignment, rtls etc
0032     QTextOption textOption;
0033     textOption.setTextDirection(options.direction);
0034     textOption.setAlignment(QStyle::visualAlignment(options.direction, options.displayAlignment));
0035     textLayout.setTextOption(textOption);
0036 
0037     // layout the text
0038     textLayout.beginLayout();
0039 
0040     QTextLine line = textLayout.createLine();
0041     if (!line.isValid())
0042         return;
0043 
0044     const int lineWidth = options.rect.width();
0045     line.setLineWidth(lineWidth);
0046     line.setPosition(QPointF(0, 0));
0047 
0048     textLayout.endLayout();
0049 
0050     int y = QStyle::alignedRect(Qt::LayoutDirectionAuto, options.displayAlignment, textLayout.boundingRect().size().toSize(), options.rect).y();
0051 
0052     // draw the text
0053     const auto pos = QPointF(options.rect.x(), y);
0054     textLayout.draw(p, pos);
0055 }
0056 
0057 void KateCompletionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o, const QModelIndex &index) const
0058 {
0059     QStyleOptionViewItem opt = o;
0060     initStyleOption(&opt, index);
0061     QString text = opt.text;
0062 
0063     if (text.isEmpty()) {
0064         QStyledItemDelegate::paint(painter, o, index);
0065         return;
0066     }
0067 
0068     auto *style = opt.widget->style() ? opt.widget->style() : qApp->style();
0069 
0070     opt.text.clear();
0071 
0072     style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
0073 
0074     QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget);
0075 
0076     const bool isGroup = index.data(KateCompletionModel::IsNonEmptyGroup).toBool();
0077     if (!isGroup && !opt.features.testFlag(QStyleOptionViewItem::HasDecoration)) {
0078         // 3 because 2 margins for the icon, and one left margin for the text
0079         int hMargins = style->pixelMetric(QStyle::PM_FocusFrameHMargin) * 3;
0080         textRect.adjust(hMargins + opt.decorationSize.width(), 0, 0, 0);
0081     }
0082 
0083 #if 0
0084     auto p = painter->pen();
0085     painter->setPen(Qt::yellow);
0086     painter->drawRect(opt.rect);
0087 
0088     painter->setPen(Qt::red);
0089     painter->drawRect(textRect);
0090     painter->setPen(p);
0091 #endif
0092 
0093     auto highlightings = createHighlighting(index);
0094     opt.rect = textRect;
0095     opt.displayAlignment = m_alignTop ? Qt::AlignTop : Qt::AlignVCenter;
0096     paintItemViewText(painter, text, opt, std::move(highlightings));
0097 }
0098 
0099 QSize KateCompletionDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0100 {
0101     if (index.data().toString().isEmpty()) {
0102         return QStyledItemDelegate::sizeHint(option, index);
0103     }
0104 
0105     QSize size = QStyledItemDelegate::sizeHint(option, index);
0106     if (!index.data(Qt::DecorationRole).isNull()) {
0107         return size;
0108     }
0109     const int hMargins = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) * 3;
0110     size.rwidth() += option.decorationSize.width() + hMargins;
0111     return size;
0112 }
0113 
0114 static QList<QTextLayout::FormatRange> highlightingFromVariantList(const QList<QVariant> &customHighlights)
0115 {
0116     QList<QTextLayout::FormatRange> ret;
0117 
0118     for (int i = 0; i + 2 < customHighlights.count(); i += 3) {
0119         if (!customHighlights[i].canConvert<int>() || !customHighlights[i + 1].canConvert<int>() || !customHighlights[i + 2].canConvert<QTextFormat>()) {
0120             qCWarning(LOG_KTE) << "Unable to convert triple to custom formatting.";
0121             continue;
0122         }
0123 
0124         QTextLayout::FormatRange format;
0125         format.start = customHighlights[i].toInt();
0126         format.length = customHighlights[i + 1].toInt();
0127         format.format = customHighlights[i + 2].value<QTextFormat>().toCharFormat();
0128 
0129         if (!format.format.isValid()) {
0130             qCWarning(LOG_KTE) << "Format is not valid";
0131         }
0132 
0133         ret << format;
0134     }
0135     return ret;
0136 }
0137 
0138 QList<QTextLayout::FormatRange> KateCompletionDelegate::createHighlighting(const QModelIndex &index)
0139 {
0140     QVariant highlight = index.data(KTextEditor::CodeCompletionModel::HighlightingMethod);
0141 
0142     // TODO: config enable specifying no highlight as default
0143     int highlightMethod = KTextEditor::CodeCompletionModel::InternalHighlighting;
0144     if (highlight.canConvert<int>()) {
0145         highlightMethod = highlight.toInt();
0146     }
0147 
0148     if (highlightMethod & KTextEditor::CodeCompletionModel::CustomHighlighting) {
0149         return highlightingFromVariantList(index.data(KTextEditor::CodeCompletionModel::CustomHighlight).toList());
0150     }
0151 
0152     return {};
0153 }