1
/*
2
 *  Copyright (c) 2006-2007 Maximilian Kossick <maximilian.kossick@googlemail.com>
3
 *
4
 *  This program is free software; you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by
6
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  (at your option) any later version.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program; if not, write to the Free Software
16
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
 */
18
#ifndef AMAROK_MOUNTPOINTMANAGER_H
19
#define AMAROK_MOUNTPOINTMANAGER_H
20
21
#include "Amarok.h"
22
#include "amarok_export.h"
23
#include "plugin/plugin.h"
24
#include "PluginManager.h"
25
26
#include <KConfig>
27
#include <KUrl>
28
#include <solid/device.h>
29
#include <threadweaver/Job.h>
30
31
#include <QMap>
32
#include <QMutex>
33
#include <QStringList>
34
35
class DeviceHandler;
36
class DeviceHandlerFactory;
37
38
typedef QList<int> IdList;
39
typedef QList<DeviceHandlerFactory*> FactoryList;
40
typedef QMap<int, DeviceHandler*> HandlerMap;
41
42
class AMAROK_EXPORT DeviceHandlerFactory : public Amarok::Plugin
43
{
44
public:
45
    DeviceHandlerFactory() {}
46
    virtual ~DeviceHandlerFactory() {}
47
48
    /**
49
     * checks whether a DeviceHandler subclass can handle a given Medium.
50
     * @param volume the connected solid volume
51
     * @return true if the DeviceHandler implementation can handle the medium,
52
     * false otherwise
53
     */
54
    virtual bool canHandle( const Solid::Device &device ) const = 0;
55
56
    /**
57
     * tells the MountPointManager whether it makes sense to ask the factory to
58
     * create a Devicehandler when a new Medium was connected
59
     * @return true if the factory can create DeviceHandlers from Medium instances
60
     */
61
    virtual bool canCreateFromMedium() const = 0;
62
63
    /**
64
     * creates a DeviceHandler which represents the Medium.
65
     * @param volume the Volume for which a DeviceHandler is required
66
     * @return a DeviceHandler or 0 if the factory cannot handle the Medium
67
     */
68
    virtual DeviceHandler* createHandler( const Solid::Device &device, const QString &udi ) const = 0;
69
70
    virtual bool canCreateFromConfig() const = 0;
71
72
    virtual DeviceHandler* createHandler( KSharedConfigPtr c ) const = 0;
73
74
    /**
75
     * returns the type of the DeviceHandler. Should be the same as the value used in
76
     * ~/.kde/share/config/amarokrc
77
     * @return a QString describing the type of the DeviceHandler
78
     */
79
    virtual QString type() const = 0;
80
81
};
82
83
/**
84
 *
85
 *
86
 */
87
class DeviceHandler
88
{
89
public:
90
    DeviceHandler() {}
91
    virtual ~DeviceHandler() {}
92
93
94
    virtual bool isAvailable() const = 0;
95
96
    /**
97
     * returns the type of the DeviceHandler. Should be the same as the value used in
98
     * ~/.kde/share/config/amarokrc
99
     * @return a QString describing the type of the DeviceHandler
100
     */
101
    virtual QString type() const = 0;
102
103
    /**
104
     * returns an absolute path which is guaranteed to be playable by amarok's current engine. (based on an
105
     * idea by andrewt512: this method would only be called when we actually want to play the file, not when we
106
     * simply want to show it to the user. It could for example download a file using KIO and return a path to a
107
     * temporary file. Needs some more thought and is not actually used at the moment.
108
     * @param absolutePath
109
     * @param relativePath
110
     */
111
    virtual void getPlayableURL( KUrl &absolutePath, const KUrl &relativePath ) = 0;
112
113
    /**
114
     * builds an absolute path from a relative path and DeviceHandler specific information. The absolute path
115
     * is not necessarily playable! (based on an idea by andrewt512: allows better handling of files stored in remote  * collections. this method would return a "pretty" URL which might not be playable by amarok's engines.
116
     * @param absolutePath the not necessarily playbale absolute path
117
     * @param relativePath the device specific relative path
118
     */
119
    virtual void getURL( KUrl &absolutePath, const KUrl &relativePath ) = 0;
120
121
    /**
122
     * retrieves the unique database id of a given Medium. Implementations are responsible
123
     * for generating a (sufficiently) unique value which identifies the Medium.
124
     * Additionally, implementations must recognize unknown mediums and store the necessary
125
     * information to recognize them the next time they are connected in the database.
126
     * @return unique identifier which can be used as a foreign key to the media table.
127
     */
128
    virtual int getDeviceID() = 0;
129
130
    virtual const QString &getDevicePath() const = 0;
131
132
    /**
133
     * allows MountPointManager to check if a device handler handles a specific medium.
134
     * @param m
135
     * @return true if the device handler handles the Medium m
136
     */
137
    virtual bool deviceMatchesUdi( const QString &udi ) const = 0;
138
};
139
140
/**
141
 *	@author Maximilian Kossick <maximilian.kossick@googlemail.com>
142
 */
