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