1# Copyright (C) 2008-2010 Adam Olsen 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2, or (at your option) 6# any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# 18# The developers of the Exaile media player hereby grant permission 19# for non-GPL compatible GStreamer and Exaile plugins to be used and 20# distributed together with GStreamer and Exaile. This permission is 21# above and beyond the permissions granted by the GPL license by which 22# Exaile is covered. If you modify this code, you may extend this 23# exception to your version of the code, but you are not obligated to 24# do so. If you do not wish to do so, delete this exception statement 25# from your version. 26 27from gi.repository import GObject 28from gi.repository import Gtk 29 30from xl import common, event 31from xl.nls import gettext as _ 32from xlgui import panel 33from xlgui.panel.collection import CollectionPanel 34from xlgui.panel.flatplaylist import FlatPlaylistPanel 35 36 37class DeviceTransferThread(common.ProgressThread): 38 """ 39 Transfers tracks from devices 40 """ 41 42 def __init__(self, device): 43 common.ProgressThread.__init__(self) 44 45 self.device = device 46 47 def stop(self): 48 """ 49 Stops the thread 50 """ 51 self.device.transfer.cancel() 52 common.ProgressThread.stop(self) 53 54 def on_track_transfer_progress(self, type, transfer, progress): 55 """ 56 Notifies about progress changes 57 """ 58 if progress < 100: 59 self.emit('progress-update', progress) 60 else: 61 self.emit('done') 62 63 def run(self): 64 """ 65 Runs the thread 66 """ 67 event.add_ui_callback( 68 self.on_track_transfer_progress, 69 'track_transfer_progress', 70 self.device.transfer, 71 ) 72 try: 73 self.device.start_transfer() 74 finally: 75 event.remove_callback( 76 self.on_track_transfer_progress, 77 'track_transfer_progress', 78 self.device.transfer, 79 ) 80 81 82class ReceptiveCollectionPanel(CollectionPanel): 83 def drag_data_received(self, widget, context, x, y, data, info, stamp): 84 uris = data.get_uris() 85 tracks, playlists = self.tree.get_drag_data(uris) 86 tracks = [ 87 t for t in tracks if not self.collection.loc_is_member(t.get_loc_for_io()) 88 ] 89 90 self.add_tracks_func(tracks) 91 92 def add_tracks_func(self, tracks): 93 locs = [t['__loc'] for t in tracks] 94 # FIXME: 95 lib = self.collection.get_libraries()[0] 96 97 # TODO: there should be a queue for ipod and such devices, 98 # otherwise you'll have to write the database on every track add and 99 # that won't be good 100 # this _needs_ to be asynchronous 101 for l in locs: 102 lib.add(l) 103 104 105class DevicePanel(panel.Panel): 106 """ 107 generic panel for devices 108 """ 109 110 __gsignals__ = { 111 'append-items': (GObject.SignalFlags.RUN_LAST, None, (object, bool)), 112 'replace-items': (GObject.SignalFlags.RUN_LAST, None, (object,)), 113 'queue-items': (GObject.SignalFlags.RUN_LAST, None, (object,)), 114 'collection-tree-loaded': (GObject.SignalFlags.RUN_LAST, None, ()), 115 } 116 117 ui_info = ('device.ui', 'DevicePanel') 118 119 def __init__(self, parent, main, device, name): 120 121 label = device.get_name() 122 panel.Panel.__init__(self, parent, name, label) 123 self.device = device 124 self.main = main 125 126 self.notebook = self.builder.get_object("device_notebook") 127 128 self.collectionpanel = ReceptiveCollectionPanel( 129 parent, collection=device.collection, name=name, label=label 130 ) 131 self.collectionpanel.add_tracks_func = self.add_tracks_func 132 133 self.collectionpanel.connect( 134 'append-items', lambda *e: self.emit('append-items', *e[1:]) 135 ) 136 self.collectionpanel.connect( 137 'replace-items', lambda *e: self.emit('replace-items', *e[1:]) 138 ) 139 self.collectionpanel.connect( 140 'queue-items', lambda *e: self.emit('queue-items', *e[1:]) 141 ) 142 self.collectionpanel.connect( 143 'collection-tree-loaded', lambda *e: self.emit('collection-tree-loaded') 144 ) 145 146 def add_tracks_func(self, tracks): 147 self.device.add_tracks(tracks) 148 thread = DeviceTransferThread(self.device) 149 thread.connect('done', lambda *e: self.load_tree()) 150 self.main.controller.progress_manager.add_monitor( 151 thread, _("Transferring to %s...") % self.name, 'drive-harddisk' 152 ) 153 154 def get_panel(self): 155 return self.collectionpanel.get_panel() 156 157 def add_panel(self, child, name): 158 label = Gtk.Label(label=name) 159 self.notebook.append_page(child, label) 160 161 def load_tree(self, *args): 162 self.collectionpanel.load_tree(*args) 163 164 165class FlatPlaylistDevicePanel(panel.Panel): 166 __gsignals__ = { 167 'append-items': (GObject.SignalFlags.RUN_LAST, None, (object, bool)), 168 'replace-items': (GObject.SignalFlags.RUN_LAST, None, (object,)), 169 'queue-items': (GObject.SignalFlags.RUN_LAST, None, (object,)), 170 } 171 172 ui_info = ('device.ui', 'DevicePanel') 173 174 def __init__(self, parent, main, device, name): 175 176 label = device.get_name() 177 panel.Panel.__init__(self, parent, name, label) 178 self.device = device 179 self.main = main 180 181 self.notebook = self.builder.get_object("device_notebook") 182 183 self.fppanel = FlatPlaylistPanel(self, name, label) 184 185 self.fppanel.connect( 186 'append-items', lambda *e: self.emit('append-items', *e[1:]) 187 ) 188 self.fppanel.connect( 189 'replace-items', lambda *e: self.emit('replace-items', *e[1:]) 190 ) 191 self.fppanel.connect('queue-items', lambda *e: self.emit('queue-items', *e[1:])) 192 193 def get_panel(self): 194 return self.fppanel.get_panel() 195 196 def add_panel(self, child, name): 197 label = Gtk.Label(label=name) 198 self.notebook.append_page(child, label) 199 200 def load_tree(self, *e): 201 # TODO: handle *all* the playlists 202 self.fppanel.set_playlist(self.device.get_playlists()[0]) 203