1 #!/usr/bin/env python2.5
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
7 from album_art import MussorgskyAlbumArt
10 # Fields in the tuple!
17 class MussorgskyEditPanel (hildon.StackableWindow):
19 def __init__ (self, songs_list=None, albums_list=None, artists_list=None):
20 hildon.StackableWindow.__init__ (self)
21 self.set_border_width (12)
23 self.album_callback_id = -1
24 self.album_change_handler = -1
25 self.artist_change_handler = -1
26 self.writer = MutagenBackend ()
27 self.player = MediaPlayer ()
28 self.album_art_retriever = MussorgskyAlbumArt ()
29 self.albums_list = [a [0] for a in albums_list]
30 self.artists_list = [a [0] for a in artists_list]
31 self.add (self.__create_view ())
33 self.set_songs_list (songs_list)
37 def update_title (self):
38 self.set_title ("Edit (%d/%d)" % (self.song_counter+1, len (self.songs_list)))
41 def set_songs_list (self, songs_list):
42 if (songs_list and len (songs_list) > 0):
43 self.songs_list = songs_list
44 self.set_data_in_view (songs_list [0])
47 def press_back_cb (self, widget):
48 if (self.player.is_playing ()):
51 if (self.banner and self.banner.get_property("visible")):
52 self.banner.destroy ()
54 if (self.album_callback_id != -1):
55 gobject.source_remove (self.album_callback_id)
56 self.album_callback_id = -1
58 if self.__is_view_dirty ():
59 print "Modified data. Save!"
62 if (self.song_counter > 0):
63 self.song_counter -= 1
64 self.set_data_in_view (self.songs_list [self.song_counter])
69 def press_next_cb (self, widget):
70 if (self.player.is_playing ()):
73 if (self.banner and self.banner.get_property("visible")):
74 self.banner.destroy ()
76 if (self.album_callback_id != -1):
77 gobject.source_remove (self.album_callback_id)
78 self.album_callback_id = -1
80 if self.__is_view_dirty ():
81 print "Modified data. Save!"
84 if (self.song_counter < len (self.songs_list) -1):
85 self.song_counter += 1
86 self.set_data_in_view (self.songs_list [self.song_counter])
91 def save_metadata (self):
92 # Save the data in the online model to show the appropiate data
93 # in the UI while tracker process the update.
94 song = self.songs_list [self.song_counter]
96 new_song = (song[FILE_URI], song[1],
97 self.artist_button.get_value (),
98 self.title_entry.get_text (),
99 self.album_button.get_value (),
101 self.songs_list [self.song_counter] = new_song
103 self.writer.save_metadata_on_file (new_song[FILE_URI],
105 self.artist_button.get_value (),
106 self.title_entry.get_text (),
107 self.album_button.get_value ())
109 # This error in case of tracker returning unexistent files.
110 # Uhm.... for instance after removing a memory card we are editing!
111 dialog = gtk.MessageDialog (self,
112 gtk.DIALOG_DESTROY_WITH_PARENT,
120 def __is_view_dirty (self):
122 True if the data has been modified in the widgets
124 song = self.songs_list [self.song_counter]
126 return not (self.filename_data.get_text() == song[FILE_URI] and
127 self.artist_button.get_value () == song[ARTIST_KEY] and
128 self.title_entry.get_text () == song[TITLE_KEY] and
129 self.album_button.get_value () == song[ALBUM_KEY] )
132 def __create_view (self):
133 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
135 filename_row = gtk.HBox ()
136 filename_label = gtk.Label ("Filename:")
137 filename_row.pack_start (filename_label, expand=False, padding=12);
138 self.filename_data = gtk.Label ("")
139 filename_row.pack_start (self.filename_data, expand=True)
141 play_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
142 img = gtk.image_new_from_stock (gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON)
143 play_button.set_image (img)
144 play_button.connect ("clicked", self.clicked_play)
145 filename_row.pack_start (play_button, expand=False, fill=False)
146 view_vbox.pack_start (filename_row, expand=False);
148 central_panel = gtk.HBox (spacing=12)
150 table = gtk.Table (3, 2, False)
151 table.set_col_spacings (12)
152 table.set_row_spacings (12)
154 central_panel.pack_start (table, fill=True)
155 view_vbox.pack_start (central_panel, expand=True, fill=True)
158 label_title = gtk.Label ("Title:")
159 table.attach (label_title, 0, 1, 0, 1, 0)
160 self.title_entry = gtk.Entry()
161 table.attach (self.title_entry, 1, 2, 0, 1)
164 artist_selector = hildon.hildon_touch_selector_new_text ()
165 for a in self.artists_list:
166 artist_selector.append_text (a)
167 self.artist_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
168 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
169 self.artist_button.set_title ("Artist: ")
170 self.artist_button.set_selector (artist_selector)
171 table.attach (self.artist_button, 0, 2, 1, 2)
175 album_selector = hildon.hildon_touch_selector_new_text ()
176 for a in self.albums_list:
177 album_selector.append_text (a)
178 self.album_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
179 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
180 self.album_button.set_title ("Album: ")
181 self.album_button.set_selector (album_selector)
182 table.attach (self.album_button, 0, 2, 2, 3)
186 album_art_button = gtk.Button ()
187 self.album_art = gtk.Image ()
188 self.album_art.set_size_request (124, 124)
189 album_art_button.add (self.album_art)
190 album_art_button.connect ("clicked", self.clicked_album_art)
191 central_panel.pack_start (album_art_button, expand=False, fill=False)
194 button_box = gtk.HButtonBox ()
195 button_box.set_layout (gtk.BUTTONBOX_END)
197 back_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
198 img = gtk.image_new_from_stock (gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
199 back_button.set_image (img)
200 back_button.connect ("clicked", self.press_back_cb)
201 button_box.pack_start (back_button, expand=True, fill=True, padding=6)
203 next_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
204 img = gtk.image_new_from_stock (gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
205 next_button.set_image (img)
206 next_button.connect ("clicked", self.press_next_cb)
207 button_box.pack_start (next_button, expand=True, fill=True, padding=6)
209 view_vbox.pack_start (button_box, expand=False, fill=True, padding=6)
214 def set_data_in_view (self, song):
216 Place in the screen the song information.
217 Song is a tuple like (filename, 'Music', title, artist, album, mime)
219 assert len (song) == 6
221 self.filename_data.set_text (song[FILE_URI])
222 self.title_entry.set_text (song[TITLE_KEY])
225 # Disconnect the value-change signal to avoid extra album art retrievals
226 if (self.album_button.handler_is_connected (self.album_change_handler)):
227 self.album_button.disconnect (self.album_change_handler)
229 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
230 self.artist_button.disconnect (self.artist_change_handler)
232 # Set values in the picker buttons
234 self.artist_button.set_active (self.artists_list.index(song[ARTIST_KEY]))
236 print "'%s' not in artist list!?" % (song[ARTIST_KEY])
237 self.artist_button.set_value ("")
240 self.album_button.set_active (self.albums_list.index (song[ALBUM_KEY]))
242 print "'%s' is not in the album list!?" % (song[ALBUM_KEY])
243 self.album_button.set_value ("")
245 # Reconnect the signals!
246 self.album_change_handler = self.album_button.connect ("value-changed",
247 self.album_selection_cb)
249 self.artist_change_handler = self.artist_button.connect ("value-changed",
250 self.artist_selection_cb)
252 # Set the album art given the current data
254 if (song[ALBUM_KEY]):
255 thumb = album_art_spec.getCoverArtThumbFileName (song[ALBUM_KEY])
256 print "%s -> %s" % (song[ALBUM_KEY], thumb)
257 if (os.path.exists (thumb)):
258 self.album_art.set_from_file (thumb)
261 self.album_callback_id = gobject.idle_add (self.retrieve_album_art,
262 song[ARTIST_KEY], song[ALBUM_KEY])
265 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
267 if (not song[MIME_KEY] in self.writer.get_supported_mimes ()):
268 print "show notification"
269 self.banner = hildon.Banner ()
270 self.banner.set_text ("Unsupported format (%s)" % song[MIME_KEY])
271 self.banner.show_all ()
273 def retrieve_album_art (self, artist, album):
274 print "trying to get the album art"
275 (img, thumb) = self.album_art_retriever.get_album_art (artist, album)
277 self.album_art.set_from_file (thumb)
279 print "Unable to retrieve album art"
283 def clicked_play (self, widget):
284 if (self.player.is_playing ()):
287 song = self.songs_list [self.song_counter]
288 self.player.play ("file://" + song[FILE_URI])
290 def clicked_album_art (self, widget):
291 print "implement me, please"
293 def album_selection_cb (self, widget):
295 On album change, add the album the local list of albums and the selector
296 if it doesn't exist already. So we show the new entry in the selector next time.
298 song = self.songs_list [self.song_counter]
299 if (not widget.get_value () in self.albums_list):
300 print "Inserting ", widget.get_value ()
301 widget.get_selector ().prepend_text (widget.get_value ())
302 self.albums_list.insert (0, widget.get_value ())
303 self.retrieve_album_art (song[ARTIST_KEY], widget.get_value ())
305 def artist_selection_cb (self, widget):
307 On artist change, add the artist the local list of artists and the selector
308 if it doesn't exist already. So we show the new entry in the selector next time
310 song = self.songs_list [self.song_counter]
311 if (not widget.get_value () in self.artists_list):
312 print "Inserting artist", widget.get_value ()
313 widget.get_selector ().prepend_text (widget.get_value ())
314 self.artists_list.insert (0, widget.get_value ())
317 if __name__ == "__main__":
319 TEST_DATA = [("/home/user/Music/dylan.mp3", "Music", "Bob Dylan", "Subterranean homesick blues", "Bring it all back home", "audio/mpeg"),
320 ("/home/user/mufix/a.mp3", "Music", "", "title", "Album 2", "a/b"),
321 ("/media/mmc1/Attachments/b.m4a", "Music", "", "b", "Album 9", "audio/mpeg"),
322 ("/home/user/mufix/3.mp2", "Music", "", "titlex", "Album 3", "audio/mpeg")]
324 ALBUMS = [["Album %d" % i] for i in range (0, 10)] + [["Bring it all back home"]]
325 ARTISTS = [["Artist %d" % i] for i in range (0, 10)] + [["Bob Dylan"]]
326 window = MussorgskyEditPanel (TEST_DATA, ALBUMS, ARTISTS)
327 window.connect ("destroy", gtk.main_quit)