1 #!/usr/bin/env python2.5
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
6 from utils import escape_html
10 # Fields in the tuple!
11 # Shared with browse_panel
20 class MussorgskyEditPanel (hildon.StackableWindow):
23 hildon.StackableWindow.__init__ (self)
24 self.set_border_width (12)
25 self.album_callback_id = -1
26 self.album_change_handler = -1
27 self.artist_change_handler = -1
28 self.writer = MutagenBackend ()
29 self.player = MediaPlayer ()
31 self.data_loaded = False
32 self.artist_list = None
33 self.albums_list = None
34 self.connect ("delete-event", self.close_function)
36 def close_function (self, widget, event):
37 if (not self.data_loaded):
40 if self.__is_view_dirty ():
44 def update_title (self):
45 self.set_title ("Edit (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
48 def get_current_row (self):
49 if (not self.current):
51 return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
53 def set_model (self, model, current=None):
55 if self.artists_list or self.albums_list:
57 except AttributeError, e:
58 print "**** Set album and artist alternatives before setting a model"
63 self.current = current
65 self.current = self.model.get_iter_first ()
66 self.data_loaded = True
67 self.set_data_in_view (self.get_current_row ())
70 def set_current (self, current):
72 Iterator to current element
74 self.current = current
75 self.set_data_in_view (self.get_current_row ())
79 def set_artist_alternatives (self, alternatives):
80 self.artists_list = alternatives
81 artist_selector = hildon.TouchSelectorEntry (text=True)
82 for a in self.artists_list:
83 artist_selector.append_text (a)
84 self.artist_button.set_selector (artist_selector)
86 def set_album_alternatives (self, alternatives):
87 self.albums_list = alternatives
88 album_selector = hildon.TouchSelectorEntry (text=True)
89 for a in self.albums_list:
90 album_selector.append_text (a)
91 self.album_button.set_selector (album_selector)
94 def press_back_cb (self, widget):
95 if (self.player.is_playing ()):
98 if (self.album_callback_id != -1):
99 gobject.source_remove (self.album_callback_id)
100 self.album_callback_id = -1
102 if self.__is_view_dirty ():
103 print "Modified data. Save!"
104 self.save_metadata ()
106 path = self.model.get_path (self.current)
110 new_path = ( path[0] -1, )
111 self.current = self.model.get_iter (new_path)
112 self.set_data_in_view (self.get_current_row ())
115 def press_next_cb (self, widget):
116 if (self.player.is_playing ()):
119 if (self.album_callback_id != -1):
120 gobject.source_remove (self.album_callback_id)
121 self.album_callback_id = -1
123 if self.__is_view_dirty ():
124 print "Modified data. Save!"
125 self.save_metadata ()
127 self.current = self.model.iter_next (self.current)
128 if (not self.current):
131 self.set_data_in_view (self.get_current_row ())
135 def save_metadata (self):
136 # Save the data in the online model to show the appropiate data
137 # in the UI while tracker process the update.
139 # 0 - filename -> doesn't change
140 # 1 - "Music" -> doesn't change
141 # 5 - mimetype -> doesn't change
142 if (type (self.model) == gtk.TreeModelFilter):
143 m = self.model.get_model ()
144 c = self.model.convert_iter_to_child_iter (self.current)
150 artist = self.artist_button.get_value ()
151 title = self.title_entry.get_text ()
152 album = self.album_button.get_value ()
153 text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
154 escape_html (artist) + " / " + escape_html (album))
155 search_str = artist.lower () + " " + title.lower () + " " + album.lower ()
158 ARTIST_COLUMN, artist,
162 SEARCH_COLUMN, search_str)
163 new_song = self.get_current_row ()
165 self.writer.save_metadata_on_file (new_song[URI_COLUMN],
166 new_song[MIME_COLUMN],
167 self.artist_button.get_value (),
168 self.title_entry.get_text (),
169 self.album_button.get_value ())
171 # This error in case of tracker returning unexistent files.
172 # Uhm.... for instance after removing a memory card we are editing!
174 #dialog = gtk.MessageDialog (self,
175 # gtk.DIALOG_DESTROY_WITH_PARENT,
182 def __is_view_dirty (self):
184 True if the data has been modified in the widgets
186 song = self.get_current_row ()
188 return not (self.filename_data.get_text() == song[URI_COLUMN] and
189 self.artist_button.get_value () == song[ARTIST_COLUMN] and
190 self.title_entry.get_text () == song[TITLE_COLUMN] and
191 self.album_button.get_value () == song[ALBUM_COLUMN] )
194 def __create_view (self):
195 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
197 filename_row = gtk.HBox ()
198 filename_label = gtk.Label ()
199 filename_label.set_markup ("<small>Filename:</small>")
200 filename_row.pack_start (filename_label, expand=False, padding=12);
201 self.filename_data = gtk.Label ("")
202 filename_row.pack_start (self.filename_data, expand=True)
204 #filename_row.pack_start (play_button, expand=False, fill=False)
205 view_vbox.pack_start (filename_row, expand=False);
207 central_panel = gtk.HBox (spacing=12)
209 table = gtk.Table (3, 2, False)
210 table.set_col_spacings (12)
211 table.set_row_spacings (12)
213 central_panel.pack_start (table, fill=True)
214 view_vbox.pack_start (central_panel, expand=True, fill=True)
217 label_title = gtk.Label ("Title:")
218 table.attach (label_title, 0, 1, 0, 1, 0)
219 self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
220 table.attach (self.title_entry, 1, 2, 0, 1)
223 self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_FINGER_HEIGHT,
224 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
225 self.artist_button.set_title ("Artist: ")
226 # Set data will set the selector
227 table.attach (self.artist_button, 0, 2, 1, 2)
231 self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_FINGER_HEIGHT,
232 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
233 self.album_button.set_title ("Album: ")
234 # set_data will set the selector
235 table.attach (self.album_button, 0, 2, 2, 3)
239 self.album_art = gtk.Image ()
240 self.album_art.set_size_request (124, 124)
241 central_panel.pack_start (self.album_art, expand=False, fill=False)
244 button_box = gtk.Toolbar ()
246 play_button = gtk.ToolButton (gtk.image_new_from_stock (gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON))
247 play_button.connect ("clicked", self.clicked_play)
248 play_button.set_expand (True)
249 button_box.insert (play_button, -1)
251 separator = gtk.SeparatorToolItem ()
252 separator.set_expand (True)
253 button_box.insert (separator, -1)
255 back_button = gtk.ToolButton (gtk.image_new_from_stock (gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON))
256 back_button.connect ("clicked", self.press_back_cb)
257 back_button.set_expand (True)
258 button_box.insert (back_button, -1)
260 next_button = gtk.ToolButton (gtk.image_new_from_stock (gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON))
261 next_button.connect ("clicked", self.press_next_cb)
262 next_button.set_expand (True)
263 button_box.insert (next_button, -1)
265 self.add_toolbar (button_box)
270 def set_data_in_view (self, song):
272 Place in the screen the song information.
273 Song is a tuple like (filename, 'Music', title, artist, album, mime)
275 assert len (song) == 6
277 self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
278 self.title_entry.set_text (song[TITLE_COLUMN])
281 # Disconnect the value-change signal to avoid extra album art retrievals
282 if (self.album_button.handler_is_connected (self.album_change_handler)):
283 self.album_button.disconnect (self.album_change_handler)
285 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
286 self.artist_button.disconnect (self.artist_change_handler)
288 # Set values in the picker buttons
290 self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
292 print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
293 self.artist_button.set_value ("")
294 except AttributeError:
295 print "WARNING: Use set_artist_alternatives method to set a list of artists"
298 self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
300 print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
301 self.album_button.set_value ("")
302 except AttributeError:
303 print "WARNING: Use set_album_alternatives method to set a list of artists"
305 # Reconnect the signals!
306 self.album_change_handler = self.album_button.connect ("value-changed",
307 self.album_selection_cb)
309 self.artist_change_handler = self.artist_button.connect ("value-changed",
310 self.artist_selection_cb)
312 # Set the album art given the current data
313 self.set_album_art (song[ALBUM_COLUMN])
315 if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
316 self.artist_button.set_sensitive (False)
317 self.album_button.set_sensitive (False)
318 self.title_entry.set_sensitive (False)
320 self.artist_button.set_sensitive (True)
321 self.album_button.set_sensitive (True)
322 self.title_entry.set_sensitive (True)
324 def set_album_art (self, album):
327 thumb = album_art_spec.getCoverArtThumbFileName (album)
328 print "%s -> %s" % (album, thumb)
329 if (os.path.exists (thumb)):
330 self.album_art.set_from_file (thumb)
334 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
337 def clicked_play (self, widget):
338 if (self.player.is_playing ()):
341 song = self.songs_list [self.song_counter]
342 self.player.play ("file://" + song[URI_COLUMN])
344 def album_selection_cb (self, widget):
346 On album change, add the album the local list of albums and the selector
347 if it doesn't exist already. So we show the new entry in the selector next time.
349 song = self.get_current_row ()
350 if (not widget.get_value () in self.albums_list):
351 print "Inserting ", widget.get_value ()
352 widget.get_selector ().prepend_text (widget.get_value ())
353 self.albums_list.insert (0, widget.get_value ())
354 self.set_album_art (widget.get_value ())
356 def artist_selection_cb (self, widget):
358 On artist change, add the artist the local list of artists and the selector
359 if it doesn't exist already. So we show the new entry in the selector next time
361 song = self.get_current_row ()
362 if (not widget.get_value () in self.artists_list):
363 print "Inserting artist", widget.get_value ()
364 widget.get_selector ().prepend_text (widget.get_value ())
365 self.artists_list.insert (0, widget.get_value ())
368 if __name__ == "__main__":
370 TEST_DATA = [("/home/user/Music/dylan.mp3", "Music", "Bob Dylan", "Subterranean homesick blues", "Bring it all back home", "audio/mpeg"),
371 ("/home/user/mufix/a.mp3", "Music", "", "title", "Album 2", "a/b"),
372 ("/media/mmc1/Attachments/b.m4a", "Music", "", "b", "Album 9", "audio/mpeg"),
373 ("/home/user/mufix/3.mp2", "Music", "", "titlex", "Album 3", "audio/mpeg")]
375 model = gtk.ListStore (str, str, str, str, str, str)
379 window = MussorgskyEditPanel ()
380 window.set_artist_alternatives (["", "Bob Dylan"])
381 window.set_album_alternatives (["", "Bring it all back home", "Album 2", "Album 9", "Album 3"])
382 window.set_model (model)
383 window.connect ("destroy", gtk.main_quit)