1 /*
2     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "katecompletiondelegate.h"
8 
9 #include <ktexteditor/codecompletionmodel.h>
10 
11 #include "katedocument.h"
12 #include "katehighlight.h"
13 #include "katepartdebug.h"
14 #include "katerenderer.h"
15 #include "katerenderrange.h"
16 #include "katetextline.h"
17 #include "kateview.h"
18 
19 #include "katecompletionmodel.h"
20 #include "katecompletiontree.h"
21 #include "katecompletionwidget.h"
22 
23 // Currently disable because it doesn't work
24 #define DISABLE_INTERNAL_HIGHLIGHTING
25 
KateCompletionDelegate(ExpandingWidgetModel * model,KateCompletionWidget * parent)26 KateCompletionDelegate::KateCompletionDelegate(ExpandingWidgetModel *model, KateCompletionWidget *parent)
27     : ExpandingDelegate(model, parent)
28     , m_cachedRow(-1)
29 {
30 }
31 
adjustStyle(const QModelIndex & index,QStyleOptionViewItem & option) const32 void KateCompletionDelegate::adjustStyle(const QModelIndex &index, QStyleOptionViewItem &option) const
33 {
34     if (index.column() == 0) {
35         // We always want to use the match-color if available, also for highlighted items.
36         ///@todo Only do this for the "current" item, for others the model is asked for the match color.
37         uint color = model()->matchColor(index);
38         if (color != 0) {
39             QColor match(color);
40 
41             for (int a = 0; a <= 2; a++) {
42                 option.palette.setColor((QPalette::ColorGroup)a, QPalette::Highlight, match);
43             }
44         }
45     }
46 }
47 
renderer() const48 KateRenderer *KateCompletionDelegate::renderer() const
49 {
50     return widget()->view()->renderer();
51 }
52 
widget() const53 KateCompletionWidget *KateCompletionDelegate::widget() const
54 {
55     return static_cast<KateCompletionWidget *>(const_cast<QObject *>(parent()));
56 }
57 
document() const58 KTextEditor::DocumentPrivate *KateCompletionDelegate::document() const
59 {
60     return widget()->view()->doc();
61 }
62 
heightChanged() const63 void KateCompletionDelegate::heightChanged() const
64 {
65     if (parent()) {
66         widget()->updateHeight();
67     }
68 }
69 
createHighlighting(const QModelIndex & index,QStyleOptionViewItem & option) const70 QVector<QTextLayout::FormatRange> KateCompletionDelegate::createHighlighting(const QModelIndex &index, QStyleOptionViewItem &option) const
71 {
72     QVariant highlight = model()->data(index, KTextEditor::CodeCompletionModel::HighlightingMethod);
73 
74     // TODO: config enable specifying no highlight as default
75     int highlightMethod = KTextEditor::CodeCompletionModel::InternalHighlighting;
76     if (highlight.canConvert(QVariant::Int)) {
77         highlightMethod = highlight.toInt();
78     }
79 
80     if (highlightMethod & KTextEditor::CodeCompletionModel::CustomHighlighting) {
81         m_currentColumnStart = 0;
82         return highlightingFromVariantList(model()->data(index, KTextEditor::CodeCompletionModel::CustomHighlight).toList());
83     }
84 
85 #ifdef DISABLE_INTERNAL_HIGHLIGHTING
86     return QVector<QTextLayout::FormatRange>();
87 #endif
88 
89     if (index.row() == m_cachedRow && highlightMethod & KTextEditor::CodeCompletionModel::InternalHighlighting) {
90         if (index.column() < m_cachedColumnStarts.size()) {
91             m_currentColumnStart = m_cachedColumnStarts[index.column()];
92         } else {
93             qCWarning(LOG_KTE) << "Column-count does not match";
94         }
95 
96         return m_cachedHighlights;
97     }
98 
99     ///@todo reset the cache when the model changed
100     m_cachedRow = index.row();
101 
102     KTextEditor::Cursor completionStart = widget()->completionRange()->start();
103 
104     QString startText = document()->text(KTextEditor::Range(completionStart.line(), 0, completionStart.line(), completionStart.column()));
105 
106     QString lineContent = startText;
107 
108     int len = completionStart.column();
109     m_cachedColumnStarts.clear();
110 
111     for (int i = 0; i < KTextEditor::CodeCompletionModel::ColumnCount; ++i) {
112         m_cachedColumnStarts.append(len);
113         QString text = model()->data(model()->index(index.row(), i, index.parent()), Qt::DisplayRole).toString();
114         lineContent += text;
115         len += text.length();
116     }
117 
118     Kate::TextLine thisLine = Kate::TextLine(new Kate::TextLineData(lineContent));
119 
120     // qCDebug(LOG_KTE) << "About to highlight with mode " << highlightMethod << " text [" << thisLine->string() << "]";
121 
122     if (highlightMethod & KTextEditor::CodeCompletionModel::InternalHighlighting) {
123         Kate::TextLine previousLine;
124         if (completionStart.line()) {
125             previousLine = document()->kateTextLine(completionStart.line() - 1);
126         } else {
127             previousLine = Kate::TextLine(new Kate::TextLineData());
128         }
129 
130         Kate::TextLine nextLine;
131         if ((completionStart.line() + 1) < document()->lines()) {
132             nextLine = document()->kateTextLine(completionStart.line() + 1);
133         } else {
134             nextLine = Kate::TextLine(new Kate::TextLineData());
135         }
136 
137         bool ctxChanged = false;
138         document()->highlight()->doHighlight(previousLine.data(), thisLine.data(), nextLine.data(), ctxChanged);
139     }
140 
141     m_currentColumnStart = m_cachedColumnStarts[index.column()];
142 
143     QVector<QTextLayout::FormatRange> ret = renderer()->decorationsForLine(thisLine, 0, false, true, option.state & QStyle::State_Selected);
144 
145     // Remove background-colors
146     for (QVector<QTextLayout::FormatRange>::iterator it = ret.begin(); it != ret.end(); ++it) {
147         (*it).format.clearBackground();
148     }
149 
150     return ret;
151 }
152