Changeset View
Changeset View
Standalone View
Standalone View
src/browsers/CollectionTreeItemModelBase.cpp
Show All 34 Lines | |||||
35 | #include "widgets/PrettyTreeRoles.h" | 35 | #include "widgets/PrettyTreeRoles.h" | ||
36 | 36 | | |||
37 | #include <KLocalizedString> | 37 | #include <KLocalizedString> | ||
38 | #include <ThreadWeaver/Lambda> | 38 | #include <ThreadWeaver/Lambda> | ||
39 | #include <ThreadWeaver/Queue> | 39 | #include <ThreadWeaver/Queue> | ||
40 | 40 | | |||
41 | #include <QApplication> | 41 | #include <QApplication> | ||
42 | #include <QIcon> | 42 | #include <QIcon> | ||
43 | #include <QMutex> | | |||
44 | #include <QPixmap> | 43 | #include <QPixmap> | ||
44 | #include <QPointer> | ||||
45 | #include <QStandardPaths> | 45 | #include <QStandardPaths> | ||
46 | #include <QStyle> | 46 | #include <QStyle> | ||
47 | #include <QTimeLine> | 47 | #include <QTimeLine> | ||
48 | #include <QTimer> | 48 | #include <QTimer> | ||
49 | 49 | | |||
50 | #include <functional> | ||||
51 | | ||||
52 | | ||||
50 | using namespace Meta; | 53 | using namespace Meta; | ||
51 | 54 | | |||
52 | 55 | | |||
53 | class TrackLoaderJob : public ThreadWeaver::Job | 56 | class TrackLoaderJob : public ThreadWeaver::Job | ||
54 | { | 57 | { | ||
55 | public: | 58 | public: | ||
56 | TrackLoaderJob( const QModelIndex &index, const Meta::AlbumPtr &album, CollectionTreeItemModelBase *model ) | 59 | TrackLoaderJob( const QModelIndex &index, const Meta::AlbumPtr &album, CollectionTreeItemModelBase *model ) | ||
57 | : m_index( index ) | 60 | : m_index( index ) | ||
58 | , m_album( album ) | 61 | , m_album( album ) | ||
59 | , m_model( model ) | 62 | , m_model( model ) | ||
63 | , m_abortRequested( false ) | ||||
60 | { | 64 | { | ||
65 | if( !m_model || !m_album || !m_index.isValid() ) | ||||
66 | requestAbort(); | ||||
67 | } | ||||
68 | | ||||
69 | void requestAbort() override | ||||
70 | { | ||||
71 | m_abortRequested = true; | ||||
61 | } | 72 | } | ||
62 | 73 | | |||
63 | protected: | 74 | protected: | ||
64 | void run( ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread ) override | 75 | void run( ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread ) override | ||
65 | { | 76 | { | ||
66 | Q_UNUSED( self ) | 77 | Q_UNUSED( self ) | ||
67 | Q_UNUSED( thread ) | 78 | Q_UNUSED( thread ) | ||
68 | 79 | | |||
69 | m_model->tracksLoaded( m_album, m_index, m_album->tracks() ); | 80 | if( m_abortRequested || !m_model ) | ||
81 | return; | ||||
82 | | ||||
83 | const auto tracks = m_album->tracks(); | ||||
84 | | ||||
85 | if( m_model && !m_abortRequested ) | ||||
86 | { | ||||
87 | auto slot = std::bind( &CollectionTreeItemModelBase::tracksLoaded, m_model, m_album, m_index, tracks ); | ||||
88 | QTimer::singleShot( 0, m_model, slot ); | ||||
89 | } | ||||
70 | } | 90 | } | ||
71 | 91 | | |||
72 | private: | 92 | private: | ||
73 | QModelIndex m_index; | 93 | QModelIndex m_index; | ||
74 | Meta::AlbumPtr m_album; | 94 | Meta::AlbumPtr m_album; | ||
75 | CollectionTreeItemModelBase *m_model; | 95 | QPointer<CollectionTreeItemModelBase> m_model; | ||
96 | bool m_abortRequested; | ||||
anthonyfieroni: In C++ it's used atomic. | |||||
76 | }; | 97 | }; | ||
77 | 98 | | |||
78 | inline uint qHash( const Meta::DataPtr &data ) | 99 | inline uint qHash( const Meta::DataPtr &data ) | ||
79 | { | 100 | { | ||
80 | return qHash( data.data() ); | 101 | return qHash( data.data() ); | ||
81 | } | 102 | } | ||
82 | 103 | | |||
83 | /** | 104 | /** | ||
84 | * This set determines which collection browser levels should have shown Various Artists | 105 | * This set determines which collection browser levels should have shown Various Artists | ||
85 | * item under them. AlbumArtist is certain, (Track)Artist is questionable. | 106 | * item under them. AlbumArtist is certain, (Track)Artist is questionable. | ||
86 | */ | 107 | */ | ||
87 | static const QSet<CategoryId::CatMenuId> variousArtistCategories = | 108 | static const QSet<CategoryId::CatMenuId> variousArtistCategories = | ||
88 | QSet<CategoryId::CatMenuId>() << CategoryId::AlbumArtist; | 109 | QSet<CategoryId::CatMenuId>() << CategoryId::AlbumArtist; | ||
89 | 110 | | |||
90 | CollectionTreeItemModelBase::CollectionTreeItemModelBase( ) | 111 | CollectionTreeItemModelBase::CollectionTreeItemModelBase( ) | ||
91 | : QAbstractItemModel() | 112 | : QAbstractItemModel() | ||
92 | , m_loadingAlbumsMutex( new QMutex ) | | |||
93 | , m_rootItem( 0 ) | 113 | , m_rootItem( 0 ) | ||
94 | , m_animFrame( 0 ) | 114 | , m_animFrame( 0 ) | ||
95 | , m_loading1( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading1.png" ) ) ) | 115 | , m_loading1( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading1.png" ) ) ) | ||
96 | , m_loading2( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading2.png" ) ) ) | 116 | , m_loading2( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading2.png" ) ) ) | ||
97 | , m_currentAnimPixmap( m_loading1 ) | 117 | , m_currentAnimPixmap( m_loading1 ) | ||
98 | , m_autoExpand( false ) | 118 | , m_autoExpand( false ) | ||
99 | { | 119 | { | ||
100 | m_timeLine = new QTimeLine( 10000, this ); | 120 | m_timeLine = new QTimeLine( 10000, this ); | ||
101 | m_timeLine->setFrameRange( 0, 20 ); | 121 | m_timeLine->setFrameRange( 0, 20 ); | ||
102 | m_timeLine->setLoopCount ( 0 ); | 122 | m_timeLine->setLoopCount ( 0 ); | ||
103 | connect( m_timeLine, &QTimeLine::frameChanged, this, &CollectionTreeItemModelBase::loadingAnimationTick ); | 123 | connect( m_timeLine, &QTimeLine::frameChanged, this, &CollectionTreeItemModelBase::loadingAnimationTick ); | ||
104 | } | 124 | } | ||
105 | 125 | | |||
106 | CollectionTreeItemModelBase::~CollectionTreeItemModelBase() | 126 | CollectionTreeItemModelBase::~CollectionTreeItemModelBase() | ||
107 | { | 127 | { | ||
108 | KConfigGroup config = Amarok::config( "Collection Browser" ); | 128 | KConfigGroup config = Amarok::config( "Collection Browser" ); | ||
109 | QList<int> levelNumbers; | 129 | QList<int> levelNumbers; | ||
110 | foreach( CategoryId::CatMenuId category, levels() ) | 130 | foreach( CategoryId::CatMenuId category, levels() ) | ||
111 | levelNumbers.append( category ); | 131 | levelNumbers.append( category ); | ||
112 | config.writeEntry( "TreeCategory", levelNumbers ); | 132 | config.writeEntry( "TreeCategory", levelNumbers ); | ||
113 | 133 | | |||
114 | if( m_rootItem ) | 134 | if( m_rootItem ) | ||
115 | m_rootItem->deleteLater(); | 135 | m_rootItem->deleteLater(); | ||
116 | | ||||
117 | delete m_loadingAlbumsMutex; | | |||
118 | } | 136 | } | ||
119 | 137 | | |||
120 | Qt::ItemFlags CollectionTreeItemModelBase::flags(const QModelIndex & index) const | 138 | Qt::ItemFlags CollectionTreeItemModelBase::flags(const QModelIndex & index) const | ||
121 | { | 139 | { | ||
122 | Qt::ItemFlags flags = 0; | 140 | Qt::ItemFlags flags = 0; | ||
123 | if( index.isValid() ) | 141 | if( index.isValid() ) | ||
124 | { | 142 | { | ||
125 | flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable; | 143 | flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable; | ||
126 | } | 144 | } | ||
127 | return flags; | 145 | return flags; | ||
128 | | ||||
129 | } | 146 | } | ||
130 | 147 | | |||
131 | bool | 148 | bool | ||
132 | CollectionTreeItemModelBase::setData( const QModelIndex &index, const QVariant &value, int role ) | 149 | CollectionTreeItemModelBase::setData( const QModelIndex &index, const QVariant &value, int role ) | ||
133 | { | 150 | { | ||
134 | Q_UNUSED( role ) | 151 | Q_UNUSED( role ) | ||
135 | 152 | | |||
136 | if( !index.isValid() ) | 153 | if( !index.isValid() ) | ||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Line(s) | 299 | { | |||
284 | { | 301 | { | ||
285 | int year = m_years.value( album.data() ); | 302 | int year = m_years.value( album.data() ); | ||
286 | 303 | | |||
287 | if( year > 0 ) | 304 | if( year > 0 ) | ||
288 | name.prepend( QString("%1 - ").arg( year ) ); | 305 | name.prepend( QString("%1 - ").arg( year ) ); | ||
289 | } | 306 | } | ||
290 | else if( !album->name().isEmpty() ) | 307 | else if( !album->name().isEmpty() ) | ||
291 | { | 308 | { | ||
292 | QMutexLocker locker( m_loadingAlbumsMutex ); | | |||
293 | if( !m_loadingAlbums.contains( album ) ) | 309 | if( !m_loadingAlbums.contains( album ) ) | ||
294 | { | 310 | { | ||
295 | m_loadingAlbums.insert( album ); | 311 | m_loadingAlbums.insert( album ); | ||
296 | 312 | | |||
297 | auto nonConstThis = const_cast<CollectionTreeItemModelBase*>( this ); | 313 | auto nonConstThis = const_cast<CollectionTreeItemModelBase*>( this ); | ||
298 | auto job = QSharedPointer<TrackLoaderJob>::create( itemIndex( item ), album, nonConstThis ); | 314 | auto job = QSharedPointer<TrackLoaderJob>::create( itemIndex( item ), album, nonConstThis ); | ||
299 | ThreadWeaver::Queue::instance()->enqueue( job ); | 315 | ThreadWeaver::Queue::instance()->enqueue( job ); | ||
300 | } | 316 | } | ||
Show All 21 Lines | |||||
322 | 338 | | |||
323 | case PrettyTreeRoles::YearRole: | 339 | case PrettyTreeRoles::YearRole: | ||
324 | { | 340 | { | ||
325 | if( m_years.contains( album.data() ) ) | 341 | if( m_years.contains( album.data() ) ) | ||
326 | return m_years.value( album.data() ); | 342 | return m_years.value( album.data() ); | ||
327 | 343 | | |||
328 | else if( !album->name().isEmpty() ) | 344 | else if( !album->name().isEmpty() ) | ||
329 | { | 345 | { | ||
330 | QMutexLocker locker( m_loadingAlbumsMutex ); | | |||
331 | if( !m_loadingAlbums.contains( album ) ) | 346 | if( !m_loadingAlbums.contains( album ) ) | ||
332 | { | 347 | { | ||
333 | m_loadingAlbums.insert( album ); | 348 | m_loadingAlbums.insert( album ); | ||
334 | 349 | | |||
335 | auto nonConstThis = const_cast<CollectionTreeItemModelBase*>( this ); | 350 | auto nonConstThis = const_cast<CollectionTreeItemModelBase*>( this ); | ||
336 | auto job = QSharedPointer<TrackLoaderJob>::create( itemIndex( item ), album, nonConstThis ); | 351 | auto job = QSharedPointer<TrackLoaderJob>::create( itemIndex( item ), album, nonConstThis ); | ||
337 | ThreadWeaver::Queue::instance()->enqueue( job ); | 352 | ThreadWeaver::Queue::instance()->enqueue( job ); | ||
338 | } | 353 | } | ||
▲ Show 20 Lines • Show All 336 Lines • ▼ Show 20 Line(s) | 689 | default: | |||
675 | type = Collections::QueryMaker::None; | 690 | type = Collections::QueryMaker::None; | ||
676 | break; | 691 | break; | ||
677 | } | 692 | } | ||
678 | 693 | | |||
679 | return type; | 694 | return type; | ||
680 | } | 695 | } | ||
681 | 696 | | |||
682 | void | 697 | void | ||
683 | CollectionTreeItemModelBase::tracksLoaded( Meta::AlbumPtr album, const QModelIndex &index, const Meta::TrackList& tracks ) | 698 | CollectionTreeItemModelBase::tracksLoaded( const Meta::AlbumPtr &album, const QModelIndex &index, const Meta::TrackList& tracks ) | ||
684 | { | 699 | { | ||
685 | DEBUG_BLOCK | 700 | DEBUG_BLOCK | ||
686 | 701 | | |||
687 | if( !album ) | 702 | if( !album ) | ||
688 | return; | 703 | return; | ||
689 | 704 | | |||
690 | QMutexLocker locker( m_loadingAlbumsMutex ); | | |||
691 | m_loadingAlbums.remove( album ); | 705 | m_loadingAlbums.remove( album ); | ||
692 | 706 | | |||
693 | if( !index.isValid() ) | 707 | if( !index.isValid() ) | ||
694 | return; | 708 | return; | ||
695 | 709 | | |||
696 | int year = 0; | 710 | int year = 0; | ||
697 | 711 | | |||
698 | if( !tracks.isEmpty() ) | 712 | if( !tracks.isEmpty() ) | ||
699 | { | 713 | { | ||
700 | Meta::YearPtr yearPtr = tracks.first()->year(); | 714 | Meta::YearPtr yearPtr = tracks.first()->year(); | ||
701 | if( yearPtr ) | 715 | if( yearPtr ) | ||
702 | year = yearPtr->year(); | 716 | year = yearPtr->year(); | ||
703 | 717 | | |||
704 | debug() << "Valid album year found:" << year; | 718 | debug() << "Valid album year found:" << year; | ||
705 | } | 719 | } | ||
706 | 720 | | |||
707 | // Set the year in the thread associated with this | | |||
708 | auto lambda = [=] () { | | |||
709 | if( !m_years.contains( album.data() ) || m_years.value( album.data() ) != year ) | 721 | if( !m_years.contains( album.data() ) || m_years.value( album.data() ) != year ) | ||
710 | { | 722 | { | ||
711 | m_years[ album.data() ] = year; | 723 | m_years[ album.data() ] = year; | ||
712 | emit dataChanged( index, index ); | 724 | emit dataChanged( index, index ); | ||
713 | } | 725 | } | ||
714 | }; | | |||
715 | QTimer::singleShot( 0, this, lambda ); | | |||
716 | } | 726 | } | ||
717 | 727 | | |||
718 | void | 728 | void | ||
719 | CollectionTreeItemModelBase::addQueryMaker( CollectionTreeItem* item, | 729 | CollectionTreeItemModelBase::addQueryMaker( CollectionTreeItem* item, | ||
720 | Collections::QueryMaker *qm ) const | 730 | Collections::QueryMaker *qm ) const | ||
721 | { | 731 | { | ||
722 | connect( qm, &Collections::QueryMaker::newTracksReady, this, &CollectionTreeItemModelBase::newTracksReady, Qt::QueuedConnection ); | 732 | connect( qm, &Collections::QueryMaker::newTracksReady, this, &CollectionTreeItemModelBase::newTracksReady, Qt::QueuedConnection ); | ||
723 | connect( qm, &Collections::QueryMaker::newArtistsReady, this, &CollectionTreeItemModelBase::newArtistsReady, Qt::QueuedConnection ); | 733 | connect( qm, &Collections::QueryMaker::newArtistsReady, this, &CollectionTreeItemModelBase::newArtistsReady, Qt::QueuedConnection ); | ||
▲ Show 20 Lines • Show All 591 Lines • Show Last 20 Lines |
In C++ it's used atomic.