143
class MountPointManager : public QObject
144
{
145
Q_OBJECT
146
147
148
public:
149
    //the methods of this class a called *very* often. make sure they are as fast as possible
150
    // (inline them?)
151
152
    /**
153
     * factory method.
154
     * @return a MountPointManager instance
155
     */
156
    AMAROK_EXPORT static MountPointManager *instance();
157
158
    /**
159
     * frees the singleton
160
     */
161
    AMAROK_EXPORT static void destroy();
162
163
    /**
164
     *
165
     * @param url
166
     * @return
167
     */
168
    AMAROK_EXPORT int getIdForUrl( const KUrl &url );
169
    /**
170
     *
171
     * @param id
172
     * @return
173
     */
174
    QString getMountPointForId( const int id ) const;
175
    /**
176
     * builds the absolute path from the mount point of the medium and the given relative
177
     * path.
178
     * @param deviceId the medium(device)'s unique id
179
     * @param relativePath relative path on the medium
180
     * @return the absolute path
181
     */
182
    void getAbsolutePath( const int deviceId, const KUrl& relativePath, KUrl& absolutePath ) const;
183
    AMAROK_EXPORT QString getAbsolutePath ( const int deviceId, const QString& relativePath ) const;
184
    /**
185
     * calculates a file's/directory's relative path on a given device.
186
     * @param deviceId the unique id which identifies the device the file/directory is supposed to be on
187
     * @param absolutePath the file's/directory's absolute path
188
     * @param relativePath the calculated relative path
189
     */
190
    void getRelativePath( const int deviceId, const KUrl& absolutePath, KUrl& relativePath ) const;
191
    AMAROK_EXPORT QString getRelativePath( const int deviceId, const QString& absolutePath ) const;
192
    /**
193
     * allows calling code to access the ids of all active devices
194
     * @return the ids of all devices which are currently mounted or otherwise accessible
195
     */
196
    AMAROK_EXPORT IdList getMountedDeviceIds() const;
197
198
    AMAROK_EXPORT QStringList collectionFolders();
199
    void setCollectionFolders( const QStringList &folders );
200
201
public slots:
202
//     void mediumAdded( const Medium *m );
203
//     /**
204
//      * initiates the update of the class' internal list of mounted mediums.
205
//      * @param m the medium whose status changed
206
//      */
207
//     void mediumChanged( const Medium* m );
208
//     void mediumRemoved( const Medium* m );
209
210
    void updateStatisticsURLs( bool changed = true );
211
212
private slots:
213
    void migrateStatistics();
214
    void checkDeviceAvailability();
215
    void startStatisticsUpdateJob();
216
217
private:
218
    static MountPointManager* s_instance;
219
    MountPointManager();
220
    ~MountPointManager();
221
222
    /**
223
     * checks whether a medium identified by its unique database id is currently mounted.
224
     * Note: does not handle deviceId = -1! It only checks real devices
225
     * @param deviceId the mediums unique id
226
     * @return true if the medium is mounted, false otherwise
227
     */
228
    bool isMounted ( const int deviceId ) const;
229
    void init();
230
    /**
231
     * maps a device id to a mount point. does only work for mountable filesystems and needs to be
232
     * changed for the real Dynamic Collection implementation.
233
     */
234
    HandlerMap m_handlerMap;
235
    mutable QMutex m_handlerMapMutex;
236
    FactoryList m_mediumFactories;
237
    FactoryList m_remoteFactories;
238
239
//Solid specific
240
    void createHandlerFromDevice( const Solid::Device &device, const QString &udi );
241
private slots:
242
    void deviceAdded( const QString &udi );
243
    void deviceRemoved( const QString &udi );
244
245
};
246
247
class UrlUpdateJob : public ThreadWeaver::Job
248
{
249
public:
250
    UrlUpdateJob( QObject *dependent );
251
252
    virtual void run();
253
254
private:
255
    void updateStatistics();
256
    void updateLabels();
257
};
258
259
#endif