1/* This file is part of the KDE libraries
2 Copyright (C) 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
3 Copyright (C) 2005-2006 Hamish Rodda <rodda@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#ifndef KDELIBS_KTEXTEDITOR_CODECOMPLETIONMODEL_H
21#define KDELIBS_KTEXTEDITOR_CODECOMPLETIONMODEL_H
22
23#include <ktexteditor/ktexteditor_export.h>
24#include <QtCore/QModelIndex>
25#include <ktexteditor/range.h>
26
27namespace KTextEditor {
28
29class Document;
30class View;
31
32/**
33 * \short An item model for providing code completion, and meta information for
34 * enhanced presentation.
35 *
36 * \section compmodel_intro Introduction
37 *
38 * The CodeCompletionModel is the actual workhorse to provide code completions
39 * in a KTextEditor::View. It is meant to be used in conjunction with the
40 * CodeCompletionInterface. The CodeCompletionModel is not meant to be used as
41 * is. Rather you need to implement a subclass of CodeCompletionModel to actually
42 * generate completions appropriate for your type of Document.
43 *
44 * \section compmodel_implementing Implementing a CodeCompletionModel
45 *
46 * The CodeCompletionModel is a QAbstractItemModel, and can be subclassed in the
47 * same way. It provides default implementations of several members, however, so
48 * in most cases (if your completions are essentially a non-hierarchical, flat list
49 * of matches) you will only need to overload few virtual functions.
50 *
51 * \section compmodel_flatlist Implementing a CodeCompletionModel for a flat list
52 *
53 * For the simple case of a flat list of completions, you will need to:
54 * - Implement completionInvoked() to actually generate/update the list of completion
55 * matches
56 * - implement itemData() (or QAbstractItemModel::data()) to return the information that
57 * should be displayed for each match.
58 * - use setRowCount() to reflect the number of matches.
59 *
60 * \section compmodel_roles_columns Columns and roles
61 *
62 * \todo document the meaning and usage of the columns and roles used by the
63 * CodeCompletionInterface
64 *
65 * \section compmodel_usage Using the new CodeCompletionModel
66 *
67 * To start using your CodeCompletionModel, refer to CodeCompletionInterface.
68 *
69 * \section compmodel_controller ControllerInterface to get more control
70 *
71 * To have more control over code completion implement
72 * CodeCompletionModelControllerInterface in your CodeCompletionModel.
73 *
74 * \see CodeCompletionInterface, CodeCompletionModelControllerInterface
75 * @author Hamish Rodda <rodda@kde.org>
76 */
77class KTEXTEDITOR_EXPORT CodeCompletionModel : public QAbstractItemModel
78{
79 Q_OBJECT
80
81 public:
82 CodeCompletionModel(QObject* parent);
83 virtual ~CodeCompletionModel();
84
85 enum Columns {
86 Prefix = 0,
87 /// Icon representing the type of completion. We have a separate icon field
88 /// so that names remain aligned where only some completions have icons,
89 /// and so that they can be rearranged by the user.
90 Icon,
91 Scope,
92 Name,
93 Arguments,
94 Postfix
95 };
96 static const int ColumnCount = Postfix + 1;
97
98 enum CompletionProperty {
99 NoProperty = 0x0,
100 FirstProperty = 0x1,
101
102 // Access specifiers - no more than 1 per item
103 Public = 0x1,
104 Protected = 0x2,
105 Private = 0x4,
106
107 // Extra access specifiers - any number per item
108 Static = 0x8,
109 Const = 0x10,
110
111 // Type - no more than 1 per item (except for Template)
112 Namespace = 0x20,
113 Class = 0x40,
114 Struct = 0x80,
115 Union = 0x100,
116 Function = 0x200,
117 Variable = 0x400,
118 Enum = 0x800,
119 Template = 0x1000,
120 TypeAlias = 0x2000,
121
122 // Special attributes - any number per item
123 Virtual = 0x4000,
124 Override = 0x8000,
125 Inline = 0x10000,
126 Friend = 0x20000,
127 Signal = 0x40000,
128 Slot = 0x80000,
129
130 // Scope - no more than 1 per item
131 LocalScope = 0x100000,
132 NamespaceScope = 0x200000,
133 GlobalScope = 0x400000,
134
135 // Keep this in sync so the code knows when to stop
136 LastProperty = GlobalScope
137 };
138 Q_DECLARE_FLAGS(CompletionProperties, CompletionProperty)
139
140 enum HighlightMethod {
141 NoHighlighting = 0x0,
142 InternalHighlighting = 0x1,
143 CustomHighlighting = 0x2
144 };
145 Q_DECLARE_FLAGS(HighlightMethods, HighlightMethod)
146
147 /// Meta information is passed through extra {Qt::ItemDataRole}s.
148 /// This information should be returned when requested on the Name column.
149 enum ExtraItemDataRoles {
150 /// The model should return a set of CompletionProperties.
151 CompletionRole = Qt::UserRole,
152
153 /// The model should return an index to the scope
154 /// -1 represents no scope
155 /// \todo how to sort scope?
156 ScopeIndex,
157
158 /**
159 * If requested, your model should try to determine whether the
160 * completion in question is a suitable match for the context (ie.
161 * is accessible, exported, + returns the data type required).
162 *
163 * The returned data should ideally be matched against the argument-hint context
164 * set earlier by SetMatchContext.
165 *
166 * Return an integer value that should be positive if the completion is suitable,
167 * and zero if the completion is not suitable. The value should be between 0 an 10, where
168 * 10 means perfect match.
169 *
170 * Return QVariant::Invalid if you are unable to determine this.
171 */
172 MatchQuality,
173
174 /**
175 * Is requested before MatchQuality(..) is requested. The item on which this is requested
176 * is an argument-hint item(@see ArgumentHintDepth). When this role is requested, the item should
177 * be noted, and whenever MatchQuality is requested, it should be computed by matching the item given
178 * with MatchQuality into the context chosen by SetMatchContext.
179 *
180 * Feel free to ignore this, but ideally you should return QVariant::Invalid to make clear that your model does not support this.
181 * */
182 SetMatchContext,
183
184 /**
185 * Define which highlighting method will be used:
186 * - QVariant::Invalid - allows the editor to choose (usually internal highlighting)
187 * - QVariant::Integer - highlight as specified by HighlightMethods.
188 */
189 HighlightingMethod,
190
191 /**
192 * Allows an item to provide custom highlighting. Return a
193 * QList\<QVariant\> in the following format:
194 * - int startColumn (where 0 = start of the completion entry)
195 * - int endColumn (note: not length)
196 * - QTextFormat attribute (note: attribute may be a KTextEditor::Attribute, as it is a child class)
197 * If the attribute is invalid, and the item is an argument-hint, the text will be drawn with
198 * a background-color depending on match-quality, or yellow.
199 * You can use that to mark the actual arguments that are matched in an argument-hint.
200 *
201 * Repeat this triplet as many times as required, however each column must be >= the previous,
202 * and startColumn != endColumn.
203 */
204 CustomHighlight,
205
206 /**
207 * Returns the inheritance depth of the completion. For example, a completion
208 * which comes from the base class would have depth 0, one from a parent class
209 * would have depth 1, one from that class' parent 2, etc. you can use this to
210 * symbolize the general distance of a completion-item from a user. It will be used
211 * for sorting.
212 */
213 InheritanceDepth,
214
215 /**
216 * This allows items in the completion-list to be expandable. If a model returns an QVariant bool value
217 * that evaluates to true, the completion-widget will draw a handle to expand the item, and will also make
218 * that action accessible through keyboard.
219 */
220 IsExpandable,
221 /**
222 * After a model returned true for a row on IsExpandable, the row may be expanded by the user.
223 * When this happens, ExpandingWidget is requested.
224 *
225 * The model may return two types of values:
226 * QWidget*:
227 * If the model returns a QVariant of type QWidget*, the code-completion takes over the given widget
228 * and embeds it into the completion-list under the completion-item. The widget will be automatically deleted at some point.
229 * The completion-widget will use the height of the widget as a hint for its preferred size, but it will
230 * resize the widget at will.
231 * QString:
232 * If the mode returns a QVariant of type QString, it will create a small html-widget showing the given html-code,
233 * and embed it into the completion-list under the completion-item.
234 *
235 * Warning:
236 * QWidget* widget;
237 * return QVariant(widget);
238 * Will not work correctly!
239 * Use the following instead.:
240 * QVariant v;
241 * v.setValue<QWidget*>(widget);
242 * return v;
243 *
244 * */
245 ExpandingWidget,
246 /**
247 * Whenever an item is selected, this will be requested from the underlying model.
248 * It may be used as a simple notification that the item was selected.
249 *
250 * Above that, the model may return a QString, which then should then contain html-code. A html-widget
251 * will then be displayed as a one- or two-liner under the currently selected item(it will be partially expanded)
252 * */
253 ItemSelected,
254
255 /**Is this completion-item an argument-hint?
256 * The model should return an integral positive number if the item is an argument-hint, and QVariant() or 0 if it is not one.
257 *
258 * The returned depth-integer is important for sorting and matching.
259 * Example:
260 * "otherFunction(function1(function2("
261 * all functions named function2 should have ArgumentHintDepth 1, all functions found for function1 should have ArgumentHintDepth 2,
262 * and all functions named otherFunction should have ArgumentHintDepth 3
263 *
264 * Later, a completed item may then be matched with the first argument of function2, the return-type of function2 with the first
265 * argument-type of function1, and the return-type of function1 with the argument-type of otherFunction.
266 *
267 * If the model returns a positive value on this role for a row, the content will be treated specially:
268 * - It will be shown in a separate argument-hint list
269 * - It will be sorted by Argument-hint depth
270 * - Match-qualities will be illustrated by differently highlighting the matched argument if possible
271 * The argument-hint list strings will be built from all source-model, with a little special behavior:
272 * Prefix - Should be all text of the function-signature up to left of the matched argument of the function
273 * Name - Should be the type and name of the function's matched argument. This part will be highlighted differently depending on the match-quality
274 * Suffix - Should be all the text of the function-signature behind the matched argument
275 *
276 * Example: You are matching a function with signature "void test(int param1, int param2)", and you are matching the first argument.
277 * The model should then return:
278 * Prefix: "void test("
279 * Name: "int param1"
280 * Suffix: ", int param2)"
281 *
282 * If you don't use the highlighting, matching, etc. you can also return the columns in the usual way.
283 * */
284 ArgumentHintDepth,
285
286 /**
287 * This will be requested for each item to ask whether it should be included in computing a best-matches list.
288 * If you return a valid positive integer n here, the n best matches will be listed at top of the completion-list separately.
289 *
290 * This is expensive because all items of the whole completion-list will be tested for their matching-quality, with each of the level 1
291 * argument-hints.
292 *
293 * For that reason the end-user should be able to disable this feature.
294 */
295 BestMatchesCount,
296
297 /**
298 * The following three enumeration-values are only used on expanded completion-list items that contain an expanding-widget(@see ExpandingWidget)
299 *
300 * You can use them to allow the user to interact with the widget by keyboard.
301 *
302 * AccessibilityNext will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation
303 * short-cut to go to navigate to the next position within the expanding-widget(if applicable).
304 *
305 * Return QVariant(true) if the input was used.
306 * */
307 AccessibilityNext,
308 /**
309 * AccessibilityPrevious will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation
310 * short-cut to go to navigate to the previous position within the expanding-widget(if applicable).
311 *
312 * Return QVariant(true) if the input was used.
313 * */
314 AccessibilityPrevious,
315 /**
316 * AccessibilityAccept will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special
317 * shortcut to trigger the action associated with the position within the expanding-widget the user has navigated to using AccessibilityNext and AccessibilityPrevious.
318 *
319 * This should return QVariant(true) if an action was triggered, else QVariant(false) or QVariant().
320 * */
321 AccessibilityAccept,
322
323 /**
324 * Using this Role, it is possible to greatly optimize the time needed to process very long completion-lists.
325 *
326 * In the completion-list, the items are usually ordered by some properties like argument-hint depth,
327 * inheritance-depth and attributes. Kate usually has to query the completion-models for these values
328 * for each item in the completion-list in order to extract the argument-hints and correctly sort the
329 * completion-list. However, with a very long completion-list, only a very small fraction of the items is actually
330 * visible.
331 *
332 * By using a tree structure you can give the items in a grouped order to kate, so it does not need to look at each
333 * item and query data in order to initially show the completion-list.
334 *
335 * This is how it works:
336 * - You create a tree-structure for your items
337 * - Every inner node of the tree defines one attribute value that all sub-nodes have in common.
338 * - When the inner node is queried for GroupRole, it should return the "ExtraItemDataRoles" that all sub-nodes have in common
339 * - When the inner node is then queried for that exact role, it should return that value.
340 * - No other queries will be done to inner nodes.
341 * - Every leaf node stands for an actual item in the completion list.
342 *
343 * The recommended grouping order is: Argument-hint depth, inheritance depth, attributes.
344 *
345 * This role can also be used to define completely custom groups, bypassing the editors builtin grouping:
346 * - Return Qt::DisplayRole when GroupRole is requested
347 * - Return the lable text of the group when Qt::DisplayRole
348 * - Optional: Return an integer sorting-value when InheritanceDepth is requested. This number will
349 * be used to determine the order of the groups. The order of the builtin groups is:
350 * 1 = Best Matches, 100 = Local Scope, 200 = Public, 300 = Protected, 400 = Private, 500 = Namespace, 600 = Global
351 * You can pick any arbitrary number to position your group relative to these builtin groups.
352 * */
353 GroupRole,
354
355 /**
356 * Return a nonzero value here to enforce sorting the item at the end of the list.
357 */
358 UnimportantItemRole,
359
360 LastExtraItemDataRole
361 };
362 // KDE5 remove
363 static const int LastItemDataRole = AccessibilityAccept;
364
365 void setRowCount(int rowCount);
366
367 enum InvocationType {
368 AutomaticInvocation,
369 UserInvocation,
370 ManualInvocation
371 };
372
373 /**
374 * This function is responsible to generating / updating the list of current
375 * completions. The default implementation does nothing.
376 *
377 * When implementing this function, remember to call setRowCount() (or implement
378 * rowCount()), and to generate the appropriate change notifications (for instance
379 * by calling QAbstractItemModel::reset()).
380 * @param view The view to generate completions for
381 * @param range The range of text to generate completions for
382 * @param invocationType How the code completion was triggered
383 * */
384 virtual void completionInvoked(KTextEditor::View* view, const KTextEditor::Range& range, InvocationType invocationType);
385 /**
386 * @deprecated This does not work if your model is hierarchical(@see GroupRole). Use CodeCompletionModel2::executeCompletionItem2 instead.
387 *
388 * This function is responsible for inserting a selected completion into the
389 * document. The default implementation replaces the text that the completions
390 * were based on with the Qt::DisplayRole of the Name column of the given match.
391 *
392 * @param document The document to insert the completion into
393 * @param word The Range that the completions are based on (what the user entered
394 * so far)
395 * @param row The row of the completion match to insert
396 * */
397 virtual void executeCompletionItem(Document* document, const Range& word, int row) const;
398
399 // Reimplementations
400 /**
401 * Reimplemented from QAbstractItemModel::columnCount(). The default implementation
402 * returns ColumnCount for all indices.
403 * */
404 virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
405 /**
406 * Reimplemented from QAbstractItemModel::index(). The default implementation
407 * returns a standard QModelIndex as long as the row and column are valid.
408 * */
409 virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
410 /**
411 * Reimplemented from QAbstractItemModel::itemData(). The default implementation
412 * returns a map with the QAbstractItemModel::data() for all roles that are used
413 * by the CodeCompletionInterface. You will need to reimplement either this
414 * function or QAbstractItemModel::data() in your CodeCompletionModel.
415 * */
416 virtual QMap<int, QVariant> itemData ( const QModelIndex & index ) const;
417 /**
418 * Reimplemented from QAbstractItemModel::parent(). The default implementation
419 * returns an invalid QModelIndex for all items. This is appropriate for
420 * non-hierarchical / flat lists of completions.
421 * */
422 virtual QModelIndex parent ( const QModelIndex & index ) const;
423 /**
424 * Reimplemented from QAbstractItemModel::rowCount(). The default implementation
425 * returns the value set by setRowCount() for invalid (toplevel) indices, and 0
426 * for all other indices. This is appropriate for non-hierarchical / flat lists
427 * of completions
428 * */
429 virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
430
431 /**
432 * This function returns true if the model needs grouping, otherwise false
433 * in KDE 4 default value is true, in KDE 5 the default will be false
434 * TODO KDE 5
435 */
436 bool hasGroups() const;
437
438 Q_SIGNALS:
439
440 /**
441 * Emit this if the code-completion for this model was invoked, some time is needed in order to get the data,
442 * and the model is reset once the data is available.
443 *
444 * This only has an effect if emitted from within completionInvoked(..).
445 *
446 * This prevents the code-completion list from showing until this model is reset,
447 * so there is no annoying flashing in the user-interface resulting from other models
448 * supplying their data earlier.
449 *
450 * @note The implementation may choose to show the completion-list anyway after some timeout
451 *
452 * @warning If you emit this, you _must_ also reset the model at some point,
453 * else the code-completion will be completely broken to the user.
454 * Consider that there may always be additional completion-models apart from yours.
455 *
456 * @since KDE 4.3
457 */
458 void waitForReset();
459
460 /**
461 * Internal
462 */
463 void hasGroupsChanged(KTextEditor::CodeCompletionModel *model,bool hasGroups);
464
465 protected:
466 void setHasGroups(bool hasGroups);
467
468 private:
469 class CodeCompletionModelPrivate* const d;
470};
471
472/**
473 * You must inherit your completion-model from CodeCompletionModel2 if you want to
474 * use a hierarchical structure and want to receive execution-feedback.
475 * @see CodeCompletionModel::GroupRole
476 * */
477class KTEXTEDITOR_EXPORT CodeCompletionModel2 : public CodeCompletionModel {
478 Q_OBJECT
479 public:
480 CodeCompletionModel2(QObject* parent);
481 /**
482 * This function is responsible for inserting a selected completion into the
483 * document. The default implementation replaces the text that the completions
484 * were based on with the Qt::DisplayRole of the Name column of the given match.
485 *
486 * @param document the document to insert the completion into
487 * @param word the Range that the completions are based on (what the user entered
488 * so far)
489 * @param index identifies the completion match to insert
490 * */
491 virtual void executeCompletionItem2(Document* document, const Range& word, const QModelIndex& index) const;
492};
493
494Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::CompletionProperties)
495Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::HighlightMethods)
496
497}
498
499#endif // KDELIBS_KTEXTEDITOR_CODECOMPLETIONMODEL_H
500