Remove references to the old album_art file
[mussorgsky] / src / edit_panel.py
1 #!/usr/bin/env python2.5
2 import hildon
3 import gtk, gobject
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
6 import album_art_spec
7 import os
8
9 # Fields in the tuple!
10 FILE_URI = 0
11 ARTIST_KEY = 2
12 TITLE_KEY = 3
13 ALBUM_KEY = 4
14 MIME_KEY = 5
15
16 class MussorgskyEditPanel (hildon.StackableWindow):
17
18     def __init__ (self, songs_list=None, albums_list=None, artists_list=None):
19         hildon.StackableWindow.__init__ (self)
20         self.set_border_width (12)
21         self.song_counter = 0
22         self.album_callback_id = -1
23         self.album_change_handler = -1
24         self.artist_change_handler = -1
25         self.writer = MutagenBackend ()
26         self.player = MediaPlayer ()
27         self.albums_list = [a [0] for a in albums_list]
28         self.artists_list = [a [0] for a in artists_list]
29         self.__create_view ()
30         if (songs_list):
31             self.set_songs_list (songs_list)
32         self.update_title ()
33         self.banner = None
34
35
36     def update_title (self):
37         self.set_title ("Edit (%d/%d)" % (self.song_counter+1, len (self.songs_list)))
38
39         
40     def set_songs_list (self, songs_list):
41         if (songs_list and len (songs_list) > 0):
42             self.songs_list = songs_list
43             self.set_data_in_view (songs_list [0])
44             self.song_counter = 0
45
46     def press_back_cb (self, widget):
47         if (self.player.is_playing ()):
48             self.player.stop ()
49
50         if (self.banner and self.banner.get_property("visible")):
51             self.banner.destroy ()
52
53         if (self.album_callback_id != -1):
54             gobject.source_remove (self.album_callback_id)
55             self.album_callback_id = -1
56
57         if self.__is_view_dirty ():
58             print "Modified data. Save!"
59             self.save_metadata ()
60             
61         if (self.song_counter > 0):
62             self.song_counter -= 1
63             self.set_data_in_view (self.songs_list [self.song_counter])
64             self.update_title ()
65         else:
66             self.destroy ()
67
68     def press_next_cb (self, widget):
69         if (self.player.is_playing ()):
70             self.player.stop ()
71
72         if (self.banner and self.banner.get_property("visible")):
73             self.banner.destroy ()
74
75         if (self.album_callback_id != -1):
76             gobject.source_remove (self.album_callback_id)
77             self.album_callback_id = -1
78
79         if self.__is_view_dirty ():
80             print "Modified data. Save!"
81             self.save_metadata ()
82
83         if (self.song_counter < len (self.songs_list) -1):
84             self.song_counter += 1
85             self.set_data_in_view (self.songs_list [self.song_counter])
86             self.update_title ()
87         else:
88             self.destroy ()
89
90     def save_metadata (self):
91         # Save the data in the online model to show the appropiate data
92         # in the UI while tracker process the update.
93         song = self.songs_list [self.song_counter]
94
95         new_song = (song[FILE_URI], song[1],
96                     self.artist_button.get_value (),
97                     self.title_entry.get_text (),
98                     self.album_button.get_value (),
99                     song[MIME_KEY])
100         self.songs_list [self.song_counter] = new_song
101         try:
102             self.writer.save_metadata_on_file (new_song[FILE_URI],
103                                                new_song[MIME_KEY],
104                                                self.artist_button.get_value (),
105                                                self.title_entry.get_text (),
106                                                self.album_button.get_value ())
107         except IOError, e:
108             # This error in case of tracker returning unexistent files.
109             # Uhm.... for instance after removing a memory card we are editing!
110             dialog = gtk.MessageDialog (self,
111                                         gtk.DIALOG_DESTROY_WITH_PARENT,
112                                         gtk.MESSAGE_ERROR,
113                                         gtk.BUTTONS_CLOSE,
114                                         "%s" % str(e));
115             dialog.run ()
116
117         
118
119     def __is_view_dirty (self):
120         """
121         True if the data has been modified in the widgets
122         """
123         song = self.songs_list [self.song_counter]
124
125         return not (self.filename_data.get_text() == song[FILE_URI] and
126                     self.artist_button.get_value () == song[ARTIST_KEY] and
127                     self.title_entry.get_text () == song[TITLE_KEY] and
128                     self.album_button.get_value () == song[ALBUM_KEY] )
129         
130
131     def __create_view (self):
132         view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
133
134         filename_row = gtk.HBox ()
135         filename_label = gtk.Label ("Filename:")
136         filename_row.pack_start (filename_label, expand=False, padding=12);
137         self.filename_data = gtk.Label ("")
138         filename_row.pack_start (self.filename_data, expand=True)
139
140         play_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
141         img = gtk.image_new_from_stock (gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON)
142         play_button.set_image (img)
143         play_button.connect ("clicked", self.clicked_play)
144         filename_row.pack_start (play_button, expand=False, fill=False)
145         view_vbox.pack_start (filename_row, expand=False);
146
147         central_panel = gtk.HBox (spacing=12)
148
149         table = gtk.Table (3, 2, False)
150         table.set_col_spacings (12)
151         table.set_row_spacings (12)
152
153         central_panel.pack_start (table, fill=True)
154         view_vbox.pack_start (central_panel, expand=True, fill=True)
155
156         # Title row
157         label_title = gtk.Label ("Title:")
158         table.attach (label_title, 0, 1, 0, 1, 0)
159         self.title_entry = gtk.Entry()
160         table.attach (self.title_entry, 1, 2, 0, 1)
161
162         # Artist row
163         artist_selector = hildon.TouchSelectorEntry (text=True)
164         for a in self.artists_list:
165             artist_selector.append_text (a)
166         self.artist_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
167                                                   hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
168         self.artist_button.set_title ("Artist: ")
169         self.artist_button.set_selector (artist_selector)
170         table.attach (self.artist_button, 0, 2, 1, 2)
171
172
173         # Album row
174         album_selector = hildon.TouchSelectorEntry (text=True)
175         for a in self.albums_list:
176             album_selector.append_text (a)
177         self.album_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
178                                                  hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
179         self.album_button.set_title ("Album: ")
180         self.album_button.set_selector (album_selector)
181         table.attach (self.album_button, 0, 2, 2, 3) 
182         
183
184         # Album art space
185         album_art_button = gtk.Button ()
186         self.album_art = gtk.Image ()
187         self.album_art.set_size_request (124, 124)
188         album_art_button.add (self.album_art)
189         album_art_button.connect ("clicked", self.clicked_album_art)
190         central_panel.pack_start (album_art_button, expand=False, fill=False)
191         
192         # Buttons row
193         button_box = gtk.HButtonBox ()
194         button_box.set_layout (gtk.BUTTONBOX_END)
195
196         back_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
197         img = gtk.image_new_from_stock (gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
198         back_button.set_image (img)
199         back_button.connect ("clicked", self.press_back_cb)
200         button_box.pack_start (back_button, expand=True, fill=True, padding=6)
201         
202         next_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
203         img = gtk.image_new_from_stock (gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
204         next_button.set_image (img)
205         next_button.connect ("clicked", self.press_next_cb)
206         button_box.pack_start (next_button, expand=True, fill=True, padding=6)
207         
208         view_vbox.pack_start (button_box, expand=False, fill=True, padding=6)
209         
210         self.add (view_vbox)
211
212         #menu = hildon.AppMenu ()
213         #go_to = hildon.Button (hildon.BUTTON_STYLE_NORMAL,
214         #                       hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
215         #go_to.set_title ("Go to")
216         #go_to.connect ("clicked", self.go_to_cb)
217         #menu.append (go_to)
218         #menu.show_all ()
219         #self.set_app_menu (menu)
220         
221
222     def go_to_cb (self, widget):
223         pass
224
225     def set_data_in_view (self, song):
226         """
227         Place in the screen the song information.
228         Song is a tuple like (filename, 'Music', title, artist, album, mime)
229         """
230         assert len (song) == 6
231         
232         self.filename_data.set_text (song[FILE_URI])
233         self.title_entry.set_text (song[TITLE_KEY])
234         
235
236         # Disconnect the value-change signal to avoid extra album art retrievals
237         if (self.album_button.handler_is_connected (self.album_change_handler)):
238             self.album_button.disconnect (self.album_change_handler)
239             
240         if (self.artist_button.handler_is_connected (self.artist_change_handler)):
241             self.artist_button.disconnect (self.artist_change_handler)
242
243         # Set values in the picker buttons
244         try:
245             self.artist_button.set_active (self.artists_list.index(song[ARTIST_KEY]))
246         except ValueError:
247             print "'%s' not in artist list!?" % (song[ARTIST_KEY])
248             self.artist_button.set_value ("")
249             
250         try:
251             self.album_button.set_active (self.albums_list.index (song[ALBUM_KEY]))
252         except ValueError:
253             print "'%s' is not in the album list!?" % (song[ALBUM_KEY])
254             self.album_button.set_value ("")
255
256         # Reconnect the signals!
257         self.album_change_handler = self.album_button.connect ("value-changed",
258                                                                self.album_selection_cb)
259
260         self.artist_change_handler = self.artist_button.connect ("value-changed",
261                                                                  self.artist_selection_cb)
262
263         # Set the album art given the current data
264         has_album = False
265         if (song[ALBUM_KEY]):
266             thumb = album_art_spec.getCoverArtThumbFileName (song[ALBUM_KEY])
267             print "%s -> %s" % (song[ALBUM_KEY], thumb)
268             if (os.path.exists (thumb)):
269                 self.album_art.set_from_file (thumb)
270                 has_album = True
271             else:
272                 self.album_callback_id = gobject.idle_add (self.retrieve_album_art,
273                                                            song[ARTIST_KEY], song[ALBUM_KEY])
274                 
275         if (not has_album):
276             self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
277
278         if (not song[MIME_KEY] in self.writer.get_supported_mimes ()):
279             print "show notification"
280             self.banner = hildon.Banner ()
281             self.banner.set_text ("Unsupported format (%s)" % song[MIME_KEY])
282             self.banner.show_all ()
283
284     def retrieve_album_art (self, artist, album):
285         print "trying to get the album art"
286         (img, thumb) = self.album_art_retriever.get_album_art (artist, album)
287         if (thumb):
288             self.album_art.set_from_file (thumb)
289         else:
290             print "Unable to retrieve album art"
291
292         return False
293         
294     def clicked_play (self, widget):
295         if (self.player.is_playing ()):
296             self.player.stop ()
297         else:
298             song = self.songs_list [self.song_counter]
299             self.player.play ("file://" + song[FILE_URI])
300
301     def clicked_album_art (self, widget):
302         print "implement me, please"
303
304     def album_selection_cb (self, widget):
305         """
306         On album change, add the album the local list of albums and the selector
307         if it doesn't exist already. So we show the new entry in the selector next time.
308         """
309         song = self.songs_list [self.song_counter]
310         if (not widget.get_value () in self.albums_list):
311             print "Inserting ", widget.get_value ()
312             widget.get_selector ().prepend_text (widget.get_value ())
313             self.albums_list.insert (0, widget.get_value ())
314         self.retrieve_album_art (song[ARTIST_KEY], widget.get_value ())
315
316     def artist_selection_cb (self, widget):
317         """
318         On artist change, add the artist the local list of artists and the selector
319         if it doesn't exist already. So we show the new entry in the selector next time
320         """
321         song = self.songs_list [self.song_counter]
322         if (not widget.get_value () in self.artists_list):
323             print "Inserting artist", widget.get_value ()
324             widget.get_selector ().prepend_text (widget.get_value ())
325             self.artists_list.insert (0, widget.get_value ())
326     
327 # Testing porpuses
328 if __name__ == "__main__":
329
330     TEST_DATA = [("/home/user/Music/dylan.mp3", "Music", "Bob Dylan", "Subterranean homesick blues", "Bring it all back home", "audio/mpeg"),
331                  ("/home/user/mufix/a.mp3", "Music", "", "title", "Album 2", "a/b"),
332                  ("/media/mmc1/Attachments/b.m4a", "Music", "", "b", "Album 9", "audio/mpeg"),
333                  ("/home/user/mufix/3.mp2", "Music", "", "titlex", "Album 3", "audio/mpeg")]
334     #TEST_DATA = []
335     ALBUMS = [["Album %d" % i] for i in range (0, 10)] + [["Bring it all back home"]]
336     ARTISTS = [["Artist %d" % i] for i in range (0, 10)] + [["Bob Dylan"]]
337     window = MussorgskyEditPanel (TEST_DATA, ALBUMS, ARTISTS)
338     window.connect ("destroy", gtk.main_quit)
339     window.show_all ()
340     gtk.main ()