00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "katecompletionmodel.h"
00021
00022 #include <QTextEdit>
00023 #include <QMultiMap>
00024 #include <QTimer>
00025
00026 #include <klocale.h>
00027 #include <kiconloader.h>
00028 #include <kapplication.h>
00029
00030 #include "katecompletionwidget.h"
00031 #include "katecompletiontree.h"
00032 #include "katecompletiondelegate.h"
00033 #include "kateargumenthintmodel.h"
00034 #include "kateview.h"
00035 #include "katerenderer.h"
00036 #include "kateconfig.h"
00037 #include <ktexteditor/codecompletionmodelcontrollerinterface.h>
00038
00039 using namespace KTextEditor;
00040
00042 class HierarchicalModelHandler {
00043 public:
00044 HierarchicalModelHandler(CodeCompletionModel* model);
00045 void addValue(CodeCompletionModel::ExtraItemDataRoles role, const QVariant& value);
00046
00047 void collectRoles(const QModelIndex& index);
00048 void takeRole(const QModelIndex& index);
00049
00050 CodeCompletionModel* model() const;
00051
00052
00053 QVariant getData(CodeCompletionModel::ExtraItemDataRoles role, const QModelIndex& index) const;
00054
00055 bool hasHierarchicalRoles() const;
00056
00057 int inheritanceDepth(const QModelIndex& i) const;
00058
00059 QString customGroup() const {
00060 return m_customGroup;
00061 }
00062
00063 int customGroupingKey() const {
00064 return m_groupSortingKey;
00065 }
00066 private:
00067 typedef QMap<CodeCompletionModel::ExtraItemDataRoles, QVariant> RoleMap;
00068 RoleMap m_roleValues;
00069 QString m_customGroup;
00070 int m_groupSortingKey;
00071 CodeCompletionModel* m_model;
00072 };
00073
00074 CodeCompletionModel* HierarchicalModelHandler::model() const {
00075 return m_model;
00076 }
00077
00078 bool HierarchicalModelHandler::hasHierarchicalRoles() const {
00079 return !m_roleValues.isEmpty();
00080 }
00081
00082 void HierarchicalModelHandler::collectRoles(const QModelIndex& index) {
00083 if( index.parent().isValid() )
00084 collectRoles(index.parent());
00085 if(m_model->rowCount(index) != 0)
00086 takeRole(index);
00087 }
00088
00089 int HierarchicalModelHandler::inheritanceDepth(const QModelIndex& i) const {
00090 return getData(CodeCompletionModel::InheritanceDepth, i).toInt();
00091 }
00092
00093 void HierarchicalModelHandler::takeRole(const QModelIndex& index) {
00094 QVariant v = index.data(CodeCompletionModel::GroupRole);
00095 if( v.isValid() && v.canConvert(QVariant::Int) ) {
00096 QVariant value = index.data(v.toInt());
00097 if(v.toInt() == Qt::DisplayRole) {
00098 m_customGroup = index.data(Qt::DisplayRole).toString();
00099 QVariant sortingKey = index.data(CodeCompletionModel::InheritanceDepth);
00100 if(sortingKey.canConvert(QVariant::Int))
00101 m_groupSortingKey = sortingKey.toInt();
00102 }else{
00103 m_roleValues[(CodeCompletionModel::ExtraItemDataRoles)v.toInt()] = value;
00104 }
00105 }else{
00106 kDebug( 13035 ) << "Did not return valid GroupRole in hierarchical completion-model";
00107 }
00108 }
00109
00110 QVariant HierarchicalModelHandler::getData(CodeCompletionModel::ExtraItemDataRoles role, const QModelIndex& index) const {
00111 RoleMap::const_iterator it = m_roleValues.find(role);
00112 if( it != m_roleValues.end() )
00113 return *it;
00114 else
00115 return index.data(role);
00116 }
00117
00118 HierarchicalModelHandler::HierarchicalModelHandler(CodeCompletionModel* model) : m_groupSortingKey(-1), m_model(model) {
00119 }
00120
00121 void HierarchicalModelHandler::addValue(CodeCompletionModel::ExtraItemDataRoles role, const QVariant& value) {
00122 m_roleValues[role] = value;
00123 }
00124
00125 KateCompletionModel::KateCompletionModel(KateCompletionWidget* parent)
00126 : ExpandingWidgetModel(parent)
00127 , m_hasGroups(false)
00128 , m_matchCaseSensitivity(Qt::CaseInsensitive)
00129 , m_ungrouped(new Group(this))
00130 , m_argumentHints(new Group(this))
00131 , m_bestMatches(new Group(this))
00132 , m_sortingEnabled(false)
00133 , m_sortingAlphabetical(false)
00134 , m_isSortingByInheritance(false)
00135 , m_sortingCaseSensitivity(Qt::CaseInsensitive)
00136 , m_filteringEnabled(false)
00137 , m_filterContextMatchesOnly(false)
00138 , m_filterByAttribute(false)
00139 , m_filterAttributes(KTextEditor::CodeCompletionModel::NoProperty)
00140 , m_maximumInheritanceDepth(0)
00141 , m_groupingEnabled(false)
00142 , m_accessConst(false)
00143 , m_accessStatic(false)
00144 , m_accesSignalSlot(false)
00145 , m_columnMergingEnabled(false)
00146
00147 {
00148
00149 m_ungrouped->attribute = 0;
00150 m_argumentHints->attribute = -1;
00151 m_bestMatches->attribute = BestMatchesProperty;
00152
00153 m_argumentHints->title = i18n("Argument-hints");
00154 m_bestMatches->title = i18n("Best matches");
00155
00156 m_emptyGroups.append(m_ungrouped);
00157 m_emptyGroups.append(m_argumentHints);
00158 m_emptyGroups.append(m_bestMatches);
00159
00160 m_updateBestMatchesTimer = new QTimer(this);
00161 m_updateBestMatchesTimer->setSingleShot(true);
00162 connect(m_updateBestMatchesTimer, SIGNAL(timeout()), this, SLOT(updateBestMatches()));
00163
00164 m_groupHash.insert(0, m_ungrouped);
00165 m_groupHash.insert(-1, m_argumentHints);
00166 m_groupHash.insert(BestMatchesProperty, m_argumentHints);
00167 }
00168
00169 KateCompletionModel::~KateCompletionModel() {
00170 clearCompletionModels();
00171 delete m_argumentHints;
00172 delete m_ungrouped;
00173 delete m_bestMatches;
00174 }
00175
00176 QTreeView* KateCompletionModel::treeView() const {
00177 return view()->completionWidget()->treeView();
00178 }
00179
00180 QVariant KateCompletionModel::data( const QModelIndex & index, int role ) const
00181 {
00182 if (!hasCompletionModel() || !index.isValid())
00183 return QVariant();
00184
00185 if( role == Qt::DecorationRole && index.column() == KTextEditor::CodeCompletionModel::Prefix && isExpandable(index) )
00186 {
00187 cacheIcons();
00188
00189 if( !isExpanded(index ) )
00190 return QVariant( m_collapsedIcon );
00191 else
00192 return QVariant( m_expandedIcon );
00193 }
00194
00195
00196 if (!hasGroups() || groupOfParent(index)) {
00197 switch (role) {
00198 case Qt::TextAlignmentRole:
00199 if (isColumnMergingEnabled() && m_columnMerges.count()) {
00200 int c = 0;
00201 foreach (const QList<int>& list, m_columnMerges) {
00202 foreach (int column, list) {
00203 if (c++ == index.column()) {
00204 if (column == CodeCompletionModel::Scope)
00205 if (list.count() == 1)
00206 return Qt::AlignRight;
00207
00208 goto dontalign;
00209 }
00210 }
00211 }
00212
00213 } else if ((!isColumnMergingEnabled() || m_columnMerges.isEmpty()) && index.column() == CodeCompletionModel::Scope) {
00214 return Qt::AlignRight;
00215 }
00216
00217 dontalign:
00218 break;
00219 }
00220
00221
00222 if (role == Qt::DisplayRole && m_columnMerges.count() && isColumnMergingEnabled()) {
00223 QString text;
00224 foreach (int column, m_columnMerges[index.column()]) {
00225 QModelIndex sourceIndex = mapToSource(createIndex(index.row(), column, index.internalPointer()));
00226 text.append(sourceIndex.data(role).toString());
00227 }
00228
00229 return text;
00230 }
00231
00232 if(role == CodeCompletionModel::HighlightingMethod)
00233 {
00234
00235 foreach (int column, m_columnMerges[index.column()]) {
00236 QModelIndex sourceIndex = mapToSource(createIndex(index.row(), column, index.internalPointer()));
00237 QVariant method = sourceIndex.data(CodeCompletionModel::HighlightingMethod);
00238 if( method.type() == QVariant::Int && method.toInt() == CodeCompletionModel::CustomHighlighting)
00239 return QVariant(CodeCompletionModel::CustomHighlighting);
00240 }
00241 return QVariant();
00242 }
00243 if(role == CodeCompletionModel::CustomHighlight)
00244 {
00245
00246 QStringList strings;
00247
00248
00249 foreach (int column, m_columnMerges[index.column()])
00250 strings << mapToSource(createIndex(index.row(), column, index.internalPointer())).data(Qt::DisplayRole).toString();
00251
00252 QList<QVariantList> highlights;
00253
00254
00255 foreach (int column, m_columnMerges[index.column()])
00256 highlights << mapToSource(createIndex(index.row(), column, index.internalPointer())).data(CodeCompletionModel::CustomHighlight).toList();
00257
00258 return mergeCustomHighlighting( strings, highlights, 0 );
00259 }
00260
00261 QVariant v = mapToSource(index).data(role);
00262 if( v.isValid() )
00263 return v;
00264 else
00265 return ExpandingWidgetModel::data(index, role);
00266 }
00267
00268
00269 Group* g = groupForIndex(index);
00270
00271 if (g && (!g->isEmpty)) {
00272 switch (role) {
00273 case Qt::DisplayRole:
00274
00275 return ' ' + g->title;
00276 break;
00277
00278 case Qt::FontRole:
00279 if (!index.column()) {
00280 QFont f = view()->renderer()->config()->font();
00281 f.setBold(true);
00282 return f;
00283 }
00284 break;
00285
00286 case Qt::ForegroundRole:
00287 return KApplication::kApplication()->palette().toolTipText().color();
00288 case Qt::BackgroundRole:
00289 return KApplication::kApplication()->palette().toolTipBase().color();
00290 }
00291 }
00292
00293 return QVariant();
00294 }
00295
00296 int KateCompletionModel::contextMatchQuality(const QModelIndex& index) const {
00297 if(!index.isValid())
00298 return 0;
00299 Group* g = groupOfParent(index);
00300 if(!g || g->filtered.size() < index.row())
00301 return 0;
00302
00303 return contextMatchQuality(g->filtered[index.row()].sourceRow());
00304 }
00305
00306 int KateCompletionModel::contextMatchQuality(const ModelRow& source) const {
00307 QModelIndex realIndex = source.second;
00308
00309 int bestMatch = -1;
00310
00311 foreach( const Item& item, m_argumentHints->filtered )
00312 {
00313 const ModelRow& row(item.sourceRow());
00314 if( realIndex.model() != row.first )
00315 continue;
00316
00317 QModelIndex hintIndex = row.second;
00318
00319 QVariant depth = hintIndex.data(CodeCompletionModel::ArgumentHintDepth);
00320 if( !depth.isValid() || depth.type() != QVariant::Int || depth.toInt() != 1 )
00321 continue;
00322
00323 hintIndex.data(CodeCompletionModel::SetMatchContext);
00324
00325 QVariant matchQuality = realIndex.data(CodeCompletionModel::MatchQuality);
00326 if( matchQuality.isValid() && matchQuality.type() == QVariant::Int ) {
00327 int m = matchQuality.toInt();
00328 if( m > bestMatch )
00329 bestMatch = m;
00330 }
00331 }
00332
00333 if(m_argumentHints->filtered.isEmpty()) {
00334 QVariant matchQuality = realIndex.data(CodeCompletionModel::MatchQuality);
00335 if( matchQuality.isValid() && matchQuality.type() == QVariant::Int ) {
00336 int m = matchQuality.toInt();
00337 if( m > bestMatch )
00338 bestMatch = m;
00339 }
00340 }
00341
00342 return bestMatch;
00343 }
00344
00345 Qt::ItemFlags KateCompletionModel::flags( const QModelIndex & index ) const
00346 {
00347 if (!hasCompletionModel() || !index.isValid())
00348 return 0;
00349
00350 if (!hasGroups() || groupOfParent(index))
00351 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
00352
00353 return Qt::ItemIsEnabled;
00354 }
00355
00356 KateCompletionWidget* KateCompletionModel::widget() const {
00357 return static_cast<KateCompletionWidget*>(QObject::parent());
00358 }
00359
00360 KateView * KateCompletionModel::view( ) const
00361 {
00362 return widget()->view();
00363 }
00364
00365 void KateCompletionModel::setMatchCaseSensitivity( Qt::CaseSensitivity cs )
00366 {
00367 m_matchCaseSensitivity = cs;
00368 }
00369
00370 int KateCompletionModel::columnCount( const QModelIndex& ) const
00371 {
00372 return isColumnMergingEnabled() && !m_columnMerges.isEmpty() ? m_columnMerges.count() : KTextEditor::CodeCompletionModel::ColumnCount;
00373 }
00374
00375 KateCompletionModel::ModelRow KateCompletionModel::modelRowPair(const QModelIndex& index) const
00376 {
00377 return qMakePair(static_cast<CodeCompletionModel*>(const_cast<QAbstractItemModel*>(index.model())), index);
00378 }
00379
00380 bool KateCompletionModel::hasChildren( const QModelIndex & parent ) const
00381 {
00382 if (!hasCompletionModel())
00383 return false;
00384
00385 if (!parent.isValid()) {
00386 if (hasGroups())
00387 return true;
00388
00389 return !m_ungrouped->filtered.isEmpty();
00390 }
00391
00392 if (parent.column() != 0)
00393 return false;
00394
00395 if (!hasGroups())
00396 return false;
00397
00398 if (Group* g = groupForIndex(parent))
00399 return !g->filtered.isEmpty();
00400
00401 return false;
00402 }
00403
00404 QModelIndex KateCompletionModel::index( int row, int column, const QModelIndex & parent ) const
00405 {
00406 if (row < 0 || column < 0 || column >= columnCount(QModelIndex()))
00407 return QModelIndex();
00408
00409 if (parent.isValid() || !hasGroups()) {
00410 if (parent.isValid() && parent.column() != 0)
00411 return QModelIndex();
00412
00413 Group* g = groupForIndex(parent);
00414
00415 if (!g)
00416 return QModelIndex();
00417
00418 if (row >= g->filtered.count()) {
00419
00420 return QModelIndex();
00421 }
00422
00423
00424 return createIndex(row, column, g);
00425 }
00426
00427 if (row >= m_rowTable.count()) {
00428
00429 return QModelIndex();
00430 }
00431
00432
00433 return createIndex(row, column, 0);
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 bool KateCompletionModel::hasIndex( int row, int column, const QModelIndex & parent ) const
00461 {
00462 if (row < 0 || column < 0 || column >= columnCount(QModelIndex()))
00463 return false;
00464
00465 if (parent.isValid() || !hasGroups()) {
00466 if (parent.isValid() && parent.column() != 0)
00467 return false;
00468
00469 Group* g = groupForIndex(parent);
00470
00471 if (row >= g->filtered.count())
00472 return false;
00473
00474 return true;
00475 }
00476
00477 if (row >= m_rowTable.count())
00478 return false;
00479
00480 return true;
00481 }
00482
00483 QModelIndex KateCompletionModel::indexForRow( Group * g, int row ) const
00484 {
00485 if (row < 0 || row >= g->filtered.count())
00486 return QModelIndex();
00487
00488 return createIndex(row, 0, g);
00489 }
00490
00491 QModelIndex KateCompletionModel::indexForGroup( Group * g ) const
00492 {
00493 if (!hasGroups())
00494 return QModelIndex();
00495
00496 int row = m_rowTable.indexOf(g);
00497
00498 if (row == -1)
00499 return QModelIndex();
00500
00501 return createIndex(row, 0, 0);
00502 }
00503
00504 void KateCompletionModel::clearGroups( bool shouldReset )
00505 {
00506 clearExpanding();
00507 m_ungrouped->clear();
00508 m_argumentHints->clear();
00509 m_bestMatches->clear();
00510
00511
00512 m_rowTable.removeAll(m_ungrouped);
00513 m_emptyGroups.removeAll(m_ungrouped);
00514
00515 m_rowTable.removeAll(m_argumentHints);
00516 m_emptyGroups.removeAll(m_argumentHints);
00517
00518 m_rowTable.removeAll(m_bestMatches);
00519 m_emptyGroups.removeAll(m_bestMatches);
00520
00521 qDeleteAll(m_rowTable);
00522 qDeleteAll(m_emptyGroups);
00523 m_rowTable.clear();
00524 m_emptyGroups.clear();
00525 m_groupHash.clear();
00526 m_customGroupHash.clear();
00527
00528 m_emptyGroups.append(m_ungrouped);
00529 m_groupHash.insert(0, m_ungrouped);
00530
00531 m_emptyGroups.append(m_argumentHints);
00532 m_groupHash.insert(-1, m_argumentHints);
00533
00534 m_emptyGroups.append(m_bestMatches);
00535 m_groupHash.insert(BestMatchesProperty, m_bestMatches);
00536
00537 if(shouldReset)
00538 reset();
00539 }
00540
00541 QSet<KateCompletionModel::Group*> KateCompletionModel::createItems(const HierarchicalModelHandler& _handler, const QModelIndex& i, bool notifyModel) {
00542 HierarchicalModelHandler handler(_handler);
00543 QSet<Group*> ret;
00544
00545 if( handler.model()->rowCount(i) == 0 ) {
00546
00547 ret.insert( createItem(handler, i, notifyModel) );
00548 } else {
00549
00550 handler.takeRole(i);
00551 for(int a = 0; a < handler.model()->rowCount(i); a++)
00552 ret += createItems(handler, i.child(a, 0), notifyModel);
00553 }
00554
00555 return ret;
00556 }
00557
00558 QSet<KateCompletionModel::Group*> KateCompletionModel::deleteItems(const QModelIndex& i) {
00559 QSet<Group*> ret;
00560
00561 if( i.model()->rowCount(i) == 0 ) {
00562
00563 Group* g = groupForIndex(mapFromSource(i));
00564 ret.insert(g);
00565 g->removeItem(ModelRow(const_cast<CodeCompletionModel*>(static_cast<const CodeCompletionModel*>(i.model())), i));
00566 } else {
00567
00568 for(int a = 0; a < i.model()->rowCount(i); a++)
00569 ret += deleteItems(i.child(a, 0));
00570 }
00571
00572 return ret;
00573 }
00574
00575 void KateCompletionModel::createGroups()
00576 {
00577
00578
00579 clearGroups(true);
00580
00581 bool has_groups=false;
00582 foreach (CodeCompletionModel* sourceModel, m_completionModels) {
00583 has_groups|=sourceModel->hasGroups();
00584 for (int i = 0; i < sourceModel->rowCount(); ++i)
00585 createItems(HierarchicalModelHandler(sourceModel), sourceModel->index(i, 0));
00586 }
00587 m_hasGroups=has_groups;
00588
00589
00590
00591 foreach (Group* g, m_rowTable)
00592 hideOrShowGroup(g);
00593
00594 foreach (Group* g, m_emptyGroups)
00595 hideOrShowGroup(g);
00596
00597 updateBestMatches();
00598
00599 reset();
00600
00601 emit contentGeometryChanged();
00602 }
00603
00604 KateCompletionModel::Group* KateCompletionModel::createItem(const HierarchicalModelHandler& handler, const QModelIndex& sourceIndex, bool notifyModel)
00605 {
00606
00607
00608 int completionFlags = handler.getData(CodeCompletionModel::CompletionRole, sourceIndex).toInt();
00609
00610
00611 QString scopeIfNeeded = (groupingMethod() & Scope) ? sourceIndex.sibling(sourceIndex.row(), CodeCompletionModel::Scope).data(Qt::DisplayRole).toString() : QString();
00612
00613 int argumentHintDepth = handler.getData(CodeCompletionModel::ArgumentHintDepth, sourceIndex).toInt();
00614
00615 Group* g;
00616 if( argumentHintDepth ) {
00617 g = m_argumentHints;
00618 } else{
00619 QString customGroup = handler.customGroup();
00620 if(!customGroup.isNull() && m_hasGroups) {
00621 if(m_customGroupHash.contains(customGroup)) {
00622 g = m_customGroupHash[customGroup];
00623 }else{
00624 g = new Group(this);
00625 g->title = customGroup;
00626 g->customSortingKey = handler.customGroupingKey();
00627 m_emptyGroups.append(g);
00628 m_customGroupHash.insert(customGroup, g);
00629 }
00630 }else{
00631 g = fetchGroup(completionFlags, scopeIfNeeded, handler.hasHierarchicalRoles());
00632 }
00633 }
00634
00635 Item item = Item(g != m_argumentHints, this, handler, ModelRow(handler.model(), sourceIndex));
00636
00637 if(g != m_argumentHints)
00638 item.match();
00639
00640 g->addItem(item, notifyModel);
00641
00642 return g;
00643 }
00644
00645 void KateCompletionModel::slotRowsInserted( const QModelIndex & parent, int start, int end )
00646 {
00647 QSet<Group*> affectedGroups;
00648
00649 HierarchicalModelHandler handler(static_cast<CodeCompletionModel*>(sender()));
00650 if(parent.isValid())
00651 handler.collectRoles(parent);
00652
00653
00654 for (int i = start; i <= end; ++i)
00655 affectedGroups += createItems(handler, parent.isValid() ? parent.child(i, 0) : handler.model()->index(i, 0), true);
00656
00657 foreach (Group* g, affectedGroups)
00658 hideOrShowGroup(g);
00659
00660 emit contentGeometryChanged();
00661 }
00662
00663 void KateCompletionModel::slotRowsRemoved( const QModelIndex & parent, int start, int end )
00664 {
00665 CodeCompletionModel* source = static_cast<CodeCompletionModel*>(sender());
00666
00667 QSet<Group*> affectedGroups;
00668
00669 for (int i = start; i <= end; ++i) {
00670 QModelIndex index = parent.isValid() ? parent.child(i, 0) : source->index(i, 0);
00671
00672 affectedGroups += deleteItems(index);
00673 }
00674
00675 foreach (Group* g, affectedGroups)
00676 hideOrShowGroup(g);
00677
00678 emit contentGeometryChanged();
00679 }
00680
00681 KateCompletionModel::Group* KateCompletionModel::fetchGroup( int attribute, const QString& scope, bool forceGrouping )
00682 {
00683 Q_UNUSED(forceGrouping);
00684
00686 if (!hasGroups())
00687 return m_ungrouped;
00688
00689 int groupingAttribute = groupingAttributes(attribute);
00690
00691
00692 if (m_groupHash.contains(groupingAttribute)) {
00693 if (groupingMethod() & Scope) {
00694 for (QHash<int, Group*>::ConstIterator it = m_groupHash.constFind(groupingAttribute); it != m_groupHash.constEnd() && it.key() == groupingAttribute; ++it)
00695 if (it.value()->scope == scope)
00696 return it.value();
00697 } else {
00698 return m_groupHash.value(groupingAttribute);
00699 }
00700 }
00701 Group* ret = new Group(this);
00702
00703 ret->attribute = attribute;
00704 ret->scope = scope;
00705
00706 QString st, at, it;
00707
00708 if (groupingMethod() & ScopeType) {
00709 if (attribute & KTextEditor::CodeCompletionModel::GlobalScope)
00710 st = "Global";
00711 else if (attribute & KTextEditor::CodeCompletionModel::NamespaceScope)
00712 st = "Namespace";
00713 else if (attribute & KTextEditor::CodeCompletionModel::LocalScope)
00714 st = "Local";
00715
00716 ret->title = st;
00717 }
00718
00719 if (groupingMethod() & Scope) {
00720 if (!ret->title.isEmpty())
00721 ret->title.append(" ");
00722
00723 ret->title.append(scope);
00724 }
00725
00726 if (groupingMethod() & AccessType) {
00727 if (attribute & KTextEditor::CodeCompletionModel::Public)
00728 at = "Public";
00729 else if (attribute & KTextEditor::CodeCompletionModel::Protected)
00730 at = "Protected";
00731 else if (attribute & KTextEditor::CodeCompletionModel::Private)
00732 at = "Private";
00733
00734 if (accessIncludeStatic() && attribute & KTextEditor::CodeCompletionModel::Static)
00735 at.append(" Static");
00736
00737 if (accessIncludeConst() && attribute & KTextEditor::CodeCompletionModel::Const)
00738 at.append(" Const");
00739
00740 if( !at.isEmpty() ) {
00741 if (!ret->title.isEmpty())
00742 ret->title.append(", ");
00743
00744 ret->title.append(at);
00745 }
00746 }
00747
00748 if (groupingMethod() & ItemType) {
00749 if (attribute & CodeCompletionModel::Namespace)
00750 it = i18n("Namespaces");
00751 else if (attribute & CodeCompletionModel::Class)
00752 it = i18n("Classes");
00753 else if (attribute & CodeCompletionModel::Struct)
00754 it = i18n("Structs");
00755 else if (attribute & CodeCompletionModel::Union)
00756 it = i18n("Unions");
00757 else if (attribute & CodeCompletionModel::Function)
00758 it = i18n("Functions");
00759 else if (attribute & CodeCompletionModel::Variable)
00760 it = i18n("Variables");
00761 else if (attribute & CodeCompletionModel::Enum)
00762 it = i18n("Enumerations");
00763
00764 if( !it.isEmpty() ) {
00765 if (!ret->title.isEmpty())
00766 ret->title.append(" ");
00767
00768 ret->title.append(it);
00769 }
00770 }
00771
00772 m_emptyGroups.append(ret);
00773 m_groupHash.insert(groupingAttribute, ret);
00774
00775 return ret;
00776 }
00777
00778 bool KateCompletionModel::hasGroups( ) const
00779 {
00780
00781
00782
00783
00784
00785
00786 return m_groupingEnabled && m_hasGroups;
00787 }
00788
00789 KateCompletionModel::Group* KateCompletionModel::groupForIndex( const QModelIndex & index ) const
00790 {
00791 if (!index.isValid()) {
00792 if (!hasGroups())
00793 return m_ungrouped;
00794 else
00795 return 0L;
00796 }
00797
00798 if (groupOfParent(index))
00799 return 0L;
00800
00801 if (index.row() < 0 || index.row() >= m_rowTable.count())
00802 return m_ungrouped;
00803
00804 return m_rowTable[index.row()];
00805 }
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818 QModelIndex KateCompletionModel::parent( const QModelIndex & index ) const
00819 {
00820 if (!index.isValid())
00821 return QModelIndex();
00822
00823 if (Group* g = groupOfParent(index)) {
00824 if (!hasGroups()) {
00825 Q_ASSERT(g == m_ungrouped);
00826 return QModelIndex();
00827 }
00828
00829 int row = m_rowTable.indexOf(g);
00830
00831 if (row == -1) {
00832 kWarning() << "Couldn't find parent for index" << index;
00833 return QModelIndex();
00834 }
00835
00836 return createIndex(row, 0, 0);
00837 }
00838
00839 return QModelIndex();
00840 }
00841
00842 int KateCompletionModel::rowCount( const QModelIndex & parent ) const
00843 {
00844 if (!parent.isValid()) {
00845 if (hasGroups()) {
00846
00847 return m_rowTable.count();
00848 } else {
00849
00850 return m_ungrouped->filtered.count();
00851 }
00852 }
00853
00854 Group* g = groupForIndex(parent);
00855
00856
00857 if (!g)
00858 return 0;
00859
00860
00861 return g->filtered.count();
00862 }
00863
00864 void KateCompletionModel::sort( int column, Qt::SortOrder order )
00865 {
00866 Q_UNUSED(column)
00867 Q_UNUSED(order)
00868 }
00869
00870 QModelIndex KateCompletionModel::mapToSource( const QModelIndex & proxyIndex ) const
00871 {
00872 if (!proxyIndex.isValid())
00873 return QModelIndex();
00874
00875 if (Group* g = groupOfParent(proxyIndex)) {
00876 if( proxyIndex.row() >= 0 && proxyIndex.row() < g->filtered.count() ) {
00877 ModelRow source = g->filtered[proxyIndex.row()].sourceRow();
00878 return source.second.sibling(source.second.row(), proxyIndex.column());
00879 }else{
00880 kDebug("Invalid proxy-index");
00881 }
00882 }
00883
00884 return QModelIndex();
00885 }
00886
00887 QModelIndex KateCompletionModel::mapFromSource( const QModelIndex & sourceIndex ) const
00888 {
00889 if (!sourceIndex.isValid())
00890 return QModelIndex();
00891
00892 if (!hasGroups())
00893 return index(m_ungrouped->rowOf(modelRowPair(sourceIndex)), sourceIndex.column(), QModelIndex());
00894
00895 foreach (Group* g, m_rowTable) {
00896 int row = g->rowOf(modelRowPair(sourceIndex));
00897 if (row != -1)
00898 return index(row, sourceIndex.column(), QModelIndex());
00899 }
00900
00901
00902 foreach (Group* g, m_emptyGroups) {
00903 int row = g->rowOf(modelRowPair(sourceIndex));
00904 if (row != -1)
00905 return index(row, sourceIndex.column(), QModelIndex());
00906 }
00907
00908 return QModelIndex();
00909 }
00910
00911 void KateCompletionModel::setCurrentCompletion( KTextEditor::CodeCompletionModel* model, const QString & completion )
00912 {
00913 if (m_currentMatch[model] == completion)
00914 return;
00915
00916 if (!hasCompletionModel()) {
00917 m_currentMatch[model] = completion;
00918 return;
00919 }
00920
00921 changeTypes changeType = Change;
00922
00923 if (m_currentMatch[model].length() > completion.length() && m_currentMatch[model].startsWith(completion, m_matchCaseSensitivity)) {
00924
00925 changeType = Broaden;
00926
00927 } else if (m_currentMatch[model].length() < completion.length() && completion.startsWith(m_currentMatch[model], m_matchCaseSensitivity)) {
00928
00929 changeType = Narrow;
00930 }
00931
00932 kDebug( 13035 ) << model << "Old match: " << m_currentMatch[model] << ", new: " << completion << ", type: " << changeType;
00933
00934 m_currentMatch[model] = completion;
00935
00936 bool needsReset = false;
00937
00938 if (!hasGroups()) {
00939 needsReset |= changeCompletions(m_ungrouped, changeType);
00940 } else {
00941 foreach (Group* g, m_rowTable) {
00942 if(g != m_argumentHints)
00943 needsReset |= changeCompletions(g, changeType);
00944 }
00945 foreach (Group* g, m_emptyGroups) {
00946 if(g != m_argumentHints)
00947 needsReset |= changeCompletions(g, changeType);
00948 }
00949
00950 updateBestMatches();
00951 }
00952
00953 if(needsReset)
00954 reset();
00955
00956 clearExpanding();
00957 emit contentGeometryChanged();
00958 }
00959
00960 bool KateCompletionModel::changeCompletions( Group * g, changeTypes changeType )
00961 {
00962 bool notifyModel = true;
00963 if(changeType != Narrow) {
00964 notifyModel = false;
00965 g->filtered = g->prefilter;
00966
00967
00968 }
00969
00970
00971
00972 QList <KateCompletionModel::Item > newFiltered;
00973 int deleteUntil = -1;
00974 for(int currentRow = g->filtered.count()-1; currentRow >= 0; --currentRow) {
00975 if(g->filtered[currentRow].match()) {
00976
00977 if(deleteUntil != -1 && notifyModel) {
00978 beginRemoveRows(indexForGroup(g), currentRow+1, deleteUntil);
00979 endRemoveRows();
00980 }
00981 deleteUntil = -1;
00982
00983 newFiltered.prepend(g->filtered[currentRow]);
00984 }else{
00985 if(deleteUntil == -1)
00986 deleteUntil = currentRow;
00987 }
00988 }
00989
00990 if(deleteUntil != -1) {
00991 beginRemoveRows(indexForGroup(g), 0, deleteUntil);
00992 endRemoveRows();
00993 }
00994
00995 g->filtered = newFiltered;
00996 hideOrShowGroup(g, notifyModel);
00997 return !notifyModel;
00998 }
00999
01000 int KateCompletionModel::Group::orderNumber() const {
01001 if( this == model->m_ungrouped )
01002 return 700;
01003
01004 if(customSortingKey != -1)
01005 return customSortingKey;
01006
01007 if( attribute & BestMatchesProperty )
01008 return 1;
01009
01010 if (attribute & KTextEditor::CodeCompletionModel::LocalScope)
01011 return 100;
01012 else if (attribute & KTextEditor::CodeCompletionModel::Public)
01013 return 200;
01014 else if (attribute & KTextEditor::CodeCompletionModel::Protected)
01015 return 300;
01016 else if (attribute & KTextEditor::CodeCompletionModel::Private)
01017 return 400;
01018 else if (attribute & KTextEditor::CodeCompletionModel::NamespaceScope)
01019 return 500;
01020 else if (attribute & KTextEditor::CodeCompletionModel::GlobalScope)
01021 return 600;
01022
01023
01024 return 700;
01025 }
01026
01027 bool KateCompletionModel::Group::orderBefore(Group* other) const {
01028 return orderNumber() < other->orderNumber();
01029 }
01030
01031 void KateCompletionModel::hideOrShowGroup(Group* g, bool notifyModel)
01032 {
01033 if( g == m_argumentHints ) {
01034 emit argumentHintsChanged();
01035 m_updateBestMatchesTimer->start(200);
01036 return;
01037 }
01038
01039 if (!g->isEmpty) {
01040 if (g->filtered.isEmpty()) {
01041
01042 g->isEmpty = true;
01043 int row = m_rowTable.indexOf(g);
01044 if (row != -1) {
01045 if (hasGroups() && notifyModel)
01046 beginRemoveRows(QModelIndex(), row, row);
01047 m_rowTable.removeAt(row);
01048 if (hasGroups() && notifyModel)
01049 endRemoveRows();
01050 m_emptyGroups.append(g);
01051 } else {
01052 kWarning() << "Group " << g << " not found in row table!!";
01053 }
01054 }
01055
01056 } else {
01057
01058 if (!g->filtered.isEmpty()) {
01059
01060 g->isEmpty = false;
01061
01062 int row = 0;
01063 for( int a = 0; a < m_rowTable.count(); a++ ) {
01064 if( g->orderBefore(m_rowTable[a]) ) {
01065 row = a;
01066 break;
01067 }
01068 row = a+1;
01069 }
01070
01071 if(notifyModel) {
01072 if (hasGroups())
01073 beginInsertRows(QModelIndex(), row, row);
01074 else
01075 beginInsertRows(QModelIndex(), 0, g->filtered.count());
01076 }
01077 m_rowTable.insert(row, g);
01078 if(notifyModel)
01079 endInsertRows();
01080 m_emptyGroups.removeAll(g);
01081 }
01082 }
01083 }
01084
01085 bool KateCompletionModel::indexIsItem( const QModelIndex & index ) const
01086 {
01087 if (!hasGroups())
01088 return true;
01089
01090 if (groupOfParent(index))
01091 return true;
01092
01093 return false;
01094 }
01095
01096 void KateCompletionModel::slotModelReset()
01097 {
01098 createGroups();
01099
01100
01101 }
01102
01103 void KateCompletionModel::debugStats()
01104 {
01105 if (!hasGroups())
01106 kDebug( 13035 ) << "Model groupless, " << m_ungrouped->filtered.count() << " items.";
01107 else {
01108 kDebug( 13035 ) << "Model grouped (" << m_rowTable.count() << " groups):";
01109 foreach (Group* g, m_rowTable)
01110 kDebug( 13035 ) << "Group" << g << "count" << g->filtered.count();
01111 }
01112 }
01113
01114 bool KateCompletionModel::hasCompletionModel( ) const
01115 {
01116 return !m_completionModels.isEmpty();
01117 }
01118
01119 void KateCompletionModel::setFilteringEnabled( bool enable )
01120 {
01121 if (m_filteringEnabled != enable)
01122 m_filteringEnabled = enable;
01123 }
01124
01125 void KateCompletionModel::setSortingEnabled( bool enable )
01126 {
01127 if (m_sortingEnabled != enable) {
01128 m_sortingEnabled = enable;
01129 resort();
01130 }
01131 }
01132
01133 void KateCompletionModel::setGroupingEnabled(bool enable)
01134 {
01135 if (m_groupingEnabled != enable)
01136 m_groupingEnabled = enable;
01137 }
01138
01139 void KateCompletionModel::setColumnMergingEnabled(bool enable)
01140 {
01141 if (m_columnMergingEnabled != enable)
01142 m_columnMergingEnabled = enable;
01143 }
01144
01145 bool KateCompletionModel::isColumnMergingEnabled( ) const
01146 {
01147 return m_columnMergingEnabled;
01148 }
01149
01150 bool KateCompletionModel::isGroupingEnabled( ) const
01151 {
01152 return m_groupingEnabled;
01153 }
01154
01155 bool KateCompletionModel::isFilteringEnabled( ) const
01156 {
01157 return m_filteringEnabled;
01158 }
01159
01160 bool KateCompletionModel::isSortingEnabled( ) const
01161 {
01162 return m_sortingEnabled;
01163 }
01164
01165 QString KateCompletionModel::columnName( int column )
01166 {
01167 switch (column) {
01168 case KTextEditor::CodeCompletionModel::Prefix:
01169 return i18n("Prefix");
01170 case KTextEditor::CodeCompletionModel::Icon:
01171 return i18n("Icon");
01172 case KTextEditor::CodeCompletionModel::Scope:
01173 return i18n("Scope");
01174 case KTextEditor::CodeCompletionModel::Name:
01175 return i18n("Name");
01176 case KTextEditor::CodeCompletionModel::Arguments:
01177 return i18n("Arguments");
01178 case KTextEditor::CodeCompletionModel::Postfix:
01179 return i18n("Postfix");
01180 }
01181
01182 return QString();
01183 }
01184
01185 const QList< QList < int > > & KateCompletionModel::columnMerges( ) const
01186 {
01187 return m_columnMerges;
01188 }
01189
01190 void KateCompletionModel::setColumnMerges( const QList< QList < int > > & columnMerges )
01191 {
01192 m_columnMerges = columnMerges;
01193 reset();
01194 }
01195
01196 int KateCompletionModel::translateColumn( int sourceColumn ) const
01197 {
01198 if (m_columnMerges.isEmpty())
01199 return sourceColumn;
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214 int c = 0;
01215 foreach (const QList<int>& list, m_columnMerges) {
01216 foreach (int column, list) {
01217 if (column == sourceColumn)
01218 return c;
01219 }
01220 c++;
01221 }
01222 return -1;
01223 }
01224
01225 int KateCompletionModel::groupingAttributes( int attribute ) const
01226 {
01227 int ret = 0;
01228
01229 if (m_groupingMethod & ScopeType) {
01230 if (countBits(attribute & ScopeTypeMask) > 1)
01231 kWarning() << "Invalid completion model metadata: more than one scope type modifier provided.";
01232
01233 if (attribute & KTextEditor::CodeCompletionModel::GlobalScope)
01234 ret |= KTextEditor::CodeCompletionModel::GlobalScope;
01235 else if (attribute & KTextEditor::CodeCompletionModel::NamespaceScope)
01236 ret |= KTextEditor::CodeCompletionModel::NamespaceScope;
01237 else if (attribute & KTextEditor::CodeCompletionModel::LocalScope)
01238 ret |= KTextEditor::CodeCompletionModel::LocalScope;
01239 }
01240
01241 if (m_groupingMethod & AccessType) {
01242 if (countBits(attribute & AccessTypeMask) > 1)
01243 kWarning() << "Invalid completion model metadata: more than one access type modifier provided.";
01244
01245 if (attribute & KTextEditor::CodeCompletionModel::Public)
01246 ret |= KTextEditor::CodeCompletionModel::Public;
01247 else if (attribute & KTextEditor::CodeCompletionModel::Protected)
01248 ret |= KTextEditor::CodeCompletionModel::Protected;
01249 else if (attribute & KTextEditor::CodeCompletionModel::Private)
01250 ret |= KTextEditor::CodeCompletionModel::Private;
01251
01252 if (accessIncludeStatic() && attribute & KTextEditor::CodeCompletionModel::Static)
01253 ret |= KTextEditor::CodeCompletionModel::Static;
01254
01255 if (accessIncludeConst() && attribute & KTextEditor::CodeCompletionModel::Const)
01256 ret |= KTextEditor::CodeCompletionModel::Const;
01257 }
01258
01259 if (m_groupingMethod & ItemType) {
01260 if (countBits(attribute & ItemTypeMask) > 1)
01261 kWarning() << "Invalid completion model metadata: more than one item type modifier provided.";
01262
01263 if (attribute & KTextEditor::CodeCompletionModel::Namespace)
01264 ret |= KTextEditor::CodeCompletionModel::Namespace;
01265 else if (attribute & KTextEditor::CodeCompletionModel::Class)
01266 ret |= KTextEditor::CodeCompletionModel::Class;
01267 else if (attribute & KTextEditor::CodeCompletionModel::Struct)
01268 ret |= KTextEditor::CodeCompletionModel::Struct;
01269 else if (attribute & KTextEditor::CodeCompletionModel::Union)
01270 ret |= KTextEditor::CodeCompletionModel::Union;
01271 else if (attribute & KTextEditor::CodeCompletionModel::Function)
01272 ret |= KTextEditor::CodeCompletionModel::Function;
01273 else if (attribute & KTextEditor::CodeCompletionModel::Variable)
01274 ret |= KTextEditor::CodeCompletionModel::Variable;
01275 else if (attribute & KTextEditor::CodeCompletionModel::Enum)
01276 ret |= KTextEditor::CodeCompletionModel::Enum;
01277
01278
01279
01280
01281 }
01282
01283 return ret;
01284 }
01285
01286 void KateCompletionModel::setGroupingMethod( GroupingMethods m )
01287 {
01288 m_groupingMethod = m;
01289
01290 createGroups();
01291 }
01292
01293 bool KateCompletionModel::accessIncludeConst( ) const
01294 {
01295 return m_accessConst;
01296 }
01297
01298 void KateCompletionModel::setAccessIncludeConst( bool include )
01299 {
01300 if (m_accessConst != include) {
01301 m_accessConst = include;
01302
01303 if (groupingMethod() & AccessType)
01304 createGroups();
01305 }
01306 }
01307
01308 bool KateCompletionModel::accessIncludeStatic( ) const
01309 {
01310 return m_accessStatic;
01311 }
01312
01313 void KateCompletionModel::setAccessIncludeStatic( bool include )
01314 {
01315 if (m_accessStatic != include) {
01316 m_accessStatic = include;
01317
01318 if (groupingMethod() & AccessType)
01319 createGroups();
01320 }
01321 }
01322
01323 bool KateCompletionModel::accessIncludeSignalSlot( ) const
01324 {
01325 return m_accesSignalSlot;
01326 }
01327
01328 void KateCompletionModel::setAccessIncludeSignalSlot( bool include )
01329 {
01330 if (m_accesSignalSlot != include) {
01331 m_accesSignalSlot = include;
01332
01333 if (groupingMethod() & AccessType)
01334 createGroups();
01335 }
01336 }
01337
01338 int KateCompletionModel::countBits( int value ) const
01339 {
01340 int count = 0;
01341 for (int i = 1; i; i <<= 1)
01342 if (i & value)
01343 count++;
01344
01345 return count;
01346 }
01347
01348 KateCompletionModel::GroupingMethods KateCompletionModel::groupingMethod( ) const
01349 {
01350 return m_groupingMethod;
01351 }
01352
01353 bool KateCompletionModel::isSortingByInheritanceDepth() const {
01354 return m_isSortingByInheritance;
01355 }
01356 void KateCompletionModel::setSortingByInheritanceDepth(bool byInheritance) {
01357 m_isSortingByInheritance = byInheritance;
01358 }
01359
01360 bool KateCompletionModel::isSortingAlphabetical( ) const
01361 {
01362 return m_sortingAlphabetical;
01363 }
01364
01365 Qt::CaseSensitivity KateCompletionModel::sortingCaseSensitivity( ) const
01366 {
01367 return m_sortingCaseSensitivity;
01368 }
01369
01370 KateCompletionModel::Item::Item( bool doInitialMatch, KateCompletionModel* m, const HierarchicalModelHandler& handler, ModelRow sr )
01371 : model(m)
01372 , m_sourceRow(sr)
01373 , matchCompletion(StartsWithMatch)
01374 , matchFilters(true)
01375 , m_haveExactMatch(false)
01376 {
01377
01378 inheritanceDepth = handler.getData(CodeCompletionModel::InheritanceDepth, m_sourceRow.second).toInt();
01379
01380 QModelIndex nameSibling = sr.second.sibling(sr.second.row(), CodeCompletionModel::Name);
01381 m_nameColumn = nameSibling.data(Qt::DisplayRole).toString();
01382
01383 if(doInitialMatch) {
01384 filter();
01385 match();
01386 }
01387 }
01388
01389 bool KateCompletionModel::Item::operator <( const Item & rhs ) const
01390 {
01391 int ret = 0;
01392
01393
01394
01395 if( model->isSortingByInheritanceDepth() )
01396 ret = inheritanceDepth - rhs.inheritanceDepth;
01397
01398 if (ret == 0 && model->isSortingAlphabetical()) {
01399 if(!m_completionSortingName.isEmpty() && !rhs.m_completionSortingName.isEmpty())
01400
01401 ret = QString::compare(m_completionSortingName, rhs.m_completionSortingName);
01402 else
01403 ret = QString::compare(completionSortingName(), rhs.completionSortingName());
01404 }
01405
01406 if( ret == 0 ) {
01407
01408 ret = m_sourceRow.second.row() - rhs.m_sourceRow.second.row();
01409 }
01410
01411 return ret < 0;
01412 }
01413
01414 QString KateCompletionModel::Item::completionSortingName( ) const
01415 {
01416 if(m_completionSortingName.isEmpty()) {
01417 m_completionSortingName = m_nameColumn;
01418 if (model->sortingCaseSensitivity() == Qt::CaseInsensitive)
01419 m_completionSortingName = m_completionSortingName.toLower();
01420 }
01421
01422 return m_completionSortingName;
01423 }
01424
01425 void KateCompletionModel::Group::addItem( Item i, bool notifyModel )
01426 {
01427 if (isEmpty)
01428 notifyModel = false;
01429
01430 QModelIndex groupIndex;
01431 if (notifyModel)
01432 groupIndex = model->indexForGroup(this);
01433
01434 if (model->isSortingEnabled()) {
01435
01436 prefilter.insert(qUpperBound(prefilter.begin(), prefilter.end(), i), i);
01437 if(i.isVisible()) {
01438 QList<Item>::iterator it = qUpperBound(filtered.begin(), filtered.end(), i);
01439 uint rowNumber = it - filtered.begin();
01440
01441 if(notifyModel)
01442 model->beginInsertRows(groupIndex, rowNumber, rowNumber);
01443
01444 filtered.insert(it, i);
01445 }
01446 } else {
01447 if(notifyModel)
01448 model->beginInsertRows(groupIndex, prefilter.size(), prefilter.size());
01449 if (i.isVisible())
01450 prefilter.append(i);
01451 }
01452
01453 if(notifyModel)
01454 model->endInsertRows();
01455 }
01456
01457 bool KateCompletionModel::Group::removeItem(const ModelRow& row)
01458 {
01459 for (int pi = 0; pi < prefilter.count(); ++pi)
01460 if (prefilter[pi].sourceRow() == row) {
01461 int index = rowOf(row);
01462 if (index != -1)
01463 model->beginRemoveRows(model->indexForGroup(this), index, index);
01464
01465 filtered.removeAt(index);
01466 prefilter.removeAt(pi);
01467
01468 if (index != -1)
01469 model->endRemoveRows();
01470
01471 return index != -1;
01472 }
01473
01474 Q_ASSERT(false);
01475 return false;
01476 }
01477
01478 KateCompletionModel::Group::Group( KateCompletionModel * m )
01479 : model(m)
01480 , isEmpty(true)
01481 , customSortingKey(-1)
01482 {
01483 Q_ASSERT(model);
01484 }
01485
01486 void KateCompletionModel::setSortingAlphabetical( bool alphabetical )
01487 {
01488 if (m_sortingAlphabetical != alphabetical) {
01489 m_sortingAlphabetical = alphabetical;
01490 resort();
01491 }
01492 }
01493
01494 void KateCompletionModel::Group::resort( )
01495 {
01496 qStableSort(prefilter.begin(), prefilter.end());
01497
01498 filtered.clear();
01499 foreach (const Item& i, prefilter)
01500 if (i.isVisible())
01501 filtered.append(i);
01502
01503 model->hideOrShowGroup(this);
01504
01505 }
01506
01507 void KateCompletionModel::setSortingCaseSensitivity( Qt::CaseSensitivity cs )
01508 {
01509 if (m_sortingCaseSensitivity != cs) {
01510 m_sortingCaseSensitivity = cs;
01511 resort();
01512 }
01513 }
01514
01515 void KateCompletionModel::resort( )
01516 {
01517 foreach (Group* g, m_rowTable)
01518 g->resort();
01519
01520 foreach (Group* g, m_emptyGroups)
01521 g->resort();
01522
01523 emit contentGeometryChanged();
01524 }
01525
01526 bool KateCompletionModel::Item::isValid( ) const
01527 {
01528 return model && m_sourceRow.first && m_sourceRow.second.row() >= 0;
01529 }
01530
01531 void KateCompletionModel::Group::clear( )
01532 {
01533 prefilter.clear();
01534 filtered.clear();
01535 isEmpty = true;
01536 }
01537
01538 bool KateCompletionModel::filterContextMatchesOnly( ) const
01539 {
01540 return m_filterContextMatchesOnly;
01541 }
01542
01543 void KateCompletionModel::setFilterContextMatchesOnly( bool filter )
01544 {
01545 if (m_filterContextMatchesOnly != filter) {
01546 m_filterContextMatchesOnly = filter;
01547 refilter();
01548 }
01549 }
01550
01551 bool KateCompletionModel::filterByAttribute( ) const
01552 {
01553 return m_filterByAttribute;
01554 }
01555
01556 void KateCompletionModel::setFilterByAttribute( bool filter )
01557 {
01558 if (m_filterByAttribute == filter) {
01559 m_filterByAttribute = filter;
01560 refilter();
01561 }
01562 }
01563
01564 KTextEditor::CodeCompletionModel::CompletionProperties KateCompletionModel::filterAttributes( ) const
01565 {
01566 return m_filterAttributes;
01567 }
01568
01569 void KateCompletionModel::setFilterAttributes( KTextEditor::CodeCompletionModel::CompletionProperties attributes )
01570 {
01571 if (m_filterAttributes == attributes) {
01572 m_filterAttributes = attributes;
01573 refilter();
01574 }
01575 }
01576
01577 int KateCompletionModel::maximumInheritanceDepth( ) const
01578 {
01579 return m_maximumInheritanceDepth;
01580 }
01581
01582 void KateCompletionModel::setMaximumInheritanceDepth( int maxDepth )
01583 {
01584 if (m_maximumInheritanceDepth != maxDepth) {
01585 m_maximumInheritanceDepth = maxDepth;
01586 refilter();
01587 }
01588 }
01589
01590 void KateCompletionModel::refilter( )
01591 {
01592 m_ungrouped->refilter();
01593
01594 foreach (Group* g, m_rowTable)
01595 if(g != m_argumentHints)
01596 g->refilter();
01597
01598 foreach (Group* g, m_emptyGroups)
01599 if(g != m_argumentHints)
01600 g->refilter();
01601
01602 updateBestMatches();
01603
01604 clearExpanding();
01605 }
01606
01607 void KateCompletionModel::Group::refilter( )
01608 {
01609 filtered.clear();
01610 foreach (const Item& i, prefilter)
01611 if (!i.isFiltered())
01612 filtered.append(i);
01613 }
01614
01615 bool KateCompletionModel::Item::filter( )
01616 {
01617 matchFilters = false;
01618
01619 if (model->isFilteringEnabled()) {
01620 QModelIndex sourceIndex = m_sourceRow.second.sibling(m_sourceRow.second.row(), CodeCompletionModel::Name);
01621
01622 if (model->filterContextMatchesOnly()) {
01623 QVariant contextMatch = sourceIndex.data(CodeCompletionModel::MatchQuality);
01624 if (contextMatch.canConvert(QVariant::Int) && !contextMatch.toInt())
01625 goto filter;
01626 }
01627
01628 if (model->filterByAttribute()) {
01629 int completionFlags = sourceIndex.data(CodeCompletionModel::CompletionRole).toInt();
01630 if (model->filterAttributes() & completionFlags)
01631 goto filter;
01632 }
01633
01634 if (model->maximumInheritanceDepth() > 0) {
01635 int inheritanceDepth = sourceIndex.data(CodeCompletionModel::InheritanceDepth).toInt();
01636 if (inheritanceDepth > model->maximumInheritanceDepth())
01637 goto filter;
01638 }
01639 }
01640
01641 matchFilters = true;
01642
01643 filter:
01644 return matchFilters;
01645 }
01646
01647 bool KateCompletionModel::shouldMatchHideCompletionList() const {
01648
01650 foreach(Group* group, m_rowTable)
01651 foreach(const Item& item, group->filtered)
01652 if(item.haveExactMatch()) {
01653 KTextEditor::CodeCompletionModelControllerInterface2* iface2 = dynamic_cast<KTextEditor::CodeCompletionModelControllerInterface2*>(item.sourceRow().first);
01654 if(!iface2 || iface2->matchingItem(item.sourceRow().second) == KTextEditor::CodeCompletionModelControllerInterface2::HideListIfAutomaticInvocation)
01655 return true;
01656 }
01657 return false;
01658 }
01659
01660 KateCompletionModel::Item::MatchType KateCompletionModel::Item::match()
01661 {
01662
01663 QModelIndex sourceIndex = m_sourceRow.second.sibling(m_sourceRow.second.row(), CodeCompletionModel::Name);
01664
01665 QString match = model->currentCompletion(m_sourceRow.first);
01666
01667 m_haveExactMatch = false;
01668
01669
01670 if (match.isEmpty())
01671 return PerfectMatch;
01672
01673 matchCompletion = (m_nameColumn.startsWith(match, model->matchCaseSensitivity()) ? StartsWithMatch : NoMatch);
01674
01675 if(matchCompletion && match.length() == m_nameColumn.length()) {
01676 matchCompletion = PerfectMatch;
01677 m_haveExactMatch = true;
01678 }
01679
01680 return matchCompletion;
01681 }
01682
01683 QString KateCompletionModel::propertyName( KTextEditor::CodeCompletionModel::CompletionProperty property )
01684 {
01685 switch (property) {
01686 case CodeCompletionModel::Public:
01687 return i18n("Public");
01688
01689 case CodeCompletionModel::Protected:
01690 return i18n("Protected");
01691
01692 case CodeCompletionModel::Private:
01693 return i18n("Private");
01694
01695 case CodeCompletionModel::Static:
01696 return i18n("Static");
01697
01698 case CodeCompletionModel::Const:
01699 return i18n("Constant");
01700
01701 case CodeCompletionModel::Namespace:
01702 return i18n("Namespace");
01703
01704 case CodeCompletionModel::Class:
01705 return i18n("Class");
01706
01707 case CodeCompletionModel::Struct:
01708 return i18n("Struct");
01709
01710 case CodeCompletionModel::Union:
01711 return i18n("Union");
01712
01713 case CodeCompletionModel::Function:
01714 return i18n("Function");
01715
01716 case CodeCompletionModel::Variable:
01717 return i18n("Variable");
01718
01719 case CodeCompletionModel::Enum:
01720 return i18n("Enumeration");
01721
01722 case CodeCompletionModel::Template:
01723 return i18n("Template");
01724
01725 case CodeCompletionModel::Virtual:
01726 return i18n("Virtual");
01727
01728 case CodeCompletionModel::Override:
01729 return i18n("Override");
01730
01731 case CodeCompletionModel::Inline:
01732 return i18n("Inline");
01733
01734 case CodeCompletionModel::Friend:
01735 return i18n("Friend");
01736
01737 case CodeCompletionModel::Signal:
01738 return i18n("Signal");
01739
01740 case CodeCompletionModel::Slot:
01741 return i18n("Slot");
01742
01743 case CodeCompletionModel::LocalScope:
01744 return i18n("Local Scope");
01745
01746 case CodeCompletionModel::NamespaceScope:
01747 return i18n("Namespace Scope");
01748
01749 case CodeCompletionModel::GlobalScope:
01750 return i18n("Global Scope");
01751
01752 default:
01753 return i18n("Unknown Property");
01754 }
01755 }
01756
01757 bool KateCompletionModel::Item::isVisible( ) const
01758 {
01759 return matchCompletion && matchFilters;
01760 }
01761
01762 bool KateCompletionModel::Item::isFiltered( ) const
01763 {
01764 return !matchFilters;
01765 }
01766
01767 bool KateCompletionModel::Item::isMatching( ) const
01768 {
01769 return matchFilters;
01770 }
01771
01772 const KateCompletionModel::ModelRow& KateCompletionModel::Item::sourceRow( ) const
01773 {
01774 return m_sourceRow;
01775 }
01776
01777 QString KateCompletionModel::currentCompletion( KTextEditor::CodeCompletionModel* model ) const
01778 {
01779 return m_currentMatch.value(model);
01780 }
01781
01782 Qt::CaseSensitivity KateCompletionModel::matchCaseSensitivity( ) const
01783 {
01784 return m_matchCaseSensitivity;
01785 }
01786
01787 void KateCompletionModel::addCompletionModel(KTextEditor::CodeCompletionModel * model)
01788 {
01789 if (m_completionModels.contains(model))
01790 return;
01791
01792 m_completionModels.append(model);
01793
01794 connect(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(slotRowsInserted(const QModelIndex&, int, int)));
01795 connect(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
01796 connect(model, SIGNAL(modelReset()), SLOT(slotModelReset()));
01797
01798
01799 createGroups();
01800 }
01801
01802 void KateCompletionModel::setCompletionModel(KTextEditor::CodeCompletionModel* model)
01803 {
01804 clearCompletionModels();
01805 addCompletionModel(model);
01806 }
01807
01808 void KateCompletionModel::setCompletionModels(const QList<KTextEditor::CodeCompletionModel*>& models)
01809 {
01810
01811
01812
01813 clearCompletionModels();
01814
01815 m_completionModels = models;
01816
01817 foreach (KTextEditor::CodeCompletionModel* model, models) {
01818 connect(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(slotRowsInserted(const QModelIndex&, int, int)));
01819 connect(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
01820 connect(model, SIGNAL(modelReset()), SLOT(slotModelReset()));
01821 }
01822
01823
01824 createGroups();
01825 }
01826
01827 QList< KTextEditor::CodeCompletionModel * > KateCompletionModel::completionModels() const
01828 {
01829 return m_completionModels;
01830 }
01831
01832 void KateCompletionModel::removeCompletionModel(CodeCompletionModel * model)
01833 {
01834 if (!model || !m_completionModels.contains(model))
01835 return;
01836
01837 m_currentMatch.remove(model);
01838
01839 clearGroups(false);
01840
01841 model->disconnect(this);
01842
01843 m_completionModels.removeAll(model);
01844
01845 if (!m_completionModels.isEmpty()) {
01846
01847 createGroups();
01848 }else{
01849 emit contentGeometryChanged();
01850 reset();
01851 }
01852 }
01853
01854
01855 void KateCompletionModel::updateBestMatches() {
01856 int maxMatches = 300;
01857
01858 m_updateBestMatchesTimer->stop();
01859
01860 typedef QMultiMap<int, QPair<int, ModelRow> > BestMatchMap;
01861 BestMatchMap matches;
01862
01863 if(!hasGroups()) {
01864
01865 QMultiMap<int, int> rowsForQuality;
01866
01867 int row = 0;
01868 foreach(const Item& item, m_ungrouped->filtered) {
01869 ModelRow source = item.sourceRow();
01870
01871 QVariant v = source.second.data(CodeCompletionModel::BestMatchesCount);
01872
01873 if( v.type() == QVariant::Int && v.toInt() > 0 ) {
01874 int quality = contextMatchQuality(source);
01875 if(quality > 0)
01876 rowsForQuality.insert(quality, row);
01877 }
01878
01879 ++row;
01880 --maxMatches;
01881 if(maxMatches < 0)
01882 break;
01883 }
01884
01885 if(!rowsForQuality.isEmpty()) {
01886
01887 QSet<int> movedToFront;
01888 QList<Item> newFiltered;
01889 for(QMultiMap<int, int>::const_iterator it = rowsForQuality.constBegin(); it != rowsForQuality.constEnd(); ++it) {
01890 newFiltered.prepend(m_ungrouped->filtered[it.value()]);
01891 movedToFront.insert(it.value());
01892 }
01893
01894 {
01895 uint size = m_ungrouped->filtered.size();
01896 for(uint a = 0; a < size; ++a)
01897 if(!movedToFront.contains(a))
01898 newFiltered.append(m_ungrouped->filtered[a]);
01899 }
01900 m_ungrouped->filtered = newFiltered;
01901 }
01902 return;
01903 }
01904
01906 foreach (Group* g, m_rowTable) {
01907 if( g == m_bestMatches )
01908 continue;
01909 for( int a = 0; a < g->filtered.size(); a++ )
01910 {
01911 ModelRow source = g->filtered[a].sourceRow();
01912
01913 QVariant v = source.second.data(CodeCompletionModel::BestMatchesCount);
01914
01915 if( v.type() == QVariant::Int && v.toInt() > 0 ) {
01916
01917
01918 int quality = contextMatchQuality(source);
01919 if( quality > 0 )
01920 matches.insert(quality, qMakePair(v.toInt(), g->filtered[a].sourceRow()));
01921 --maxMatches;
01922 }
01923
01924 if( maxMatches < 0 )
01925 break;
01926 }
01927 if( maxMatches < 0 )
01928 break;
01929 }
01930
01931
01932
01933 int cnt = 0;
01934 int matchesSum = 0;
01935 BestMatchMap::const_iterator it = matches.constEnd();
01936 while( it != matches.constBegin() )
01937 {
01938 --it;
01939 ++cnt;
01940 matchesSum += (*it).first;
01941 if( cnt > matchesSum / cnt )
01942 break;
01943 }
01944
01945 m_bestMatches->filtered.clear();
01946
01947 it = matches.constEnd();
01948
01949 while( it != matches.constBegin() && cnt > 0 )
01950 {
01951 --it;
01952 --cnt;
01953
01954 m_bestMatches->filtered.append( Item( true, this, HierarchicalModelHandler((*it).second.first), (*it).second) );
01955 }
01956
01957 hideOrShowGroup(m_bestMatches);
01958 }
01959
01960 void KateCompletionModel::rowSelected(const QModelIndex& row) {
01961 ExpandingWidgetModel::rowSelected(row);
01963 int rc = widget()->argumentHintModel()->rowCount(QModelIndex());
01964 if( rc == 0 ) return;
01965
01966
01967 QModelIndex start = widget()->argumentHintModel()->index(0,0);
01968 QModelIndex end = widget()->argumentHintModel()->index(rc-1,0);
01969
01970 widget()->argumentHintModel()->emitDataChanged(start, end);
01971 }
01972
01973 void KateCompletionModel::clearCompletionModels()
01974 {
01975 foreach (CodeCompletionModel * model, m_completionModels)
01976 model->disconnect(this);
01977
01978 m_completionModels.clear();
01979
01980 m_currentMatch.clear();
01981
01982 clearGroups();
01983 }
01984
01985 #include "katecompletionmodel.moc"
01986