Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsbrowserproxymodel.cpp 3 : : --------------------- 4 : : begin : October 2018 5 : : copyright : (C) 2018 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgsbrowserproxymodel.h" 17 : : #include "qgsbrowsermodel.h" 18 : : 19 : 0 : QgsBrowserProxyModel::QgsBrowserProxyModel( QObject *parent ) 20 : 0 : : QSortFilterProxyModel( parent ) 21 : 0 : { 22 : 0 : setDynamicSortFilter( true ); 23 : 0 : setSortRole( QgsBrowserModel::SortRole ); 24 : 0 : setSortCaseSensitivity( Qt::CaseInsensitive ); 25 : 0 : sort( 0 ); 26 : 0 : } 27 : : 28 : 0 : void QgsBrowserProxyModel::setBrowserModel( QgsBrowserModel *model ) 29 : : { 30 : 0 : mModel = model; 31 : 0 : setSourceModel( model ); 32 : 0 : } 33 : : 34 : 0 : QgsDataItem *QgsBrowserProxyModel::dataItem( const QModelIndex &index ) const 35 : : { 36 : 0 : const QModelIndex sourceIndex = mapToSource( index ); 37 : 0 : return mModel ? mModel->dataItem( sourceIndex ) : nullptr; 38 : : } 39 : : 40 : 0 : void QgsBrowserProxyModel::setFilterSyntax( FilterSyntax syntax ) 41 : : { 42 : 0 : if ( mPatternSyntax == syntax ) 43 : 0 : return; 44 : 0 : mPatternSyntax = syntax; 45 : 0 : updateFilter(); 46 : 0 : } 47 : : 48 : 0 : QgsBrowserProxyModel::FilterSyntax QgsBrowserProxyModel::filterSyntax() const 49 : : { 50 : 0 : return mPatternSyntax; 51 : : } 52 : : 53 : 0 : void QgsBrowserProxyModel::setFilterString( const QString &filter ) 54 : : { 55 : 0 : if ( mFilter == filter ) 56 : 0 : return; 57 : 0 : mFilter = filter; 58 : 0 : updateFilter(); 59 : 0 : } 60 : : 61 : 0 : QString QgsBrowserProxyModel::filterString() const 62 : : { 63 : 0 : return mFilter; 64 : : } 65 : : 66 : 0 : void QgsBrowserProxyModel::setFilterCaseSensitivity( Qt::CaseSensitivity sensitivity ) 67 : : { 68 : 0 : mCaseSensitivity = sensitivity; 69 : 0 : updateFilter(); 70 : 0 : } 71 : : 72 : 0 : Qt::CaseSensitivity QgsBrowserProxyModel::caseSensitivity() const 73 : : { 74 : 0 : return mCaseSensitivity; 75 : : } 76 : : 77 : 0 : void QgsBrowserProxyModel::updateFilter() 78 : : { 79 : 0 : mREList.clear(); 80 : 0 : switch ( mPatternSyntax ) 81 : : { 82 : : case Normal: 83 : : { 84 : 0 : const QStringList filterParts = mFilter.split( '|' ); 85 : 0 : for ( const QString &f : filterParts ) 86 : : { 87 : 0 : QRegExp rx( QStringLiteral( "*%1*" ).arg( f.trimmed() ) ); 88 : 0 : rx.setPatternSyntax( QRegExp::Wildcard ); 89 : 0 : rx.setCaseSensitivity( mCaseSensitivity ); 90 : 0 : mREList.append( rx ); 91 : 0 : } 92 : : break; 93 : 0 : } 94 : : case Wildcards: 95 : : { 96 : 0 : const QStringList filterParts = mFilter.split( '|' ); 97 : 0 : for ( const QString &f : filterParts ) 98 : : { 99 : 0 : QRegExp rx( f.trimmed() ); 100 : 0 : rx.setPatternSyntax( QRegExp::Wildcard ); 101 : 0 : rx.setCaseSensitivity( mCaseSensitivity ); 102 : 0 : mREList.append( rx ); 103 : 0 : } 104 : : break; 105 : 0 : } 106 : : case RegularExpression: 107 : : { 108 : 0 : QRegExp rx( mFilter.trimmed() ); 109 : 0 : rx.setPatternSyntax( QRegExp::RegExp ); 110 : 0 : rx.setCaseSensitivity( mCaseSensitivity ); 111 : 0 : mREList.append( rx ); 112 : : break; 113 : 0 : } 114 : : } 115 : 0 : invalidateFilter(); 116 : 0 : } 117 : : 118 : 0 : bool QgsBrowserProxyModel::filterAcceptsString( const QString &value ) const 119 : : { 120 : 0 : switch ( mPatternSyntax ) 121 : : { 122 : : case Normal: 123 : : case Wildcards: 124 : : { 125 : 0 : for ( const QRegExp &rx : mREList ) 126 : : { 127 : 0 : if ( rx.exactMatch( value ) ) 128 : 0 : return true; 129 : : } 130 : 0 : break; 131 : : } 132 : : 133 : : case RegularExpression: 134 : : { 135 : 0 : for ( const QRegExp &rx : mREList ) 136 : : { 137 : 0 : if ( rx.indexIn( value ) != -1 ) 138 : 0 : return true; 139 : : } 140 : 0 : break; 141 : : } 142 : : } 143 : : 144 : 0 : return false; 145 : 0 : } 146 : : 147 : 0 : bool QgsBrowserProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const 148 : : { 149 : 0 : if ( ( mFilter.isEmpty() && !mFilterByLayerType && mHiddenDataItemsKeys.empty() && mShownDataItemsKeys.empty() ) || !mModel ) 150 : 0 : return true; 151 : : 152 : 0 : QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent ); 153 : 0 : if ( !filterAcceptsProviderKey( sourceIndex ) || !filterRootAcceptsProviderKey( sourceIndex ) ) 154 : 0 : return false; 155 : : 156 : 0 : if ( ! mShowLayers ) 157 : : { 158 : 0 : QgsDataItem *item = mModel->dataItem( sourceIndex ); 159 : 0 : if ( qobject_cast< QgsLayerItem * >( item ) ) 160 : : { 161 : 0 : return false; 162 : : } 163 : 0 : } 164 : : 165 : 0 : return filterAcceptsItem( sourceIndex ) || filterAcceptsAncestor( sourceIndex ) || filterAcceptsDescendant( sourceIndex ); 166 : 0 : } 167 : : 168 : 0 : bool QgsBrowserProxyModel::showLayers() const 169 : : { 170 : 0 : return mShowLayers; 171 : : } 172 : : 173 : 0 : void QgsBrowserProxyModel::setShowLayers( bool showLayers ) 174 : : { 175 : 0 : mShowLayers = showLayers; 176 : 0 : } 177 : : 178 : 0 : QgsMapLayerType QgsBrowserProxyModel::layerType() const 179 : : { 180 : 0 : return mLayerType; 181 : : } 182 : : 183 : 0 : void QgsBrowserProxyModel::setLayerType( QgsMapLayerType type ) 184 : : { 185 : 0 : mLayerType = type; 186 : 0 : invalidateFilter(); 187 : 0 : } 188 : : 189 : 0 : void QgsBrowserProxyModel::setFilterByLayerType( bool filterByLayerType ) 190 : : { 191 : 0 : mFilterByLayerType = filterByLayerType; 192 : 0 : invalidateFilter(); 193 : 0 : } 194 : : 195 : 0 : bool QgsBrowserProxyModel::filterAcceptsAncestor( const QModelIndex &sourceIndex ) const 196 : : { 197 : 0 : if ( !mModel ) 198 : 0 : return true; 199 : : 200 : 0 : if ( mFilterByLayerType ) 201 : 0 : return false; 202 : : 203 : 0 : QModelIndex sourceParentIndex = mModel->parent( sourceIndex ); 204 : 0 : if ( !sourceParentIndex.isValid() ) 205 : 0 : return false; 206 : 0 : if ( filterAcceptsItem( sourceParentIndex ) ) 207 : 0 : return true; 208 : : 209 : 0 : return filterAcceptsAncestor( sourceParentIndex ); 210 : 0 : } 211 : : 212 : 0 : bool QgsBrowserProxyModel::filterAcceptsDescendant( const QModelIndex &sourceIndex ) const 213 : 0 : { 214 : 0 : if ( !mModel ) 215 : 0 : return true; 216 : 0 : 217 : 0 : for ( int i = 0; i < mModel->rowCount( sourceIndex ); i++ ) 218 : 0 : { 219 : 0 : QModelIndex sourceChildIndex = mModel->index( i, 0, sourceIndex ); 220 : 0 : if ( filterAcceptsItem( sourceChildIndex ) ) 221 : 0 : return true; 222 : 0 : if ( filterAcceptsDescendant( sourceChildIndex ) ) 223 : 0 : return true; 224 : 0 : } 225 : 0 : return false; 226 : 0 : } 227 : : 228 : 0 : bool QgsBrowserProxyModel::filterAcceptsItem( const QModelIndex &sourceIndex ) const 229 : : { 230 : 0 : if ( !mModel ) 231 : 0 : return true; 232 : : 233 : 0 : if ( mFilterByLayerType ) 234 : : { 235 : 0 : QgsDataItem *item = mModel->dataItem( sourceIndex ); 236 : 0 : if ( QgsLayerItem *layerItem = qobject_cast< QgsLayerItem * >( item ) ) 237 : : { 238 : 0 : if ( layerItem->mapLayerType() != mLayerType ) 239 : 0 : return false; 240 : 0 : } 241 : 0 : else if ( !qobject_cast< QgsDataCollectionItem * >( item ) ) 242 : 0 : return false; 243 : 0 : } 244 : : 245 : 0 : if ( !mFilter.isEmpty() ) 246 : : { 247 : : //accept item if either displayed text or comment role matches string 248 : 0 : QString comment = mModel->data( sourceIndex, QgsBrowserModel::CommentRole ).toString(); 249 : 0 : return ( filterAcceptsString( mModel->data( sourceIndex, Qt::DisplayRole ).toString() ) 250 : 0 : || ( !comment.isEmpty() && filterAcceptsString( comment ) ) ); 251 : 0 : } 252 : : 253 : 0 : return true; 254 : 0 : } 255 : : 256 : 0 : bool QgsBrowserProxyModel::filterAcceptsProviderKey( const QModelIndex &sourceIndex ) const 257 : : { 258 : 0 : if ( !mModel ) 259 : 0 : return true; 260 : : 261 : 0 : const QString providerKey = mModel->data( sourceIndex, QgsBrowserModel::ProviderKeyRole ).toString(); 262 : 0 : if ( providerKey.isEmpty() ) 263 : 0 : return true; 264 : : 265 : 0 : return !mHiddenDataItemsKeys.contains( providerKey ) && ( mShownDataItemsKeys.isEmpty() || mShownDataItemsKeys.contains( providerKey ) ); 266 : 0 : } 267 : : 268 : 0 : bool QgsBrowserProxyModel::filterRootAcceptsProviderKey( const QModelIndex &sourceIndex ) const 269 : : { 270 : 0 : if ( !mModel ) 271 : 0 : return true; 272 : : 273 : 0 : QModelIndex sourceParentIndex = mModel->parent( sourceIndex ); 274 : 0 : if ( !sourceParentIndex.isValid() ) 275 : : { 276 : 0 : return filterAcceptsProviderKey( sourceIndex ); 277 : : } 278 : : 279 : 0 : return filterRootAcceptsProviderKey( sourceParentIndex ); 280 : 0 : } 281 : : 282 : 0 : void QgsBrowserProxyModel::setHiddenDataItemProviderKeyFilter( const QStringList &filter ) 283 : : { 284 : 0 : mHiddenDataItemsKeys = filter; 285 : 0 : invalidateFilter(); 286 : 0 : } 287 : : 288 : 0 : void QgsBrowserProxyModel::setShownDataItemProviderKeyFilter( const QStringList &filter ) 289 : : { 290 : 0 : mShownDataItemsKeys = filter; 291 : 0 : invalidateFilter(); 292 : 0 : } 293 : : 294 : : 295 : 0 : bool QgsBrowserProxyModel::hasChildren( const QModelIndex &parent ) const 296 : : { 297 : 0 : bool isFertile { QSortFilterProxyModel::hasChildren( parent ) }; 298 : 0 : if ( isFertile && parent.isValid() ) 299 : : { 300 : 0 : QgsDataItem *item = dataItem( parent ); 301 : 0 : if ( ! mShowLayers ) 302 : : { 303 : 0 : return ! item->layerCollection(); 304 : : } 305 : : // Hide everything below layers if filter is set 306 : 0 : else if ( mFilterByLayerType && qobject_cast< QgsLayerItem * >( item ) ) 307 : : { 308 : 0 : return false; 309 : : } 310 : 0 : } 311 : 0 : return isFertile; 312 : 0 : }