Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsbrowsermodel.cpp 00003 --------------------- 00004 begin : July 2011 00005 copyright : (C) 2011 by Martin Dobias 00006 email : wonder.sk at gmail.com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 #include <QDir> 00016 #include <QApplication> 00017 #include <QStyle> 00018 00019 #include "qgis.h" 00020 #include "qgsapplication.h" 00021 #include "qgsdataprovider.h" 00022 #include "qgsmimedatautils.h" 00023 #include "qgslogger.h" 00024 #include "qgsproviderregistry.h" 00025 00026 #include "qgsbrowsermodel.h" 00027 00028 #include <QSettings> 00029 00030 QgsBrowserModel::QgsBrowserModel( QObject *parent ) : 00031 QAbstractItemModel( parent ) 00032 { 00033 addRootItems(); 00034 } 00035 00036 QgsBrowserModel::~QgsBrowserModel() 00037 { 00038 removeRootItems(); 00039 } 00040 00041 void QgsBrowserModel::addRootItems() 00042 { 00043 // give the home directory a prominent first place 00044 QgsDirectoryItem *item = new QgsDirectoryItem( NULL, tr( "Home" ), QDir::homePath() ); 00045 QStyle *style = QApplication::style(); 00046 QIcon homeIcon( style->standardPixmap( QStyle::SP_DirHomeIcon ) ); 00047 item->setIcon( homeIcon ); 00048 connectItem( item ); 00049 mRootItems << item; 00050 00051 // add favourite directories 00052 QgsFavouritesItem *favitem = new QgsFavouritesItem( NULL, tr( "Favourites" ) ); 00053 if ( favitem ) 00054 { 00055 connectItem( favitem ); 00056 mRootItems << favitem; 00057 } 00058 00059 // add drives 00060 foreach( QFileInfo drive, QDir::drives() ) 00061 { 00062 QString path = drive.absolutePath(); 00063 QgsDirectoryItem *item = new QgsDirectoryItem( NULL, path, path ); 00064 00065 connectItem( item ); 00066 mRootItems << item; 00067 } 00068 00069 // Add non file top level items 00070 QStringList providersList = QgsProviderRegistry::instance()->providerList(); 00071 providersList.sort(); 00072 foreach( QString key, providersList ) 00073 { 00074 QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( key ); 00075 if ( !library ) 00076 continue; 00077 00078 dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) ); 00079 if ( !dataCapabilities ) 00080 { 00081 QgsDebugMsg( library->fileName() + " does not have dataCapabilities" ); 00082 continue; 00083 } 00084 00085 int capabilities = dataCapabilities(); 00086 if ( capabilities == QgsDataProvider::NoDataCapabilities ) 00087 { 00088 QgsDebugMsg( library->fileName() + " does not have any dataCapabilities" ); 00089 continue; 00090 } 00091 00092 dataItem_t * dataItem = ( dataItem_t * ) cast_to_fptr( library->resolve( "dataItem" ) ); 00093 if ( !dataItem ) 00094 { 00095 QgsDebugMsg( library->fileName() + " does not have dataItem" ); 00096 continue; 00097 } 00098 00099 QgsDataItem *item = dataItem( "", NULL ); // empty path -> top level 00100 if ( item ) 00101 { 00102 QgsDebugMsg( "Add new top level item : " + item->name() ); 00103 connectItem( item ); 00104 mRootItems << item; 00105 } 00106 } 00107 } 00108 00109 void QgsBrowserModel::removeRootItems() 00110 { 00111 foreach( QgsDataItem* item, mRootItems ) 00112 { 00113 delete item; 00114 } 00115 00116 mRootItems.clear(); 00117 } 00118 00119 00120 Qt::ItemFlags QgsBrowserModel::flags( const QModelIndex & index ) const 00121 { 00122 if ( !index.isValid() ) 00123 return 0; 00124 00125 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; 00126 00127 QgsDataItem* ptr = ( QgsDataItem* ) index.internalPointer(); 00128 if ( ptr->type() == QgsDataItem::Layer ) 00129 { 00130 QgsLayerItem *layer = ( QgsLayerItem* ) ptr; 00131 if ( layer->providerKey() != "wms" ) 00132 { 00133 flags |= Qt::ItemIsDragEnabled; 00134 } 00135 } 00136 if ( ptr->acceptDrop() ) 00137 flags |= Qt::ItemIsDropEnabled; 00138 return flags; 00139 } 00140 00141 QVariant QgsBrowserModel::data( const QModelIndex &index, int role ) const 00142 { 00143 if ( !index.isValid() ) 00144 return QVariant(); 00145 00146 QgsDataItem *item = dataItem( index ); 00147 if ( !item ) 00148 { 00149 return QVariant(); 00150 } 00151 else if ( role == Qt::DisplayRole ) 00152 { 00153 return item->name(); 00154 } 00155 else if ( role == Qt::ToolTipRole ) 00156 { 00157 return item->toolTip(); 00158 } 00159 else if ( role == Qt::DecorationRole && index.column() == 0 ) 00160 { 00161 return item->icon(); 00162 } 00163 else 00164 { 00165 // unsupported role 00166 return QVariant(); 00167 } 00168 } 00169 00170 QVariant QgsBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const 00171 { 00172 Q_UNUSED( section ); 00173 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) 00174 { 00175 return QVariant( "header" ); 00176 } 00177 00178 return QVariant(); 00179 } 00180 00181 int QgsBrowserModel::rowCount( const QModelIndex &parent ) const 00182 { 00183 //qDebug("rowCount: idx: (valid %d) %d %d", parent.isValid(), parent.row(), parent.column()); 00184 00185 if ( !parent.isValid() ) 00186 { 00187 // root item: its children are top level items 00188 return mRootItems.count(); // mRoot 00189 } 00190 else 00191 { 00192 // ordinary item: number of its children 00193 QgsDataItem *item = dataItem( parent ); 00194 return item ? item->rowCount() : 0; 00195 } 00196 } 00197 00198 bool QgsBrowserModel::hasChildren( const QModelIndex &parent ) const 00199 { 00200 if ( !parent.isValid() ) 00201 return true; // root item: its children are top level items 00202 00203 QgsDataItem *item = dataItem( parent ); 00204 return item && item->hasChildren(); 00205 } 00206 00207 int QgsBrowserModel::columnCount( const QModelIndex &parent ) const 00208 { 00209 Q_UNUSED( parent ); 00210 return 1; 00211 } 00212 00213 QModelIndex QgsBrowserModel::findPath( QString path ) 00214 { 00215 QModelIndex theIndex; // starting from root 00216 bool foundChild = true; 00217 00218 while ( foundChild ) 00219 { 00220 foundChild = false; // assume that the next child item will not be found 00221 00222 for ( int i = 0; i < rowCount( theIndex ); i++ ) 00223 { 00224 QModelIndex idx = index( i, 0, theIndex ); 00225 QgsDataItem *item = dataItem( idx ); 00226 if ( !item ) 00227 return QModelIndex(); // an error occurred 00228 00229 if ( item->path() == path ) 00230 { 00231 QgsDebugMsg( "Arrived " + item->path() ); 00232 return idx; // we have found the item we have been looking for 00233 } 00234 00235 if ( path.startsWith( item->path() ) ) 00236 { 00237 // we have found a preceding item: stop searching on this level and go deeper 00238 foundChild = true; 00239 theIndex = idx; 00240 break; 00241 } 00242 } 00243 } 00244 00245 return QModelIndex(); // not found 00246 } 00247 00248 void QgsBrowserModel::reload() 00249 { 00250 removeRootItems(); 00251 addRootItems(); 00252 reset(); // Qt4.6 brings better methods beginResetModel + endResetModel 00253 } 00254 00255 /* Refresh dir path */ 00256 void QgsBrowserModel::refresh( QString path ) 00257 { 00258 QModelIndex idx = findPath( path ); 00259 if ( idx.isValid() ) 00260 { 00261 QgsDataItem* item = dataItem( idx ); 00262 if ( item ) 00263 item->refresh(); 00264 } 00265 } 00266 00267 QModelIndex QgsBrowserModel::index( int row, int column, const QModelIndex &parent ) const 00268 { 00269 QgsDataItem *p = dataItem( parent ); 00270 const QVector<QgsDataItem*> &items = p ? p->children() : mRootItems; 00271 QgsDataItem *item = items.value( row, 0 ); 00272 return item ? createIndex( row, column, item ) : QModelIndex(); 00273 } 00274 00275 QModelIndex QgsBrowserModel::parent( const QModelIndex &index ) const 00276 { 00277 QgsDataItem *item = dataItem( index ); 00278 if ( !item ) 00279 return QModelIndex(); 00280 00281 return findItem( item->parent() ); 00282 } 00283 00284 QModelIndex QgsBrowserModel::findItem( QgsDataItem *item, QgsDataItem *parent ) const 00285 { 00286 const QVector<QgsDataItem*> &items = parent ? parent->children() : mRootItems; 00287 00288 for ( int i = 0; i < items.size(); i++ ) 00289 { 00290 if ( items[i] == item ) 00291 return createIndex( i, 0, item ); 00292 00293 QModelIndex childIndex = findItem( item, items[i] ); 00294 if ( childIndex.isValid() ) 00295 return childIndex; 00296 } 00297 00298 return QModelIndex(); 00299 } 00300 00301 /* Refresh item */ 00302 void QgsBrowserModel::refresh( const QModelIndex& theIndex ) 00303 { 00304 QgsDataItem *item = dataItem( theIndex ); 00305 if ( !item ) 00306 return; 00307 00308 QgsDebugMsg( "Refresh " + item->path() ); 00309 item->refresh(); 00310 } 00311 00312 void QgsBrowserModel::beginInsertItems( QgsDataItem *parent, int first, int last ) 00313 { 00314 QgsDebugMsg( "parent mPath = " + parent->path() ); 00315 QModelIndex idx = findItem( parent ); 00316 if ( !idx.isValid() ) 00317 return; 00318 QgsDebugMsg( "valid" ); 00319 beginInsertRows( idx, first, last ); 00320 QgsDebugMsg( "end" ); 00321 } 00322 void QgsBrowserModel::endInsertItems() 00323 { 00324 QgsDebugMsg( "Entered" ); 00325 endInsertRows(); 00326 } 00327 void QgsBrowserModel::beginRemoveItems( QgsDataItem *parent, int first, int last ) 00328 { 00329 QgsDebugMsg( "parent mPath = " + parent->path() ); 00330 QModelIndex idx = findItem( parent ); 00331 if ( !idx.isValid() ) 00332 return; 00333 beginRemoveRows( idx, first, last ); 00334 } 00335 void QgsBrowserModel::endRemoveItems() 00336 { 00337 QgsDebugMsg( "Entered" ); 00338 endRemoveRows(); 00339 } 00340 void QgsBrowserModel::connectItem( QgsDataItem* item ) 00341 { 00342 connect( item, SIGNAL( beginInsertItems( QgsDataItem*, int, int ) ), 00343 this, SLOT( beginInsertItems( QgsDataItem*, int, int ) ) ); 00344 connect( item, SIGNAL( endInsertItems() ), 00345 this, SLOT( endInsertItems() ) ); 00346 connect( item, SIGNAL( beginRemoveItems( QgsDataItem*, int, int ) ), 00347 this, SLOT( beginRemoveItems( QgsDataItem*, int, int ) ) ); 00348 connect( item, SIGNAL( endRemoveItems() ), 00349 this, SLOT( endRemoveItems() ) ); 00350 } 00351 00352 QStringList QgsBrowserModel::mimeTypes() const 00353 { 00354 QStringList types; 00355 // In theory the mime type convention is: application/x-vnd.<vendor>.<application>.<type> 00356 // but it seems a bit over formalized. Would be an application/x-qgis-uri better? 00357 types << "application/x-vnd.qgis.qgis.uri"; 00358 return types; 00359 } 00360 00361 QMimeData * QgsBrowserModel::mimeData( const QModelIndexList &indexes ) const 00362 { 00363 QgsMimeDataUtils::UriList lst; 00364 foreach( const QModelIndex &index, indexes ) 00365 { 00366 if ( index.isValid() ) 00367 { 00368 QgsDataItem* ptr = ( QgsDataItem* ) index.internalPointer(); 00369 if ( ptr->type() != QgsDataItem::Layer ) continue; 00370 QgsLayerItem *layer = ( QgsLayerItem* ) ptr; 00371 if ( layer->providerKey() == "wms" ) continue; 00372 lst.append( QgsMimeDataUtils::Uri( layer ) ); 00373 } 00374 } 00375 return QgsMimeDataUtils::encodeUriList( lst ); 00376 } 00377 00378 bool QgsBrowserModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) 00379 { 00380 Q_UNUSED( row ); 00381 Q_UNUSED( column ); 00382 00383 QgsDataItem* destItem = dataItem( parent ); 00384 if ( !destItem ) 00385 { 00386 QgsDebugMsg( "DROP PROBLEM!" ); 00387 return false; 00388 } 00389 00390 return destItem->handleDrop( data, action ); 00391 } 00392 00393 QgsDataItem *QgsBrowserModel::dataItem( const QModelIndex &idx ) const 00394 { 00395 void *v = idx.internalPointer(); 00396 QgsDataItem *d = reinterpret_cast<QgsDataItem*>( v ); 00397 Q_ASSERT( !v || d ); 00398 return d; 00399 }