Skip to content

Commit 0c4ea1f

Browse files
committed
new class QgsAnimatedIcon
1 parent 72c9830 commit 0c4ea1f

File tree

3 files changed

+93
-33
lines changed

3 files changed

+93
-33
lines changed

python/core/qgsdataitem.sip

-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ class QgsDataItem : QObject
145145
void emitDataChanged( );
146146
void emitStateChanged( QgsDataItem* item, QgsDataItem::State oldState );
147147
virtual void childrenCreated();
148-
void setPopulatingIcon();
149148

150149
signals:
151150
void beginInsertItems( QgsDataItem* parent, int first, int last );

src/core/qgsdataitem.cpp

+60-27
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,57 @@
4343
#include "cpl_vsi.h"
4444
#include "cpl_string.h"
4545

46+
QgsAnimatedIcon::QgsAnimatedIcon( const QString & iconPath )
47+
: QObject()
48+
, mCount( 0 )
49+
, mMovie( 0 )
50+
{
51+
// QApplication as parent to ensure that it is deleted before QApplication
52+
mMovie = new QMovie( QApplication::instance() );
53+
if ( !iconPath.isEmpty() )
54+
{
55+
mMovie->setFileName( iconPath );
56+
}
57+
mMovie->setCacheMode( QMovie::CacheAll );
58+
connect( mMovie, SIGNAL( frameChanged( int ) ), SLOT( onFrameChanged() ) );
59+
}
60+
61+
QString QgsAnimatedIcon::iconPath() const
62+
{
63+
return mMovie->fileName();
64+
}
65+
66+
void QgsAnimatedIcon::setIconPath( const QString & iconPath )
67+
{
68+
mMovie->setFileName( iconPath );
69+
}
70+
71+
void QgsAnimatedIcon::onFrameChanged()
72+
{
73+
mIcon = QIcon( mMovie->currentPixmap() );
74+
emit frameChanged();
75+
}
76+
77+
void QgsAnimatedIcon::connectFrameChanged( const QObject * receiver, const char * method )
78+
{
79+
if ( connect( this, SIGNAL( frameChanged() ), receiver, method ) )
80+
{
81+
mCount++;
82+
}
83+
mMovie->setPaused( mCount == 0 );
84+
QgsDebugMsg( QString( "mCount = %1" ).arg( mCount ) );
85+
}
86+
87+
void QgsAnimatedIcon::disconnectFrameChanged( const QObject * receiver, const char * method )
88+
{
89+
if ( disconnect( this, SIGNAL( frameChanged() ), receiver, method ) )
90+
{
91+
mCount--;
92+
}
93+
mMovie->setPaused( mCount == 0 );
94+
QgsDebugMsg( QString( "mCount = %1" ).arg( mCount ) );
95+
}
96+
4697
// shared icons
4798
const QIcon &QgsLayerItem::iconPoint()
4899
{
@@ -153,9 +204,7 @@ const QIcon &QgsZipItem::iconZip()
153204

154205
QMap<QString, QIcon> QgsDataItem::mIconMap = QMap<QString, QIcon>();
155206

156-
int QgsDataItem::mPopulatingCount = 0;
157-
QMovie * QgsDataItem::mPopulatingMovie = 0;
158-
QIcon QgsDataItem::mPopulatingIcon = QIcon();
207+
QgsAnimatedIcon * QgsDataItem::mPopulatingIcon = 0;
159208

160209
QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path )
161210
// Do not pass parent to QObject, Qt would delete this when parent is deleted
@@ -247,8 +296,8 @@ void QgsDataItem::moveToThread( QThread * targetThread )
247296

248297
QIcon QgsDataItem::icon()
249298
{
250-
if ( state() == Populating )
251-
return mPopulatingIcon;
299+
if ( state() == Populating && mPopulatingIcon )
300+
return mPopulatingIcon->icon();
252301

253302
if ( !mIcon.isNull() )
254303
return mIcon;
@@ -574,11 +623,6 @@ bool QgsDataItem::equal( const QgsDataItem *other )
574623
return false;
575624
}
576625

