• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katecompletionmodel.cpp

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

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal