1 #!/usr/bin/env python2.5
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
16 class MussorgskyEditPanel (hildon.StackableWindow):
19 hildon.StackableWindow.__init__ (self)
20 self.set_border_width (12)
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 ()
29 self.data_loaded = False
30 self.connect ("destroy", self.clean_banner)
32 def clean_banner (self):
33 if (self.banner and self.banner.get_property ("visible")):
34 self.banner.destroy ()
36 def update_title (self):
37 self.set_title ("Edit (%d/%d)" % (self.song_counter+1, len (self.songs_list)))
39 def set_data (self, songs_list, albums_list=None, artists_list=None):
41 Assumes albums and artists lists already sorted
43 assert not self.data_loaded
45 album_selector = hildon.TouchSelectorEntry (text=True)
48 self.albums_list.insert (0, a [0])
49 album_selector.append_text (a[0])
50 self.albums_list.reverse ()
51 self.album_button.set_selector (album_selector)
54 self.artists_list = []
55 artist_selector = hildon.TouchSelectorEntry (text=True)
57 for a in artists_list:
58 self.artists_list.insert (0,a [0])
59 artist_selector.append_text (a[0])
60 self.artists_list.reverse ()
61 self.artist_button.set_selector (artist_selector)
63 self.set_songs_list (songs_list)
65 self.data_loaded = True
67 def set_songs_list (self, songs_list):
68 if (songs_list and len (songs_list) > 0):
69 self.songs_list = songs_list
70 self.set_data_in_view (songs_list [0])
73 def press_back_cb (self, widget):
74 if (self.player.is_playing ()):
77 if (self.banner and self.banner.get_property("visible")):
78 self.banner.destroy ()
80 if (self.album_callback_id != -1):
81 gobject.source_remove (self.album_callback_id)
82 self.album_callback_id = -1
84 if self.__is_view_dirty ():
85 print "Modified data. Save!"
88 if (self.song_counter > 0):
89 self.song_counter -= 1
90 self.set_data_in_view (self.songs_list [self.song_counter])
95 def press_next_cb (self, widget):
96 if (self.player.is_playing ()):
99 if (self.banner and self.banner.get_property("visible")):
100 self.banner.destroy ()
102 if (self.album_callback_id != -1):
103 gobject.source_remove (self.album_callback_id)
104 self.album_callback_id = -1
106 if self.__is_view_dirty ():
107 print "Modified data. Save!"
108 self.save_metadata ()
110 if (self.song_counter < len (self.songs_list) -1):
111 self.song_counter += 1
112 self.set_data_in_view (self.songs_list [self.song_counter])
117 def save_metadata (self):
118 # Save the data in the online model to show the appropiate data
119 # in the UI while tracker process the update.
120 song = self.songs_list [self.song_counter]
122 new_song = (song[FILE_URI], song[1],
123 self.artist_button.get_value (),
124 self.title_entry.get_text (),
125 self.album_button.get_value (),
127 self.songs_list [self.song_counter] = new_song
129 self.writer.save_metadata_on_file (new_song[FILE_URI],
131 self.artist_button.get_value (),
132 self.title_entry.get_text (),
133 self.album_button.get_value ())
135 # This error in case of tracker returning unexistent files.
136 # Uhm.... for instance after removing a memory card we are editing!
137 dialog = gtk.MessageDialog (self,
138 gtk.DIALOG_DESTROY_WITH_PARENT,
146 def __is_view_dirty (self):
148 True if the data has been modified in the widgets
150 song = self.songs_list [self.song_counter]
152 return not (self.filename_data.get_text() == song[FILE_URI] and
153 self.artist_button.get_value () == song[ARTIST_KEY] and
154 self.title_entry.get_text () == song[TITLE_KEY] and
155 self.album_button.get_value () == song[ALBUM_KEY] )
158 def __create_view (self):
159 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
161 filename_row = gtk.HBox ()
162 filename_label = gtk.Label ("Filename:")
163 filename_row.pack_start (filename_label, expand=False, padding=12);
164 self.filename_data = gtk.Label ("")
165 filename_row.pack_start (self.filename_data, expand=True)
167 play_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
168 img = gtk.image_new_from_stock (gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON)
169 play_button.set_image (img)
170 play_button.connect ("clicked", self.clicked_play)
171 filename_row.pack_start (play_button, expand=False, fill=False)
172 view_vbox.pack_start (filename_row, expand=False);
174 central_panel = gtk.HBox (spacing=12)
176 table = gtk.Table (3, 2, False)
177 table.set_col_spacings (12)
178 table.set_row_spacings (12)
180 central_panel.pack_start (table, fill=True)
181 view_vbox.pack_start (central_panel, expand=True, fill=True)
184 label_title = gtk.Label ("Title:")
185 table.attach (label_title, 0, 1, 0, 1, 0)
186 self.title_entry = gtk.Entry()
187 table.attach (self.title_entry, 1, 2, 0, 1)
190 self.artist_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
191 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
192 self.artist_button.set_title ("Artist: ")
193 # Set data will set the selector
194 table.attach (self.artist_button, 0, 2, 1, 2)
198 self.album_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
199 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
200 self.album_button.set_title ("Album: ")
201 # set_data will set the selector
202 table.attach (self.album_button, 0, 2, 2, 3)
206 album_art_button = gtk.Button ()
207 self.album_art = gtk.Image ()
208 self.album_art.set_size_request (124, 124)
209 album_art_button.add (self.album_art)
210 album_art_button.connect ("clicked", self.clicked_album_art)
211 central_panel.pack_start (album_art_button, expand=False, fill=False)
214 button_box = gtk.HButtonBox ()
215 button_box.set_layout (gtk.BUTTONBOX_END)
217 back_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
218 img = gtk.image_new_from_stock (gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
219 back_button.set_image (img)
220 back_button.connect ("clicked", self.press_back_cb)
221 button_box.pack_start (back_button, expand=True, fill=True, padding=6)
223 next_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
224 img = gtk.image_new_from_stock (gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
225 next_button.set_image (img)
226 next_button.connect ("clicked", self.press_next_cb)
227 button_box.pack_start (next_button, expand=True, fill=True, padding=6)
229 view_vbox.pack_start (button_box, expand=False, fill=True, padding=6)
233 #menu = hildon.AppMenu ()
234 #go_to = hildon.Button (hildon.BUTTON_STYLE_NORMAL,
235 # hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
236 #go_to.set_title ("Go to")
237 #go_to.connect ("clicked", self.go_to_cb)
240 #self.set_app_menu (menu)
243 def go_to_cb (self, widget):
246 def set_data_in_view (self, song):
248 Place in the screen the song information.
249 Song is a tuple like (filename, 'Music', title, artist, album, mime)
251 assert len (song) == 6
253 self.filename_data.set_text (song[FILE_URI])
254 self.title_entry.set_text (song[TITLE_KEY])
257 # Disconnect the value-change signal to avoid extra album art retrievals
258 if (self.album_button.handler_is_connected (self.album_change_handler)):
259 self.album_button.disconnect (self.album_change_handler)
261 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
262 self.artist_button.disconnect (self.artist_change_handler)
264 # Set values in the picker buttons
266 self.artist_button.set_active (self.artists_list.index(song[ARTIST_KEY]))
268 print "'%s' not in artist list!?" % (song[ARTIST_KEY])
269 self.artist_button.set_value ("")
272 self.album_button.set_active (self.albums_list.index (song[ALBUM_KEY]))
274 print "'%s' is not in the album list!?" % (song[ALBUM_KEY])
275 self.album_button.set_value ("")
277 # Reconnect the signals!
278 self.album_change_handler = self.album_button.connect ("value-changed",
279 self.album_selection_cb)
281 self.artist_change_handler = self.artist_button.connect ("value-changed",
282 self.artist_selection_cb)
284 # Set the album art given the current data
286 if (song[ALBUM_KEY]):
287 thumb = album_art_spec.getCoverArtThumbFileName (song[ALBUM_KEY])
288 print "%s -> %s" % (song[ALBUM_KEY], thumb)
289 if (os.path.exists (thumb)):
290 self.album_art.set_from_file (thumb)
293 self.album_callback_id = gobject.idle_add (self.retrieve_album_art,
294 song[ARTIST_KEY], song[ALBUM_KEY])
297 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
299 if (not song[MIME_KEY] in self.writer.get_supported_mimes ()):
300 print "show notification"
301 self.banner = hildon.Banner ()
302 self.banner.set_text ("Unsupported format (%s)" % song[MIME_KEY])
303 self.banner.show_all ()
305 def retrieve_album_art (self, artist, album):
306 print "trying to get the album art"
307 (img, thumb) = self.album_art_retriever.get_album_art (artist, album)
309 self.album_art.set_from_file (thumb)
311 print "Unable to retrieve album art"
315 def clicked_play (self, widget):
316 if (self.player.is_playing ()):
319 song = self.songs_list [self.song_counter]
320 self.player.play ("file://" + song[FILE_URI])
322 def clicked_album_art (self, widget):
323 print "implement me, please"
325 def album_selection_cb (self, widget):
327 On album change, add the album the local list of albums and the selector
328 if it doesn't exist already. So we show the new entry in the selector next time.
330 song = self.songs_list [self.song_counter]
331 if (not widget.get_value () in self.albums_list):
332 print "Inserting ", widget.get_value ()
333 widget.get_selector ().prepend_text (widget.get_value ())
334 self.albums_list.insert (0, widget.get_value ())
335 self.retrieve_album_art (song[ARTIST_KEY], widget.get_value ())
337 def artist_selection_cb (self, widget):
339 On artist change, add the artist the local list of artists and the selector
340 if it doesn't exist already. So we show the new entry in the selector next time
342 song = self.songs_list [self.song_counter]
343 if (not widget.get_value () in self.artists_list):
344 print "Inserting artist", widget.get_value ()
345 widget.get_selector ().prepend_text (widget.get_value ())
346 self.artists_list.insert (0, widget.get_value ())
349 if __name__ == "__main__":
351 TEST_DATA = [("/home/user/Music/dylan.mp3", "Music", "Bob Dylan", "Subterranean homesick blues", "Bring it all back home", "audio/mpeg"),
352 ("/home/user/mufix/a.mp3", "Music", "", "title", "Album 2", "a/b"),
353 ("/media/mmc1/Attachments/b.m4a", "Music", "", "b", "Album 9", "audio/mpeg"),
354 ("/home/user/mufix/3.mp2", "Music", "", "titlex", "Album 3", "audio/mpeg")]
356 ALBUMS = [["Album %d" % i] for i in range (0, 10)] + [["Bring it all back home"]]
357 ARTISTS = [["Artist %d" % i] for i in range (0, 10)] + [["Bob Dylan"]]
358 window = MussorgskyEditPanel (TEST_DATA, ALBUMS, ARTISTS)
359 window.connect ("destroy", gtk.main_quit)