577-
void QgsDataItem::setPopulatingIcon()
578-
{
579-
mPopulatingIcon = QIcon( mPopulatingMovie->currentPixmap() );
580-
}
581-
582626
QgsDataItem::State QgsDataItem::state() const
583627
{
584628
// for backward compatibility (if subclass set mPopulated directly)
@@ -598,26 +642,15 @@ void QgsDataItem::setState( State state )
598642

599643
if ( state == Populating ) // start loading
600644
{
601-
if ( !mPopulatingMovie )
645+
if ( !mPopulatingIcon )
602646
{
603-
// QApplication as parent to ensure that it is deleted before QApplication
604-
mPopulatingMovie = new QMovie( QApplication::instance() );
605-
mPopulatingMovie->setFileName( QgsApplication::iconPath( "/mIconLoading.gif" ) );
606-
mPopulatingMovie->setCacheMode( QMovie::CacheAll );
607-
connect( mPopulatingMovie, SIGNAL( frameChanged( int ) ), SLOT( setPopulatingIcon() ) );
647+
mPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( "/mIconLoading.gif" ) );
608648
}
609-
connect( mPopulatingMovie, SIGNAL( frameChanged( int ) ), SLOT( emitDataChanged() ) );
610-
mPopulatingCount++;
611-
mPopulatingMovie->setPaused( false );
649+
mPopulatingIcon->connectFrameChanged( this, SLOT( emitDataChanged() ) );
612650
}
613-
else if ( mState == Populating && mPopulatingMovie ) // stop loading
651+
else if ( mState == Populating && mPopulatingIcon ) // stop loading
614652
{
615-
disconnect( mPopulatingMovie, SIGNAL( frameChanged( int ) ), this, SLOT( emitDataChanged() ) );
616-
mPopulatingCount--;
617-
if ( mPopulatingCount == 0 )
618-
{
619-
mPopulatingMovie->setPaused( true );
620-
}
653+
mPopulatingIcon->disconnectFrameChanged( this, SLOT( emitDataChanged() ) );
621654
}
622655

623656
mState = state;
@@ -730,7 +763,7 @@ QgsDirectoryItem::~QgsDirectoryItem()
730763
QIcon QgsDirectoryItem::icon()
731764
{
732765
if ( state() == Populating )
733-
return populatingIcon();
766+
return QgsDataItem::icon();
734767
return iconDir();
735768
}
736769

src/core/qgsdataitem.h

+33-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,38 @@ class QgsDataItem;
3737

3838
typedef QgsDataItem * dataItem_t( QString, QgsDataItem* );
3939

40+
/** Animated icon is keeping an animation running if there are listeners connected to frameChanged */
41+
class QgsAnimatedIcon : public QObject
42+
{
43+
Q_OBJECT
44+
public:
45+
46+
/** Constructor
47+
* @param iconPath path to a movie, e.g. animated GIF */
48+
QgsAnimatedIcon( const QString & iconPath = QString::null );
49+
50+
QString iconPath() const;
51+
void setIconPath( const QString & iconPath );
52+
QIcon icon() const { return mIcon; }
53+
54+
/** Connect listener to frameChanged() signal */
55+
void connectFrameChanged( const QObject * receiver, const char * method );
56+
/** Disconnect listener from frameChanged() signal */
57+
void disconnectFrameChanged( const QObject * receiver, const char * method );
58+
59+
public slots:
60+
void onFrameChanged();
61+
62+
signals:
63+
/** Emited when icon changed */
64+
void frameChanged();
65+
66+
private:
67+
void resetMovie();
68+
int mCount; // number of listeners
69+
QMovie * mMovie;
70+
QIcon mIcon;
71+
};
4072

4173
/** Base class for all items in the model.
4274
* Parent/children hierarchy is not based on QObject. */
@@ -172,7 +204,6 @@ class CORE_EXPORT QgsDataItem : public QObject
172204
protected:
173205
virtual void populate( QVector<QgsDataItem*> children );
174206
virtual void refresh( QVector<QgsDataItem*> children );
175-
QIcon populatingIcon() { return mPopulatingIcon; }
176207
/** The item is scheduled to be deleted. E.g. if deleteLater() is called when
177208
* item is in Populating state (createChildren() running in another thread),
178209
* the deferredDelete() returns true and item will be deleted once Populating finished.
@@ -225,7 +256,6 @@ class CORE_EXPORT QgsDataItem : public QObject
225256
void emitDataChanged( );
226257
void emitStateChanged( QgsDataItem* item, QgsDataItem::State oldState );
227258
virtual void childrenCreated();
228-
void setPopulatingIcon();
229259

230260
signals:
231261
void beginInsertItems( QgsDataItem* parent, int first, int last );
@@ -242,9 +272,7 @@ class CORE_EXPORT QgsDataItem : public QObject
242272
bool mDeferredDelete;
243273
QFutureWatcher< QVector <QgsDataItem*> > *mFutureWatcher;
244274
// number of items currently in loading (populating) state
245-
static int mPopulatingCount;
246-
static QMovie * mPopulatingMovie;
247-
static QIcon mPopulatingIcon;
275+
static QgsAnimatedIcon * mPopulatingIcon;
248276
};
249277

250278
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsDataItem::Capabilities )

0 commit comments

Comments
 (0)