Quantum GIS API Documentation  1.8
src/core/qgsbrowsermodel.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines