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 | |
27 | namespace KTextEditor { |
28 | |
29 | class Document; |
30 | class 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 | */ |
77 | class 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 { |
150 | /// The model should return a set of CompletionProperties. |
151 | = 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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
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 | , |
354 | |
355 | /** |
356 | * Return a nonzero value here to enforce sorting the item at the end of the list. |
357 | */ |
358 | , |
359 | |
360 | |
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 | * */ |
477 | class 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 | |
494 | Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::CompletionProperties) |
495 | Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::HighlightMethods) |
496 | |
497 | } |
498 | |
499 | #endif // KDELIBS_KTEXTEDITOR_CODECOMPLETIONMODEL_H |
500 | |