1 // (c) 2004 Christian Muehlhaeuser <chris@chris.de>
2 // (c) 2005 Martin Aumueller <aumuell@reserv.at>
3 // (c) 2005 Seb Ruiz <me@sebruiz.net>
4 // (c) 2006 T.R.Shashwath <trshash84@gmail.com>
5 // See COPYING file for licensing information
7 #ifndef AMAROK_MEDIABROWSER_H
8 #define AMAROK_MEDIABROWSER_H
11 #include "amarok_export.h"
12 #include "browserToolBar.h"
14 #include "plugin/plugin.h" //baseclass
15 #include "pluginmanager.h"
18 #include <kvbox.h> //baseclass
22 #include <Q3ValueList>
27 #include <QPaintEvent>
29 #include <k3listview.h> //baseclass
30 #include <kurl.h> //stack allocated
31 #include <kio/global.h> //filesize_t
32 #include "scrobbler.h" //SubmitItem
33 #include "metabundle.h"
53 class AMAROK_EXPORT MediaItem
: public K3ListViewItem
56 MediaItem( Q3ListView
* parent
);
57 MediaItem( Q3ListViewItem
* parent
);
58 MediaItem( Q3ListView
* parent
, Q3ListViewItem
* after
);
59 MediaItem( Q3ListViewItem
* parent
, Q3ListViewItem
* after
);
63 MediaItem
*lastChild() const;
65 virtual KUrl
url() const;
66 const MetaBundle
*bundle() const;
67 void setBundle( MetaBundle
*bundle
);
69 enum Type
{ UNKNOWN
, ARTIST
, ALBUM
, TRACK
, PODCASTSROOT
, PODCASTCHANNEL
,
70 PODCASTITEM
, PLAYLISTSROOT
, PLAYLIST
, PLAYLISTITEM
, INVISIBLEROOT
,
71 INVISIBLE
, STALEROOT
, STALE
, ORPHANEDROOT
, ORPHANED
, DIRECTORY
};
73 enum Flags
{ Failed
=1, BeginTransfer
=2, StopTransfer
=4, Transferring
=8, SmartPlaylist
=16 };
75 void setType( Type type
);
76 void setFailed( bool failed
=true );
77 Type
type() const { return m_type
; }
78 MediaItem
*findItem(const QString
&key
, const MediaItem
*after
=0) const;
79 const QString
&data() const { return m_data
; }
80 void setData( const QString
&data
) { m_data
= data
; }
82 virtual bool isLeafItem() const; // A leaf node of the tree
83 virtual bool isFileBacked() const; // Should the file be deleted of the device when removed
84 virtual QDateTime
playTime() const { return QDateTime(); }
85 virtual int played() const { return 0; }
86 virtual int recentlyPlayed() const { return 0; } // no of times played on device since last sync
87 virtual void setPlayCount( int ) {}
88 virtual int rating() const { return 0; } // rating on device, normalized to 100
89 virtual void setRating( int /*rating*/ ) {}
90 virtual bool ratingChanged() const { return false; }
91 virtual void setLastPlayed( uint
) {}
92 virtual void syncStatsFromPath( const QString
&path
);
93 virtual long size() const;
94 virtual MediaDevice
*device() const { return m_device
; }
95 virtual bool listened() const { return m_listened
; }
96 virtual void setListened( bool listened
=true ) { m_listened
= listened
; }
98 int compare( Q3ListViewItem
*i
, int col
, bool ascending
) const;
99 int flags() const { return m_flags
; }
100 void createToolTip();
102 void paintCell( QPainter
*p
, const QColorGroup
&cg
, int column
, int width
, int align
);
107 QString m_playlistName
;
109 MediaDevice
*m_device
;
113 static QPixmap
*s_pixUnknown
;
114 static QPixmap
*s_pixRootItem
;
115 static QPixmap
*s_pixFile
;
116 static QPixmap
*s_pixArtist
;
117 static QPixmap
*s_pixAlbum
;
118 static QPixmap
*s_pixPlaylist
;
119 static QPixmap
*s_pixPodcast
;
120 static QPixmap
*s_pixTrack
;
121 static QPixmap
*s_pixInvisible
;
122 static QPixmap
*s_pixStale
;
123 static QPixmap
*s_pixOrphaned
;
124 static QPixmap
*s_pixDirectory
;
125 static QPixmap
*s_pixTransferFailed
;
126 static QPixmap
*s_pixTransferBegin
;
127 static QPixmap
*s_pixTransferEnd
;
130 mutable MetaBundle
*m_bundle
;
133 class MediaQueue
: public K3ListView
138 MediaQueue(MediaBrowser
*parent
);
139 MediaItem
*findPath( QString path
);
141 KIO::filesize_t
totalSize() const; // total size of items to transfer in KB
142 void computeSize() const; // compute total size of items to transfer in KB
143 void addItemToSize( const MediaItem
*item
) const;
144 void subtractItemFromSize( const MediaItem
*item
, bool unconditonally
=false ) const;
146 void removeSelected();
149 void load( const QString
&path
);
150 void save( const QString
&path
);
151 void syncPlaylist( const QString
&playlistName
, const QString
&sql
, bool loading
=false );
152 void syncPlaylist( const QString
&playlistName
, const KUrl
&url
, bool loading
=false );
153 void addUrl( const KUrl
& url
, MetaBundle
*bundle
=NULL
, const QString
&playlistName
=QString() );
154 void addUrl( const KUrl
& url
, MediaItem
*item
);
155 void addUrls( const KUrl::List urls
, const QString
&playlistName
=QString() );
157 void URLsAdded(); // call after finishing adding single urls
159 void dropProxyEvent( QDropEvent
*e
);
160 // Reimplemented from K3ListView
161 bool acceptDrag( QDropEvent
*e
) const;
162 Q3DragObject
*dragObject();
165 void itemCountChanged();
168 void selectAll() {Q3ListView::selectAll(true); }
169 void slotShowContextMenu( Q3ListViewItem
* item
, const QPoint
& point
, int );
170 void slotDropped (QDropEvent
* e
, Q3ListViewItem
* parent
, Q3ListViewItem
* after
);
173 void keyPressEvent( QKeyEvent
*e
);
174 MediaBrowser
*m_parent
;
175 mutable KIO::filesize_t m_totalSize
;
179 class MediaBrowser
: public KVBox
182 friend class DeviceConfigureDialog
;
183 friend class MediaDevice
;
184 friend class MediaView
;
185 friend class MediaQueue
;
186 friend class MediumPluginChooser
;
187 friend class MediaItem
;
190 static bool isAvailable();
191 AMAROK_EXPORT
static MediaBrowser
*instance() { return s_instance
; }
192 AMAROK_EXPORT
static MediaQueue
*queue() { return s_instance
? s_instance
->m_queue
: 0; }
194 MediaBrowser( const char *name
);
195 virtual ~MediaBrowser();
196 bool blockQuit() const;
197 MediaDevice
*currentDevice() const;
198 MediaDevice
*deviceFromId( const QString
&id
) const;
199 QStringList
deviceNames() const;
200 bool deviceSwitch( const QString
&name
);
202 QString
getInternalPluginName ( const QString string
) { return m_pluginName
[string
]; }
203 QString
getDisplayPluginName ( const QString string
) { return m_pluginAmarokName
[string
]; }
204 const KService::List
&getPlugins() { return m_plugins
; }
205 void transcodingFinished( const QString
&src
, const QString
&dst
);
206 bool isTranscoding() const { return m_waitForTranscode
; }
208 void updateButtons();
209 void updateDevices();
210 // return bundle for url if it is known to MediaBrowser
211 bool getBundle( const KUrl
&url
, MetaBundle
*bundle
) const;
212 bool isQuitting() const { return m_quitting
; }
214 KUrl
getProxyUrl( const KUrl
& daapUrl
) const;
215 KToolBar
* getToolBar() const { return m_toolbar
; }
216 KAction
*connectAction() const { return m_connectAction
; }
217 KAction
*disconnectAction() const { return m_disconnectAction
; }
218 KAction
*transferAction() const { return m_transferAction
; }
219 KAction
*configAction() const { return m_configAction
; }
220 KAction
*customAction() const { return m_customAction
; }
223 void availabilityChanged( bool isAvailable
);
226 void transferClicked();
229 void slotSetFilterTimeout();
230 void slotSetFilter();
231 void slotSetFilter( const QString
&filter
);
232 void slotEditFilter();
233 void mediumAdded( const Medium
*, QString
, bool constructing
= false);
234 void mediumChanged( const Medium
*, QString
);
235 void mediumRemoved( const Medium
*, QString
);
236 void activateDevice( const MediaDevice
*device
);
237 void activateDevice( int index
, bool skipDummy
= true );
238 void pluginSelected( const Medium
*, const QString
);
239 void showPluginManager();
240 void cancelClicked();
241 void connectClicked();
242 void disconnectClicked();
243 void customClicked();
244 void configSelectPlugin( int index
);
245 bool config(); // false if canceled by user
246 KUrl
transcode( const KUrl
&src
, const QString
&filetype
);
247 void tagsChanged( const MetaBundle
&bundle
);
248 void prepareToQuit();
251 MediaDevice
*loadDevicePlugin( const QString
&deviceName
);
252 void unloadDevicePlugin( MediaDevice
*device
);
255 AMAROK_EXPORT
static MediaBrowser
*s_instance
;
257 Q3ValueList
<MediaDevice
*> m_devices
;
258 Q3ValueList
<MediaDevice
*>::iterator m_currentDevice
;
260 QMap
<QString
, QString
> m_pluginName
;
261 QMap
<QString
, QString
> m_pluginAmarokName
;
262 void addDevice( MediaDevice
*device
);
263 void removeDevice( MediaDevice
*device
);
266 bool m_waitForTranscode
;
267 KUrl m_transcodedUrl
;
268 QString m_transcodeSrc
;
271 KHBox
* m_progressBox
;
272 QProgressBar
* m_progress
;
274 KPushButton
* m_cancelButton
;
275 //KPushButton* m_playlistButton;
277 KComboBox
* m_configPluginCombo
;
278 KComboBox
* m_deviceCombo
;
279 Browser::ToolBar
*m_toolbar
;
280 typedef QMap
<QString
, MediaItem
*> ItemMap
;
281 mutable QMutex m_itemMapMutex
;
283 KService::List m_plugins
;
286 KAction
*m_connectAction
;
287 KAction
*m_disconnectAction
;
288 KAction
*m_customAction
;
289 KAction
*m_configAction
;
290 KAction
*m_transferAction
;
291 SearchWidget
*m_searchWidget
;
294 class MediaView
: public K3ListView
297 friend class MediaBrowser
;
298 friend class MediaDevice
;
308 MediaView( QWidget
*parent
, MediaDevice
*device
);
309 virtual ~MediaView();
310 AMAROK_EXPORT
KUrl::List
nodeBuildDragList( MediaItem
* item
, int flags
=OnlySelected
);
311 int getSelectedLeaves(MediaItem
*parent
, Q3PtrList
<MediaItem
> *list
, int flags
=OnlySelected
);
312 AMAROK_EXPORT MediaItem
*newDirectory( MediaItem
* parent
);
313 bool setFilter( const QString
&filter
, MediaItem
*parent
=NULL
);
316 void rmbPressed( Q3ListViewItem
*, const QPoint
&, int );
317 void renameItem( Q3ListViewItem
*item
);
318 void slotExpand( Q3ListViewItem
* );
319 void selectAll() { Q3ListView::selectAll(true); }
320 void invokeItem( Q3ListViewItem
*, const QPoint
&, int column
);
321 void invokeItem( Q3ListViewItem
* );
324 void keyPressEvent( QKeyEvent
*e
);
325 // Reimplemented from K3ListView
326 void contentsDropEvent( QDropEvent
*e
);
327 void viewportPaintEvent( QPaintEvent
* );
328 bool acceptDrag( QDropEvent
*e
) const;
329 Q3DragObject
*dragObject();
332 MediaDevice
*m_device
;
336 /* at least the pure virtual functions have to be implemented by a media device,
337 all items are stored in a hierarchy of MediaItems,
338 when items are manipulated the MediaItems have to be updated accordingly */
340 class AMAROK_EXPORT MediaDevice
: public QObject
, public Amarok::Plugin
343 friend class DeviceConfigureDialog
;
344 friend class TransferDialog
;
345 friend class MediaBrowser
;
346 friend class MediaView
;
347 friend class MediaQueue
;
359 virtual void init( MediaBrowser
* parent
);
360 virtual ~MediaDevice();
365 * @return a KAction that will be plugged into the media device browser toolbar
367 virtual KAction
*customAction() { return 0; }
369 virtual void rmbPressed( Q3ListViewItem
*item
, const QPoint
&point
, int ) { (void)item
; (void) point
; }
372 * @return list of filetypes playable on this device
373 * (empty list is interpreted as all types are good)
375 virtual QStringList
supportedFiletypes() { return QStringList(); }
378 * @param bundle describes track that should be checked
379 * @return true if the device is capable of playing the track referred to by bundle
381 virtual bool isPlayable( const MetaBundle
&bundle
);
384 * @param bundle describes track that should be checked
385 * @return true if the track is in the preferred (first in list) format of the device
387 virtual bool isPreferredFormat( const MetaBundle
&bundle
);
390 * @return true if the device is connected
392 virtual bool isConnected() = 0;
395 * Adds particular tracks to a playlist
396 * @param playlist parent playlist for tracks to be added to
397 * @param after insert following this item
398 * @param items tracks to add to playlist
400 virtual void addToPlaylist(MediaItem
*playlist
, MediaItem
*after
, Q3PtrList
<MediaItem
> items
) { Q_UNUSED(playlist
); Q_UNUSED(after
); Q_UNUSED(items
); }
403 * Create a new playlist
404 * @param name playlist title
405 * @param parent parent MediaItem of the new playlist
406 * @param items tracks to add to the new playlist
407 * @return the newly created playlist
409 virtual MediaItem
*newPlaylist(const QString
&name
, MediaItem
*parent
, Q3PtrList
<MediaItem
> items
) { Q_UNUSED(name
); Q_UNUSED(parent
); Q_UNUSED(items
); return 0; }
412 * Move items to a directory
413 * @param directory new parent of dropped items
414 * @param items tracks to add to the directory
416 virtual void addToDirectory( MediaItem
*directory
, Q3PtrList
<MediaItem
> items
) { Q_UNUSED(directory
); Q_UNUSED(items
); }
419 * Create a new directory
420 * @param name directory title
421 * @param parent parent MediaItem of the new directory
422 * @param items tracks to add to the new directory
423 * @return the newly created directory
425 virtual MediaItem
*newDirectory( const QString
&name
, MediaItem
*parent
) { Q_UNUSED(name
); Q_UNUSED(parent
); return 0; }
428 * Notify device of changed tags
429 * @param item item to be updated
430 * @param changed bundle containing new tags
431 * @return the changed MediaItem
433 virtual MediaItem
*tagsChanged( MediaItem
*item
, const MetaBundle
&changed
) { Q_UNUSED(item
); Q_UNUSED(changed
); return 0; }
436 * Indicate whether the device has a custom transfer dialog
437 * @return whether there is a custom dialog
439 virtual bool hasTransferDialog() { return false; }
442 * Run the transfer dialog to be used when Transfer is clicked
444 virtual void runTransferDialog() {}
447 * Get the transfer dialog, if any
448 * @return the transfer dialog, if any, else NULL;
450 virtual TransferDialog
*getTransferDialog() { return NULL
; }
453 * Can be used to explicitly indicate whether a device needs manual configuration
454 * @return whether manual configuration is needed
456 virtual bool needsManualConfig() { return true; }
458 virtual void addConfigElements( QWidget
* /*parent*/ ) {}
459 virtual void removeConfigElements( QWidget
* /*parent*/ ) {}
460 virtual void applyConfig() {}
461 virtual void loadConfig();
463 QString
configString( const QString
&name
, const QString
&defValue
= QString() );
464 void setConfigString( const QString
&name
, const QString
&value
);
465 bool configBool( const QString
&name
, bool defValue
=false );
466 void setConfigBool( const QString
&name
, bool value
);
468 void setRequireMount( const bool b
) { m_requireMount
= b
; }
469 bool hasMountPoint() { return m_hasMountPoint
; }
470 void setDeviceType( const QString
&type
) { m_type
= type
; }
471 QString
deviceType() { return m_type
; }
472 virtual bool autoConnect() { return false; }
473 virtual bool asynchronousTransfer() { return false; }
474 bool isTransferring() { return m_transferring
; }
475 bool isDeleting() { return m_deleting
; }
476 bool isCanceled() { return m_canceled
; }
477 void setCanceled( const bool b
) { m_canceled
= b
; }
479 int progress() const;
480 void setProgress( const int progress
, const int total
= -1 /* leave total unchanged by default */ );
485 * @return a unique identifier that is constant across sessions
487 QString
uniqueId() const { return m_medium
.id(); }
490 * @return the name for the device that should be presented to the user
492 QString
name() const { return m_name
; }
495 * @return the device node
497 QString
deviceNode() const { return m_medium
.deviceNode(); }
500 * @return the device mount point (or empty if non-applicable or unknown)
502 QString
mountPoint() const { return m_medium
.mountPoint(); }
504 QString
getTransferDir() { return m_transferDir
; }
505 Medium
&getMedium() { return m_medium
; }
507 void setSpacesToUnderscores( bool yesno
) { m_spacesToUnderscores
= yesno
;
508 setConfigBool( "spacesToUnderscores", yesno
); }
509 bool getSpacesToUnderscores() { return m_spacesToUnderscores
; }
511 void setFirstSort( QString text
) { m_firstSort
= text
;
512 setConfigString( "firstGrouping", text
); }
513 void setSecondSort( QString text
) { m_secondSort
= text
;
514 setConfigString( "secondGrouping", text
); }
515 void setThirdSort( QString text
) { m_thirdSort
= text
;
516 setConfigString( "thirdGrouping", text
); }
518 virtual KUrl
getProxyUrl( const KUrl
& /*url*/) { return KUrl(); }
519 virtual void customClicked() { return; }
521 BundleList
bundlesToSync( const QString
&playlistName
, const QString
&sql
);
522 BundleList
bundlesToSync( const QString
&playlistName
, const KUrl
&url
);
523 void preparePlaylistForSync( const QString
&playlistName
, const BundleList
&bundles
);
524 bool isOnOtherPlaylist( const QString
&playlistToAvoid
, const MetaBundle
&bundle
);
525 bool isOnPlaylist( const MediaItem
&playlist
, const MetaBundle
&bundle
);
526 bool isInBundleList( const BundleList
&bundles
, const MetaBundle
&bundle
);
527 bool bundleMatch( const MetaBundle
&b1
, const MetaBundle
&b2
);
530 void abortTransfer();
531 void transferFiles();
532 virtual void renameItem( Q3ListViewItem
*item
) {(void)item
; }
533 virtual void expandItem( Q3ListViewItem
*item
) {(void)item
; }
534 bool connectDevice( bool silent
=false );
535 bool disconnectDevice( bool postdisconnecthook
=true );
536 void scheduleDisconnect() { m_scheduledDisconnect
= true; }
539 void fileTransferred( KIO::Job
*job
);
540 void fileTransferFinished();
543 int sysCall(const QString
& command
);
544 int runPreConnectCommand();
545 int runPostDisconnectCommand();
546 QString
replaceVariables( const QString
&cmd
); // replace %m with mount point and %d with device node
549 * Find a particular track
550 * @param bundle The metabundle of the requested media item
551 * @return The MediaItem of the item if found, otherwise NULL
552 * @note This may not be worth implementing for non database driven devices, as it could be slow
554 virtual MediaItem
*trackExists( const MetaBundle
& bundle
) = 0;
558 * Get the capacity and freespace available on the device, in bytes
559 * @return true if successful
561 virtual bool getCapacity( KIO::filesize_t
*total
, KIO::filesize_t
*available
) { Q_UNUSED(total
); Q_UNUSED(available
); return false; }
564 * Lock device for exclusive access if possible
566 virtual bool lockDevice( bool tryOnly
= false ) = 0;
571 virtual void unlockDevice() = 0;
574 * Connect to device, and populate m_view with MediaItems
575 * @return true if successful
577 virtual bool openDevice( bool silent
=false ) = 0;
580 * Wrap up any loose ends and close the device
581 * @return true if successful
583 virtual bool closeDevice() = 0;
586 * Write any pending changes to the device, such as database changes
588 virtual void synchronizeDevice() = 0;
591 * Copy a track to the device
592 * @param bundle The MetaBundle of the item to transfer. Will move the item specified by bundle().url().path()
593 * @return If successful, the created MediaItem in the media device view, else 0
595 virtual MediaItem
*copyTrackToDevice(const MetaBundle
& bundle
) = 0;
598 * Copy track from device to computer
599 * @param item The MediaItem of the track to transfer.
600 * @param url The URL to transfer the track to.
601 * @return The MediaItem transfered.
603 virtual void copyTrackFromDevice(MediaItem
*item
);
606 * Recursively remove MediaItem from the tracklist and the device
607 * @param item MediaItem to remove
608 * @param onlyPlayed True if item should be deleted only if it has been played
609 * @return -1 on failure, number of files deleted otherwise
611 virtual int deleteItemFromDevice( MediaItem
*item
, int flags
=DeleteTrack
) = 0;
614 * Abort the currently active track transfer
616 virtual void cancelTransfer() { /* often checking m_cancel is enough */ }
618 virtual void updateRootItems();
620 virtual bool isSpecialItem( MediaItem
*item
);
622 int deleteFromDevice( MediaItem
*item
=0, int flags
=DeleteTrack
);
624 void purgeEmptyItems( MediaItem
*root
=0 );
625 void syncStatsFromDevice( MediaItem
*root
=0 );
626 void syncStatsToDevice( MediaItem
*root
=0 );
628 bool kioCopyTrack( const KUrl
&src
, const KUrl
&dst
);
632 bool m_hasMountPoint
;
634 QString m_preconnectcmd
;
635 QString m_postdisconnectcmd
;
636 bool m_autoDeletePodcasts
;
640 bool m_transcodeAlways
;
641 bool m_transcodeRemove
;
643 K3ShellProcess
*sysProc
;
644 MediaBrowser
*m_parent
;
647 QString m_transferDir
;
649 QString m_secondSort
;
652 bool m_waitForDeletion
;
658 bool m_deferredDisconnect
;
659 bool m_scheduledDisconnect
;
660 bool m_runDisconnectHook
;
661 bool m_spacesToUnderscores
;
668 // root listview items
669 MediaItem
*m_playlistItem
;
670 MediaItem
*m_podcastItem
;
671 // items not on the master playlist and not on the podcast playlist are not visible on the ipod
672 MediaItem
*m_invisibleItem
;
673 // items in the database for which the file is missing
674 MediaItem
*m_staleItem
;
675 // files without database entry
676 MediaItem
*m_orphanedItem
;
678 // stow away all items below m_rootItems when device is not current
679 Q3PtrList
<Q3ListViewItem
> m_rootItems
;
683 #endif /* AMAROK_MEDIABROWSER_H */