Skip to content

Commit

Permalink
populating browser icons in threads moved to QgsDataItem
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Dec 12, 2014
1 parent 917cee0 commit d84af0d
Show file tree
Hide file tree
Showing 15 changed files with 262 additions and 217 deletions.
1 change: 0 additions & 1 deletion python/core/qgsdataitem.sip
Expand Up @@ -28,7 +28,6 @@ class QgsDataItem : QObject
// Populate children using children vector created by createChildren()
virtual void populate();
bool isPopulated();
void setPopulated();

// Insert new child using alphabetical order based on mName, emits necessary signal to model before and after, sets parent and connects signals
// refresh - refresh populated item, emit signals to model
Expand Down
130 changes: 16 additions & 114 deletions src/core/qgsbrowsermodel.cpp
Expand Up @@ -51,9 +51,6 @@ QgsBrowserModel::QgsBrowserModel( QObject *parent )
{
connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ), this, SLOT( updateProjectHome() ) );
connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ), this, SLOT( updateProjectHome() ) );
mLoadingMovie.setFileName( QgsApplication::iconPath( "/mIconLoading.gif" ) );
mLoadingMovie.setCacheMode( QMovie::CacheAll );
connect( &mLoadingMovie, SIGNAL( frameChanged( int ) ), SLOT( loadingFrameChanged() ) );
addRootItems();
}

Expand Down Expand Up @@ -232,10 +229,6 @@ QVariant QgsBrowserModel::data( const QModelIndex &index, int role ) const
}
else if ( role == Qt::DecorationRole && index.column() == 0 )
{
if ( fetching( item ) )
{
return mLoadingIcon;
}
return item->icon();
}
else
Expand Down Expand Up @@ -330,6 +323,7 @@ QModelIndex QgsBrowserModel::findPath( QString path, Qt::MatchFlag matchFlag )

void QgsBrowserModel::reload()
{
// TODO: put items creating currently children in threads to deleteLater (does not seem urget because reload() is not used in QGIS)
beginResetModel();
removeRootItems();
addRootItems();
Expand Down Expand Up @@ -398,6 +392,14 @@ void QgsBrowserModel::endRemoveItems()
QgsDebugMsgLevel( "Entered", 3 );
endRemoveRows();
}
void QgsBrowserModel::dataItemChanged( QgsDataItem * item )
{
QgsDebugMsgLevel( "Entered", 3 );
QModelIndex idx = findItem( item );
if ( !idx.isValid() )
return;
emit dataChanged( idx, idx );
}
void QgsBrowserModel::connectItem( QgsDataItem* item )
{
connect( item, SIGNAL( beginInsertItems( QgsDataItem*, int, int ) ),
Expand All @@ -408,6 +410,8 @@ void QgsBrowserModel::connectItem( QgsDataItem* item )
this, SLOT( beginRemoveItems( QgsDataItem*, int, int ) ) );
connect( item, SIGNAL( endRemoveItems() ),
this, SLOT( endRemoveItems() ) );
connect( item, SIGNAL( dataChanged( QgsDataItem* ) ),
this, SLOT( dataItemChanged( QgsDataItem* ) ) );
}

QStringList QgsBrowserModel::mimeTypes() const
Expand Down Expand Up @@ -463,30 +467,20 @@ bool QgsBrowserModel::canFetchMore( const QModelIndex & parent ) const
QgsDataItem* item = dataItem( parent );
// if ( item )
// QgsDebugMsg( QString( "path = %1 canFetchMore = %2" ).arg( item->path() ).arg( item && ! item->isPopulated() ) );
return ( item && ! item->isPopulated() );
return ( item && item->state() == QgsDataItem::NotPopulated );
}

void QgsBrowserModel::fetchMore( const QModelIndex & parent )
{
QgsDebugMsg( "Entered" );
QgsDataItem* item = dataItem( parent );

if ( !item || fetching( item ) )
if ( !item || item->state() == QgsDataItem::Populating || item->state() == QgsDataItem::Populated )
return;

QgsDebugMsg( "path = " + item->path() );

if ( item->isPopulated() )
return;

QList<QgsDataItem*> itemList;
itemList << item;
QgsBrowserWatcher * watcher = new QgsBrowserWatcher( item );
connect( watcher, SIGNAL( finished() ), SLOT( childrenCreated() ) );
watcher->setFuture( QtConcurrent::mapped( itemList, QgsBrowserModel::createChildren ) );
mWatchers.append( watcher );
mLoadingMovie.setPaused( false );
emit dataChanged( parent, parent );
item->populate();
}

/* Refresh dir path */
Expand All @@ -500,104 +494,12 @@ void QgsBrowserModel::refresh( QString path )
void QgsBrowserModel::refresh( const QModelIndex& theIndex )
{
QgsDataItem *item = dataItem( theIndex );
if ( !item )
if ( !item || item->state() == QgsDataItem::Populating )
return;

QgsDebugMsg( "Refresh " + item->path() );

QList<QgsDataItem*> itemList;
itemList << item;
QgsBrowserWatcher * watcher = new QgsBrowserWatcher( item );
connect( watcher, SIGNAL( finished() ), SLOT( refreshChildrenCreated() ) );
watcher->setFuture( QtConcurrent::mapped( itemList, QgsBrowserModel::createChildren ) );
mWatchers.append( watcher );
mLoadingMovie.setPaused( false );
emit dataChanged( theIndex, theIndex );
}

