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