1 /****************************************************************************************
2  * Copyright (c) 2009 Alejandro Wainzinger <aikawarazuni@gmail.com>                     *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #ifndef UMSCOLLECTION_H
18 #define UMSCOLLECTION_H
19 
20 #include "collectionscanner/Directory.h"
21 #include "core/collections/Collection.h"
22 #include "core/meta/Observer.h"
23 #include "core-impl/collections/support/MemoryCollection.h"
24 
25 #include <KDirWatch>
26 #include <QIcon>
27 #include <QDir>
28 #include <solid/device.h>
29 
30 #include <QtGlobal>
31 #include <QTimer>
32 
33 class GenericScanManager;
34 class UmsPodcastProvider;
35 class UmsCollection;
36 class QAction;
37 
38 using namespace Collections;
39 
40 class UmsCollectionFactory : public CollectionFactory
41 {
42     Q_PLUGIN_METADATA(IID AmarokPluginFactory_iid FILE "amarok_collection-umscollection.json")
43     Q_INTERFACES(Plugins::PluginFactory)
44     Q_OBJECT
45 
46     public:
47         UmsCollectionFactory();
48         ~UmsCollectionFactory() override;
49 
50         void init() override;
51 
52     private Q_SLOTS:
53         /**
54          * Called when solid notifier detects a new device has been added
55          */
56         void slotAddSolidDevice( const QString &udi );
57 
58         /**
59          * Called when solid StorageAccess device we are interested in is mounted or
60          * unmounted
61          */
62         void slotAccessibilityChanged( bool accessible, const QString &udi );
63 
64         /**
65          * Called when solid notifier detects a device has been removed
66          */
67         void slotRemoveSolidDevice( const QString &udi );
68 
69         /**
70          * Like @see slotRemoveSolidDevice(), but instructs Collection to eject the
71          * device after it has performed necessary teardown operations.
72          *
73          * Called when user wants to unmount the device from for example Device Notifier
74          */
75         void slotRemoveAndTeardownSolidDevice( const QString &udi );
76 
77         /**
78          * Called when "tracked" collection is destroyed
79          */
80         void slotCollectionDestroyed( QObject *collection );
81 
82     private:
83         /**
84          * Checks whether a solid device is a USB mass-storage one
85          */
86         bool identifySolidDevice( const QString &udi ) const;
87 
88         /**
89          * Attempts to create appropriate collection for already identified solid device
90          * @param udi. Should Q_EMIT newCollection() if the collection was successfully
91          * created and should become visible to the user.
92          */
93         void createCollectionForSolidDevice( const QString &udi );
94 
95         // maps device udi to active UMS collections
96         QMap<QString, UmsCollection *> m_collectionMap;
97 };
98 
99 class UmsCollection : public Collection, public Meta::Observer
100 {
101     Q_OBJECT
102 
103     public:
104         // inherited methods
105 
106         explicit UmsCollection( const Solid::Device &device );
107         ~UmsCollection() override;
108 
109         /* TrackProvider methods */
110         bool possiblyContainsTrack( const QUrl &url ) const override;
111         Meta::TrackPtr trackForUrl( const QUrl &url ) override;
112 
113         /* Collection methods */
114         QueryMaker *queryMaker() override;
115         QString uidUrlProtocol() const override;
116 
117         QString collectionId() const override;
118         QString prettyName() const override;
119         QIcon icon() const override;
120 
121         bool hasCapacity() const override;
122         float usedCapacity() const override;
123         float totalCapacity() const override;
124 
125         CollectionLocation *location() override;
126 
127         bool isOrganizable() const override;
128 
129         /* Capability-related methods */
130         bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override;
131         Capabilities::Capability *createCapabilityInterface(
132                 Capabilities::Capability::Type type ) override;
133 
134         /* Meta::Observer methods */
135         void metadataChanged( const Meta::TrackPtr &track ) override;
136         using Meta::Observer::metadataChanged; // silence compiler warning about hidder overloads
137 
138         /* own methods */
musicUrl()139         const QUrl &musicUrl() const { return m_musicUrl; }
podcastUrl()140         const QUrl &podcastUrl() const { return m_podcastUrl; }
141 
142         /**
143          * Get location where track @param track should be transferred to.
144          *
145          * @param fileExtension new extension to use. Leave empty if you don't wish to
146          * change file extension
147          */
148         QUrl organizedUrl( const Meta::TrackPtr &track, const QString &fileExtension = QString() ) const;
149 
memoryCollection()150         QSharedPointer<MemoryCollection> memoryCollection() const { return m_mc; }
151 
152     Q_SIGNALS:
153         /**
154          * Start a count-down that emits updated() signal after it expires.
155          * Resets the timer to original timeout if already running. This is to ensure
156          * that we Q_EMIT update() max. once per \<timeout\> for batch updates.
157          *
158          * Timers can only be started from "their" thread so use signals & slots for that.
159          */
160         void startUpdateTimer();
161 
162     public Q_SLOTS:
163         /**
164          * Destroy the collection (by emitting remove)
165          */
166         void slotDestroy();
167 
168         /**
169          * Destroy the collection and try to eject the device from system
170          */
171         void slotEject();
172 
173         void slotTrackAdded( const QUrl &trackLocation );
174         void slotTrackRemoved( const Meta::TrackPtr &track );
175 
176     private Q_SLOTS:
177         /**
178          * Update m_lastUpdated timestamp and Q_EMIT updated()
179          */
180         void collectionUpdated();
181 
182         void slotParseTracks();
183         void slotParseActionTriggered();
184         void slotConfigure();
185 
186         void slotDirectoryScanned( QSharedPointer<CollectionScanner::Directory> dir );
187 
188         /**
189          * Starts a timer that ensures we Q_EMIT updated() signal sometime in future.
190          */
191         void slotStartUpdateTimer();
192 
193     private:
194         /** extended constructor */
195         void init();
196 
197         //static variables relating to the on-disk configuration file
198         static QString s_settingsFileName;
199         static QString s_musicFolderKey;
200         static QString s_musicFilenameSchemeKey;
201         static QString s_vfatSafeKey;
202         static QString s_asciiOnlyKey;
203         static QString s_postfixTheKey;
204         static QString s_replaceSpacesKey;
205         static QString s_regexTextKey;
206         static QString s_replaceTextKey;
207         static QString s_podcastFolderKey;
208         static QString s_autoConnectKey;
209         static QString s_collectionName;
210         static QString s_transcodingGroup;
211 
212         Solid::Device m_device;
213         QSharedPointer<MemoryCollection> m_mc;
214         bool m_tracksParsed;
215 
216         bool m_autoConnect;
217         QString m_mountPoint;
218         QUrl m_musicUrl;
219         QUrl m_podcastUrl;
220         QString m_musicFilenameScheme;
221         bool m_vfatSafe;
222         bool m_asciiOnly;
223         bool m_postfixThe;
224         bool m_replaceSpaces;
225         QString m_regexText;
226         QString m_replaceText;
227         QString m_collectionName;
228         QString m_collectionId;
229 
230         GenericScanManager *m_scanManager;
231         KDirWatch m_watcher;
232 
233         QStringList m_supportedMimeTypes;
234 
235         UmsPodcastProvider *m_podcastProvider;
236 
237         QAction *m_parseAction;
238         QAction *m_configureAction;
239         QAction *m_ejectAction;
240         QTimer m_updateTimer;
241         qint64 m_lastUpdated; /* msecs since epoch */
242 };
243 
244 #endif
245