Kate
kateargumenthintmodel.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries and the Kate part. 00002 * 00003 * Copyright (C) 2007 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 as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kateargumenthintmodel.h" 00022 00023 #include <QTextFormat> 00024 #include <QGridLayout> 00025 #include <kapplication.h> 00026 00027 #include <ktexteditor/codecompletionmodel.h> 00028 #include "katecompletionwidget.h" 00029 #include "kateargumenthinttree.h" 00030 #include "katecompletiontree.h" 00031 00032 using namespace KTextEditor; 00033 00034 void KateArgumentHintModel::clear() { 00035 m_rows.clear(); 00036 clearExpanding(); 00037 } 00038 00039 QModelIndex KateArgumentHintModel::mapToSource( const QModelIndex & index ) const { 00040 if( index.row() < 0 || index.row() >= m_rows.count() ) 00041 return QModelIndex(); 00042 00043 if( m_rows[index.row()] < 0 || m_rows[index.row()] >= group()->filtered.count() ) 00044 return QModelIndex(); 00045 00046 KateCompletionModel::ModelRow source = group()->filtered[m_rows[index.row()]].sourceRow(); 00047 if( !source.first ) { 00048 kDebug( 13035 ) << "KateArgumentHintModel::data: Row does not exist in source"; 00049 return QModelIndex(); 00050 } 00051 00052 QModelIndex sourceIndex = source.second.sibling(source.second.row(), index.column()); 00053 00054 return sourceIndex; 00055 } 00056 00057 void KateArgumentHintModel::parentModelReset() { 00058 clear(); 00059 buildRows(); 00060 } 00061 00062 void KateArgumentHintModel::buildRows() { 00063 m_rows.clear(); 00064 QMap<int, QList<int> > m_depths; //Map each hint-depth to a list of functions of that depth 00065 for( int a = 0; a < group()->filtered.count(); a++ ) { 00066 KateCompletionModel::ModelRow source = group()->filtered[a].sourceRow(); 00067 QModelIndex sourceIndex = source.second.sibling(source.second.row(), 0); 00068 QVariant v = sourceIndex.data(CodeCompletionModel::ArgumentHintDepth); 00069 if( v.type() == QVariant::Int ) { 00070 QList<int>& lst( m_depths[v.toInt()] ); 00071 lst << a; 00072 } 00073 } 00074 00075 for( QMap<int, QList<int> >::const_iterator it = m_depths.constBegin(); it != m_depths.constEnd(); ++it ) { 00076 foreach( int row, *it ) 00077 m_rows.push_front(row);//Insert filtered in reversed order 00078 m_rows.push_front( -it.key() ); 00079 } 00080 00081 reset(); 00082 emit contentStateChanged(!m_rows.isEmpty()); 00083 } 00084 00085 KateArgumentHintModel::KateArgumentHintModel( KateCompletionWidget* parent ) : ExpandingWidgetModel(parent), m_parent(parent) { 00086 connect(parent->model(), SIGNAL(modelReset()), this, SLOT(parentModelReset())); 00087 connect(parent->model(), SIGNAL(argumentHintsChanged()), this, SLOT(parentModelReset())); 00088 } 00089 00090 QVariant KateArgumentHintModel::data ( const QModelIndex & index, int role ) const { 00091 if( index.row() < 0 || index.row() >= m_rows.count() ) { 00092 //kDebug( 13035 ) << "KateArgumentHintModel::data: index out of bound: " << index.row() << " total filtered: " << m_rows.count(); 00093 return QVariant(); 00094 } 00095 00096 if( m_rows[index.row()] < 0 ) { 00097 //Show labels 00098 if( role == Qt::DisplayRole && index.column() == 0 ) { 00099 return QString(); //QString("Depth %1").arg(-m_rows[index.row()]); 00100 } else if( role == Qt::BackgroundRole ) { 00101 return KApplication::kApplication()->palette().toolTipBase().color(); 00102 }else if( role == Qt::ForegroundRole ) { 00103 return KApplication::kApplication()->palette().toolTipText().color(); 00104 }else{ 00105 return QVariant(); 00106 } 00107 } 00108 00109 if( m_rows[index.row()] < 0 || m_rows[index.row()] >= group()->filtered.count() ) { 00110 kDebug( 13035 ) << "KateArgumentHintModel::data: index out of bound: " << m_rows[index.row()] << " total filtered: " << group()->filtered.count(); 00111 return QVariant(); 00112 } 00113 00114 KateCompletionModel::ModelRow source = group()->filtered[m_rows[index.row()]].sourceRow(); 00115 if( !source.first ) { 00116 kDebug( 13035 ) << "KateArgumentHintModel::data: Row does not exist in source"; 00117 return QVariant(); 00118 } 00119 00120 if( index.column() == 0 ) { 00121 switch( role ) { 00122 case Qt::DecorationRole: 00123 { 00124 //Show the expand-handle 00125 model()->cacheIcons(); 00126 00127 if( !isExpanded(index ) ) 00128 return QVariant( model()->m_collapsedIcon ); 00129 else 00130 return QVariant( model()->m_expandedIcon ); 00131 } 00132 case Qt::DisplayRole: 00133 //Ignore text in the first column(we create our own compound text in the second) 00134 return QVariant(); 00135 } 00136 } 00137 00138 QModelIndex sourceIndex = source.second.sibling(source.second.row(), index.column()); 00139 00140 if( !sourceIndex.isValid() ) { 00141 kDebug( 13035 ) << "KateArgumentHintModel::data: Source-index is not valid"; 00142 return QVariant(); 00143 } 00144 00145 switch( role ) { 00146 case Qt::DisplayRole: 00147 { 00148 //Construct the text 00149 QString totalText; 00150 for( int a = CodeCompletionModel::Prefix; a <= CodeCompletionModel::Postfix; a++ ) 00151 if( a != CodeCompletionModel::Scope ) //Skip the scope 00152 totalText += source.second.sibling(source.second.row(), a).data(Qt::DisplayRole).toString() + ' '; 00153 00154 00155 return QVariant(totalText); 00156 } 00157 case CodeCompletionModel::HighlightingMethod: 00158 { 00159 //Return that we are doing custom-highlighting of one of the sub-strings does it 00160 for( int a = CodeCompletionModel::Prefix; a <= CodeCompletionModel::Postfix; a++ ) { 00161 QVariant method = source.second.sibling(source.second.row(), a).data(CodeCompletionModel::HighlightingMethod); 00162 if( method.type() == QVariant::Int && method.toInt() == CodeCompletionModel::CustomHighlighting) 00163 return QVariant(CodeCompletionModel::CustomHighlighting); 00164 } 00165 00166 return QVariant(); 00167 } 00168 case CodeCompletionModel::CustomHighlight: 00169 { 00170 QStringList strings; 00171 00172 //Collect strings 00173 for( int a = CodeCompletionModel::Prefix; a <= CodeCompletionModel::Postfix; a++ ) 00174 strings << source.second.sibling(source.second.row(), a).data(Qt::DisplayRole).toString(); 00175 00176 QList<QVariantList> highlights; 00177 00178 //Collect custom-highlightings 00179 for( int a = CodeCompletionModel::Prefix; a <= CodeCompletionModel::Postfix; a++ ) 00180 highlights << source.second.sibling(source.second.row(), a).data(CodeCompletionModel::CustomHighlight).toList(); 00181 00182 //Replace invalid QTextFormats with match-quality color or yellow. 00183 for( QList<QVariantList>::iterator it = highlights.begin(); it != highlights.end(); ++it ) 00184 { 00185 QVariantList& list( *it ); 00186 00187 for( int a = 2; a < list.count(); a += 3 ) 00188 { 00189 if( list[a].canConvert<QTextFormat>() ) 00190 { 00191 QTextFormat f = list[a].value<QTextFormat>(); 00192 00193 if(!f.isValid()) 00194 { 00195 f = QTextFormat( QTextFormat::CharFormat ); 00196 uint color = matchColor( index ); 00197 00198 if( color ) 00199 f.setBackground( QBrush(color) ); 00200 else 00201 f.setBackground( Qt::yellow ); 00202 00203 list[a] = QVariant( f ); 00204 } 00205 } 00206 } 00207 } 00208 00209 00210 return mergeCustomHighlighting( strings, highlights, 1 ); 00211 } 00212 case Qt::DecorationRole: 00213 { 00214 //Redirect the decoration to the decoration of the item-column 00215 return source.second.sibling(source.second.row(), CodeCompletionModel::Icon).data(role); 00216 } 00217 } 00218 00219 QVariant v = ExpandingWidgetModel::data( index, role ); 00220 if( v.isValid() ) 00221 return v; 00222 else 00223 return sourceIndex.data( role ); 00224 } 00225 00226 int KateArgumentHintModel::rowCount ( const QModelIndex & parent ) const { 00227 if( !parent.isValid() ) 00228 return m_rows.count(); 00229 else 00230 return 0; 00231 } 00232 00233 int KateArgumentHintModel::columnCount ( const QModelIndex & /*parent*/ ) const { 00234 return 2; //2 Columns, one for the expand-handle, one for the signature 00235 } 00236 00237 KateCompletionModel::Group* KateArgumentHintModel::group() const { 00238 return model()->m_argumentHints; 00239 } 00240 00241 KateCompletionModel* KateArgumentHintModel::model() const { 00242 return m_parent->model(); 00243 } 00244 00245 QTreeView* KateArgumentHintModel::treeView() const { 00246 return m_parent->argumentHintTree(); 00247 } 00248 00249 void KateArgumentHintModel::emitDataChanged( const QModelIndex& start, const QModelIndex& end ) { 00250 emit dataChanged(start, end); 00251 } 00252 00253 bool KateArgumentHintModel::indexIsItem(const QModelIndex& index) const { 00254 return index.row() >= 0 && index.row() < m_rows.count() && m_rows[index.row()] >= 0; 00255 } 00256 00257 int KateArgumentHintModel::contextMatchQuality(const QModelIndex& index) const { 00258 int row=index.row(); 00259 if( row < 0 || row >= m_rows.count() ) 00260 return -1; 00261 00262 if( m_rows[row] < 0 || m_rows[row] >= group()->filtered.count() ) 00263 return -1; //Probably a label 00264 00265 KateCompletionModel::ModelRow source = group()->filtered[m_rows[row]].sourceRow(); 00266 if( !source.first ) 00267 return -1; 00268 00269 QModelIndex sourceIndex = source.second.sibling(source.second.row(), 0); 00270 00271 if( !sourceIndex.isValid() ) 00272 return -1; 00273 00274 int depth = sourceIndex.data(CodeCompletionModel::ArgumentHintDepth).toInt(); 00275 00276 switch(depth) { 00277 case 1: 00278 { 00279 //This argument-hint is on the lowest level, match it with the currently selected item in the completion-widget 00280 QModelIndex row = m_parent->treeView()->currentIndex(); 00281 if( !row.isValid() ) 00282 return -1; 00283 00284 QModelIndex selectedIndex = m_parent->model()->mapToSource( row ); 00285 if( !selectedIndex.isValid() ) 00286 return -1; 00287 00288 if( selectedIndex.model() != sourceIndex.model() ) 00289 return -1; //We can only match items from the same source-model 00290 00291 sourceIndex.data( CodeCompletionModel::SetMatchContext ); 00292 00293 QVariant v = selectedIndex.data( CodeCompletionModel::MatchQuality ); 00294 if( v.type() == QVariant::Int ) 00295 return v.toInt(); 00296 } 00297 break; 00298 default: 00299 //Do some other nice matching here in future 00300 break; 00301 } 00302 00303 return -1; 00304 } 00305 00306 #include "kateargumenthintmodel.moc"
KDE 4.6 API Reference