File indexing completed on 2024-04-14 03:55:02
0001 /* 0002 SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KATECOMPLETIONMODEL_H 0009 #define KATECOMPLETIONMODEL_H 0010 0011 #include <QAbstractProxyModel> 0012 #include <QList> 0013 #include <QPair> 0014 0015 #include <ktexteditor/codecompletionmodel.h> 0016 0017 #include "expandingtree/expandingwidgetmodel.h" 0018 #include <ktexteditor_export.h> 0019 0020 #include <set> 0021 0022 class KateCompletionWidget; 0023 class KateArgumentHintModel; 0024 namespace KTextEditor 0025 { 0026 class ViewPrivate; 0027 } 0028 class QWidget; 0029 class QTextEdit; 0030 class QTimer; 0031 class HierarchicalModelHandler; 0032 0033 /** 0034 * This class has the responsibility for filtering, sorting, and manipulating 0035 * code completion data provided by a CodeCompletionModel. 0036 * 0037 * @author Hamish Rodda <rodda@kde.org> 0038 */ 0039 class KateCompletionModel : public ExpandingWidgetModel 0040 { 0041 Q_OBJECT 0042 0043 public: 0044 enum InternalRole { 0045 IsNonEmptyGroup = KTextEditor::CodeCompletionModel::LastExtraItemDataRole + 1, 0046 }; 0047 0048 explicit KateCompletionModel(KateCompletionWidget *parent = nullptr); 0049 ~KateCompletionModel() override; 0050 0051 QList<KTextEditor::CodeCompletionModel *> completionModels() const; 0052 void clearCompletionModels(); 0053 KTEXTEDITOR_EXPORT void addCompletionModel(KTextEditor::CodeCompletionModel *model); 0054 KTEXTEDITOR_EXPORT void setCompletionModel(KTextEditor::CodeCompletionModel *model); 0055 void setCompletionModels(const QList<KTextEditor::CodeCompletionModel *> &models); 0056 KTEXTEDITOR_EXPORT void removeCompletionModel(KTextEditor::CodeCompletionModel *model); 0057 0058 KTextEditor::ViewPrivate *view() const; 0059 KateCompletionWidget *widget() const; 0060 0061 KTEXTEDITOR_EXPORT QString currentCompletion(KTextEditor::CodeCompletionModel *model) const; 0062 void setCurrentCompletion(QMap<KTextEditor::CodeCompletionModel *, QString> currentMatch); 0063 0064 int translateColumn(int sourceColumn) const; 0065 0066 /// Returns a common prefix for all current visible completion entries 0067 /// If there is no common prefix, extracts the next useful prefix for the selected index 0068 QString commonPrefix(QModelIndex selectedIndex) const; 0069 0070 void rowSelected(const QModelIndex &row) const; 0071 0072 bool indexIsItem(const QModelIndex &index) const override; 0073 0074 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0075 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 0076 Qt::ItemFlags flags(const QModelIndex &index) const override; 0077 bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; 0078 virtual bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const; 0079 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0080 0081 // Disabled in case of bugs, reenable once fully debugged. 0082 // virtual QMap<int, QVariant> itemData ( const QModelIndex & index ) const; 0083 QModelIndex parent(const QModelIndex &index) const override; 0084 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0085 0086 /// Maps from this display-model into the appropriate source code-completion model 0087 virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const; 0088 0089 /// Maps from an index in a source-model to the index of the item in this display-model 0090 virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; 0091 0092 enum gm { ScopeType = 0x1, Scope = 0x2, AccessType = 0x4, ItemType = 0x8 }; 0093 0094 enum { // An own property that will be used to mark the best-matches group internally 0095 BestMatchesProperty = 2 * KTextEditor::CodeCompletionModel::LastProperty 0096 }; 0097 0098 Q_DECLARE_FLAGS(GroupingMethods, gm) 0099 0100 static const int ScopeTypeMask = 0x380000; 0101 static const int AccessTypeMask = 0x7; 0102 static const int ItemTypeMask = 0xfe0; 0103 0104 void debugStats(); 0105 0106 /// Returns whether one of the filtered items exactly matches its completion string 0107 bool shouldMatchHideCompletionList() const; 0108 0109 KTEXTEDITOR_EXPORT uint filteredItemCount() const; 0110 0111 protected: 0112 int contextMatchQuality(const QModelIndex &index) const override; 0113 0114 Q_SIGNALS: 0115 void expandIndex(const QModelIndex &index); 0116 // Emitted whenever something has changed about the group of argument-hints 0117 void argumentHintsChanged(); 0118 0119 private Q_SLOTS: 0120 void slotRowsInserted(const QModelIndex &parent, int start, int end); 0121 void slotRowsRemoved(const QModelIndex &parent, int start, int end); 0122 void slotModelReset(); 0123 0124 // Updates the best-matches group 0125 void updateBestMatches(); 0126 // Makes sure that the ungrouped group contains each item only once 0127 // Must only be called right after the group was created 0128 void makeGroupItemsUnique(bool onlyFiltered = false); 0129 0130 private: 0131 typedef QPair<KTextEditor::CodeCompletionModel *, QModelIndex> ModelRow; 0132 virtual int contextMatchQuality(const ModelRow &sourceRow) const; 0133 0134 QTreeView *treeView() const override; 0135 0136 friend class KateArgumentHintModel; 0137 static ModelRow modelRowPair(const QModelIndex &index); 0138 0139 // Represents a source row; provides sorting method 0140 class Item 0141 { 0142 public: 0143 Item(bool doInitialMatch, KateCompletionModel *model, const HierarchicalModelHandler &handler, ModelRow sourceRow); 0144 0145 // Returns true if the item is not filtered and matches the current completion string 0146 bool isVisible() const; 0147 0148 enum MatchType { NoMatch = 0, PerfectMatch, StartsWithMatch, AbbreviationMatch, ContainsMatch }; 0149 MatchType match(KateCompletionModel *model); 0150 0151 const ModelRow &sourceRow() const; 0152 0153 // Sorting operator 0154 bool lessThan(KateCompletionModel *model, const Item &rhs) const; 0155 0156 bool haveExactMatch() const 0157 { 0158 return m_haveExactMatch; 0159 } 0160 0161 QString name() const 0162 { 0163 return m_nameColumn; 0164 } 0165 0166 private: 0167 ModelRow m_sourceRow; 0168 0169 QString m_nameColumn; 0170 0171 int inheritanceDepth; 0172 0173 // True when currently matching completion string 0174 MatchType matchCompletion; 0175 bool m_haveExactMatch; 0176 bool m_unimportant; 0177 }; 0178 0179 public: 0180 // Grouping and sorting of rows 0181 class Group 0182 { 0183 public: 0184 explicit Group(const QString &title, int attribute, KateCompletionModel *model); 0185 0186 void addItem(const Item &i, bool notifyModel = false); 0187 /// Removes the item specified by \a row. Returns true if a change was made to rows. 0188 bool removeItem(const ModelRow &row); 0189 void resort(); 0190 void clear(); 0191 // Returns whether this group should be ordered before other 0192 bool orderBefore(Group *other) const; 0193 // Returns a number that can be used for ordering 0194 int orderNumber() const; 0195 0196 /// Returns the row in the this group's filtered list of the given model-row in a source-model 0197 ///-1 if the item is not in the filtered list 0198 ///@todo Implement an efficient way of doing this map, that does _not_ iterate over all items! 0199 int rowOf(const ModelRow &item) 0200 { 0201 for (int a = 0; a < (int)filtered.size(); ++a) { 0202 if (filtered[a].sourceRow() == item) { 0203 return a; 0204 } 0205 } 0206 return -1; 0207 } 0208 0209 KateCompletionModel *model; 0210 int attribute; 0211 QString title, scope; 0212 std::vector<Item> filtered; 0213 std::vector<Item> prefilter; 0214 bool isEmpty; 0215 //-1 if none was set 0216 int customSortingKey; 0217 }; 0218 0219 typedef std::set<Group *> GroupSet; 0220 0221 bool hasGroups() const 0222 { 0223 // qCDebug(LOG_KTE) << "m_groupHash.size()"<<m_groupHash.size(); 0224 // qCDebug(LOG_KTE) << "m_rowTable.count()"<<m_rowTable.count(); 0225 return m_hasGroups; 0226 } 0227 0228 private: 0229 QString commonPrefixInternal(const QString &forcePrefix) const; 0230 /// @note performs model reset 0231 void createGroups(); 0232 /// Creates all sub-items of index i, or the item corresponding to index i. Returns the affected groups. 0233 /// i must be an index in the source model 0234 GroupSet createItems(const HierarchicalModelHandler &, const QModelIndex &i, bool notifyModel = false); 0235 /// Deletes all sub-items of index i, or the item corresponding to index i. Returns the affected groups. 0236 /// i must be an index in the source model 0237 GroupSet deleteItems(const QModelIndex &i); 0238 Group *createItem(const HierarchicalModelHandler &, const QModelIndex &i, bool notifyModel = false); 0239 /// @note Make sure you're in a {begin,end}ResetModel block when calling this! 0240 void clearGroups(); 0241 void hideOrShowGroup(Group *g, bool notifyModel = false); 0242 /// When forceGrouping is enabled, all given attributes will be used for grouping, regardless of the completion settings. 0243 Group *fetchGroup(int attribute, bool forceGrouping = false); 0244 // If this returns nonzero on an index, the index is the header of the returned group 0245 Group *groupForIndex(const QModelIndex &index) const; 0246 inline Group *groupOfParent(const QModelIndex &child) const 0247 { 0248 return static_cast<Group *>(child.internalPointer()); 0249 } 0250 QModelIndex indexForRow(Group *g, int row) const; 0251 QModelIndex indexForGroup(Group *g) const; 0252 0253 enum changeTypes { Broaden, Narrow, Change }; 0254 0255 // Returns whether the model needs to be reset 0256 void changeCompletions(Group *g); 0257 0258 bool hasCompletionModel() const; 0259 0260 /// Removes attributes not used in grouping from the input \a attribute 0261 int groupingAttributes(int attribute) const; 0262 static int countBits(int value); 0263 0264 void resort(); 0265 0266 KTEXTEDITOR_EXPORT static bool matchesAbbreviation(const QString &word, const QString &typed, int &score); 0267 // exported for completion_test 0268 0269 bool m_hasGroups = false; 0270 0271 // ### Runtime state 0272 // General 0273 QList<KTextEditor::CodeCompletionModel *> m_completionModels; 0274 QMap<KTextEditor::CodeCompletionModel *, QString> m_currentMatch; 0275 0276 // Column merging 0277 const std::array<std::vector<int>, 3> m_columnMerges = {{ 0278 {0}, 0279 {1, 2, 3, 4}, 0280 {5}, 0281 }}; 0282 0283 QTimer *m_updateBestMatchesTimer; 0284 0285 Group *m_ungrouped; 0286 Group *m_argumentHints; // The argument-hints will be passed on to another model, to be shown in another widget 0287 Group *m_bestMatches; // A temporary group used for holding the best matches of all visible items 0288 0289 // Storing the sorted order 0290 std::vector<Group *> m_rowTable; 0291 std::vector<Group *> m_emptyGroups; 0292 // Quick access to each specific group (if it exists) 0293 QMultiHash<int, Group *> m_groupHash; 0294 // Maps custom group-names to their specific groups 0295 QHash<QString, Group *> m_customGroupHash; 0296 0297 friend class CompletionTest; 0298 }; 0299 0300 Q_DECLARE_OPERATORS_FOR_FLAGS(KateCompletionModel::GroupingMethods) 0301 0302 #endif