// This is expected to be run in a separate thread
QVector<QgsDataItem*> QgsBrowserModel::createChildren( QgsDataItem* item )
{
QgsDebugMsg( "Entered" );
QTime time;
time.start();
QVector <QgsDataItem*> children = item->createChildren();
QgsDebugMsg( QString( "%1 children created in %2 ms" ).arg( children.size() ).arg( time.elapsed() ) );
// Children objects must be pushed to main thread.
foreach ( QgsDataItem* child, children )
{
if ( !child ) // should not happen
continue;
// However it seems to work without resetting parent, the Qt doc says that
// "The object cannot be moved if it has a parent."
QgsDebugMsg( "moveToThread child" + child->path() );
child->setParent( 0 );
child->moveToThread( QApplication::instance()->thread() );
child->setParent( item );
}
return children;
}

void QgsBrowserModel::childrenCreated()
{
QgsBrowserWatcher *watcher = dynamic_cast<QgsBrowserWatcher *>( sender() );
if ( !watcher )
return;
QgsDataItem* item = watcher->item();
QVector <QgsDataItem*> children = watcher->result();
QgsDebugMsg( QString( "path = %1 children.size() = %2" ).arg( item->path() ).arg( children.size() ) );
QModelIndex index = findItem( item );
if ( !index.isValid() ) // check if item still exists
return;
item->populate( children );
emit dataChanged( index, index );
emit fetchFinished( index );
}

void QgsBrowserModel::refreshChildrenCreated()
{
QgsBrowserWatcher *watcher = dynamic_cast<QgsBrowserWatcher *>( sender() );
if ( !watcher )
return;
QgsDataItem* item = watcher->item();
QVector <QgsDataItem*> children = watcher->result();
QgsDebugMsg( QString( "path = %1 children.size() = %2" ).arg( item->path() ).arg( children.size() ) );
QModelIndex index = findItem( item );
if ( !index.isValid() ) // check if item still exists
return;
item->refresh( children );
emit dataChanged( index, index );
}

bool QgsBrowserModel::fetching( QgsDataItem* item ) const
{
foreach ( QgsBrowserWatcher * watcher, mWatchers )
{
if ( !watcher->isFinished() && watcher->item() == item )
return true;
}
return false;
}

void QgsBrowserModel::loadingFrameChanged()
{
mLoadingIcon = QIcon( mLoadingMovie.currentPixmap() );
int notFinished = 0;
foreach ( QgsBrowserWatcher * watcher, mWatchers )
{
if ( watcher->isFinished() )
{
delete watcher;
mWatchers.removeOne( watcher );
continue;
}
QModelIndex index = findItem( watcher->item() );
QgsDebugMsg( QString( "path = %1 not finished" ).arg( watcher->item()->path() ) );
emit dataChanged( index, index );
notFinished++;
}
if ( notFinished == 0 )
mLoadingMovie.setPaused( true );
item->refresh();
}

void QgsBrowserModel::addFavouriteDirectory( QString favDir )
Expand Down
12 changes: 1 addition & 11 deletions src/core/qgsbrowsermodel.h
Expand Up @@ -113,8 +113,6 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel

bool canFetchMore( const QModelIndex & parent ) const;
void fetchMore( const QModelIndex & parent );
static QVector<QgsDataItem*> createChildren( QgsDataItem *item );
bool fetching( QgsDataItem *item ) const;

signals:
/** Emitted when item children fetch was finished */
Expand All @@ -127,14 +125,11 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
void endInsertItems();
void beginRemoveItems( QgsDataItem *parent, int first, int last );
void endRemoveItems();
void dataItemChanged( QgsDataItem * item );

void addFavouriteDirectory( QString favDir );
void removeFavourite( const QModelIndex &index );

void updateProjectHome();
void childrenCreated();
void refreshChildrenCreated();
void loadingFrameChanged();

protected:
// populates the model
Expand All @@ -144,11 +139,6 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
QVector<QgsDataItem*> mRootItems;
QgsFavouritesItem *mFavourites;
QgsDirectoryItem *mProjectHome;

private:
QList<QgsBrowserWatcher *> mWatchers;
QMovie mLoadingMovie;
QIcon mLoadingIcon;
};

#endif // QGSBROWSERMODEL_H

1 comment on commit d84af0d

@strk
Copy link
Contributor

@strk strk commented on d84af0d Dec 12, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Travis run of the testsuite failed with this commit:
https://travis-ci.org/qgis/QGIS/builds/43823913

@blazek do you receive notifications of travis build status change ?
You might need a travis account for that.

Please sign in to comment.