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 THEME_PATH = "/usr/share/themes/default"
22 class MussorgskyEditPanel (hildon.StackableWindow):
25 hildon.StackableWindow.__init__ (self)
26 self.set_border_width (12)
27 self.album_change_handler = -1
28 self.artist_change_handler = -1
29 self.writer = MutagenBackend ()
30 self.player = MediaPlayer ()
32 self.data_loaded = False
33 self.artist_list = None
34 self.albums_list = None
36 self.connect ("delete-event", self.close_function)
38 def close_function (self, widget, event):
39 if (not self.data_loaded):
42 if self.__is_view_dirty ():
46 def update_title (self):
47 self.set_title ("Edit (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
50 def get_current_row (self):
51 if (not self.current):
53 return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
55 def set_model (self, model, current=None):
56 assert type(model) == gtk.TreeModelFilter
58 if self.artists_list or self.albums_list:
60 except AttributeError, e:
61 print "**** Set album and artist alternatives before setting a model"
66 self.current = current
68 self.current = self.model.get_iter_first ()
69 self.data_loaded = True
70 self.set_data_in_view (self.get_current_row ())
73 def set_current (self, current):
75 Iterator to current element
77 self.current = current
78 self.set_data_in_view (self.get_current_row ())
82 def set_artist_alternatives (self, alternatives):
83 self.artists_list = alternatives
84 artist_selector = hildon.TouchSelectorEntry (text=True)
85 for a in self.artists_list:
86 artist_selector.append_text (a)
87 self.artist_button.set_selector (artist_selector)
89 def set_album_alternatives (self, alternatives):
90 self.albums_list = alternatives
91 album_selector = hildon.TouchSelectorEntry (text=True)
92 for a in self.albums_list:
93 album_selector.append_text (a)
94 self.album_button.set_selector (album_selector)
97 def press_back_cb (self, widget):
98 if (self.player.is_playing ()):
101 if self.__is_view_dirty ():
102 print "Modified data. Save!"
103 self.save_metadata ()
105 path = self.model.get_path (self.current)
109 new_path = ( path[0] -1, )
110 self.current = self.model.get_iter (new_path)
111 self.set_data_in_view (self.get_current_row ())
114 def press_next_cb (self, widget):
115 if (self.player.is_playing ()):
118 if self.__is_view_dirty ():
119 print "Modified data. Save!"
120 self.save_metadata ()
122 self.current = self.model.iter_next (self.current)
123 if (not self.current):
126 self.set_data_in_view (self.get_current_row ())
130 def save_metadata (self):
131 # Save the data in the online model to show the appropiate data
132 # in the UI while tracker process the update.
134 # 0 - filename -> doesn't change
135 # 1 - "Music" -> doesn't change
136 # 5 - mimetype -> doesn't change
137 m = self.model.get_model ()
138 c = self.model.convert_iter_to_child_iter (self.current)
140 artist = self.artist_button.get_value ()
141 title = self.title_entry.get_text ()
142 album = self.album_button.get_value ()
143 text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
144 escape_html (artist) + " / " + escape_html (album))
145 search_str = artist.lower () + " " + title.lower () + " " + album.lower ()
147 uri, mime = m.get (c, URI_COLUMN, MIME_COLUMN)
149 ARTIST_COLUMN, artist,
153 SEARCH_COLUMN, search_str)
155 self.writer.save_metadata_on_file (uri,#new_song[URI_COLUMN],
156 mime, #new_song[MIME_COLUMN],
157 self.artist_button.get_value (),
158 self.title_entry.get_text (),
159 self.album_button.get_value ())
161 # This error in case of tracker returning unexistent files.
162 # Uhm.... for instance after removing a memory card we are editing!
166 def __is_view_dirty (self):
168 True if the data has been modified in the widgets
170 song = self.get_current_row ()
172 return not (self.filename_data.get_text() == song[URI_COLUMN] and
173 self.artist_button.get_value () == song[ARTIST_COLUMN] and
174 self.title_entry.get_text () == song[TITLE_COLUMN] and
175 self.album_button.get_value () == song[ALBUM_COLUMN] )
178 def __create_view (self):
179 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
181 filename_row = gtk.HBox ()
182 self.filename_data = gtk.Label ("")
183 filename_row.pack_start (self.filename_data, expand=True)
185 #filename_row.pack_start (play_button, expand=False, fill=False)
186 view_vbox.pack_start (filename_row, expand=False);
188 central_panel = gtk.HBox (spacing=12)
190 table = gtk.Table (3, 2, False)
191 table.set_col_spacings (12)
192 table.set_row_spacings (12)
194 central_panel.pack_start (table, fill=True)
195 view_vbox.pack_start (central_panel, expand=True, fill=True)
198 label_title = gtk.Label ("Title:")
199 table.attach (label_title, 0, 1, 0, 1, 0)
200 self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
201 table.attach (self.title_entry, 1, 2, 0, 1)
204 self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
205 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
206 self.artist_button.set_title ("Artist: ")
207 # Set data will set the selector
208 table.attach (self.artist_button, 0, 2, 1, 2)
212 self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
213 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
214 self.album_button.set_title ("Album: ")
215 # set_data will set the selector
216 table.attach (self.album_button, 0, 2, 2, 3)
220 self.album_art = gtk.Image ()
221 self.album_art.set_size_request (124, 124)
222 central_panel.pack_start (self.album_art, expand=False, fill=False)
225 button_box = gtk.Toolbar ()
226 play_image = os.path.join (THEME_PATH, "mediaplayer", "Play.png")
227 play_button = gtk.ToolButton (gtk.image_new_from_file (play_image))
228 play_button.connect ("clicked", self.clicked_play)
229 play_button.set_expand (True)
230 button_box.insert (play_button, -1)
232 separator = gtk.SeparatorToolItem ()
233 separator.set_expand (True)
234 button_box.insert (separator, -1)
236 back_image = os.path.join (THEME_PATH, "mediaplayer", "Back.png")
237 back_button = gtk.ToolButton (gtk.image_new_from_file (back_image))
238 back_button.connect ("clicked", self.press_back_cb)
239 back_button.set_expand (True)
240 button_box.insert (back_button, -1)
242 next_image = os.path.join (THEME_PATH, "mediaplayer", "Forward.png")
243 next_button = gtk.ToolButton (gtk.image_new_from_file (next_image))
244 next_button.connect ("clicked", self.press_next_cb)
245 next_button.set_expand (True)
246 button_box.insert (next_button, -1)
248 self.add_toolbar (button_box)
253 def set_data_in_view (self, song):
255 Place in the screen the song information.
256 Song is a tuple like (filename, 'Music', title, artist, album, mime)
258 assert len (song) == 6
260 self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
261 self.title_entry.set_text (song[TITLE_COLUMN])
264 # Disconnect the value-change signal to avoid extra album art retrievals
265 if (self.album_button.handler_is_connected (self.album_change_handler)):
266 self.album_button.disconnect (self.album_change_handler)
268 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
269 self.artist_button.disconnect (self.artist_change_handler)
271 # Set values in the picker buttons
273 self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
275 print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
276 self.artist_button.set_value ("")
277 except AttributeError:
278 print "WARNING: Use set_artist_alternatives method to set a list of artists"
281 self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
283 print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
284 self.album_button.set_value ("")
285 except AttributeError:
286 print "WARNING: Use set_album_alternatives method to set a list of artists"
288 # Reconnect the signals!
289 self.album_change_handler = self.album_button.connect ("value-changed",
290 self.album_selection_cb)
292 self.artist_change_handler = self.artist_button.connect ("value-changed",
293 self.artist_selection_cb)
295 # Set the album art given the current data
296 self.set_album_art (song[ALBUM_COLUMN])
298 if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
299 self.artist_button.set_sensitive (False)
300 self.album_button.set_sensitive (False)
301 self.title_entry.set_sensitive (False)
303 self.artist_button.set_sensitive (True)
304 self.album_button.set_sensitive (True)
305 self.title_entry.set_sensitive (True)
307 def set_album_art (self, album):
310 thumb = album_art_spec.getCoverArtThumbFileName (album)
311 print "%s -> %s" % (album, thumb)
312 if (os.path.exists (thumb)):
313 self.album_art.set_from_file (thumb)
317 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
320 def clicked_play (self, widget):
321 if (self.player.is_playing ()):
324 song = self.get_current_row ()
325 self.player.play ("file://" + song[URI_COLUMN])
327 def album_selection_cb (self, widget):
329 On album change, add the album the local list of albums and the selector
330 if it doesn't exist already. So we show the new entry in the selector next time.
332 song = self.get_current_row ()
333 if (not widget.get_value () in self.albums_list):
334 print "Inserting ", widget.get_value ()
335 widget.get_selector ().prepend_text (widget.get_value ())
336 self.albums_list.insert (0, widget.get_value ())
337 self.set_album_art (widget.get_value ())
339 def artist_selection_cb (self, widget):
341 On artist change, add the artist the local list of artists and the selector
342 if it doesn't exist already. So we show the new entry in the selector next time
344 song = self.get_current_row ()
345 if (not widget.get_value () in self.artists_list):
346 print "Inserting artist", widget.get_value ()
347 widget.get_selector ().prepend_text (widget.get_value ())
348 self.artists_list.insert (0, widget.get_value ())
351 if __name__ == "__main__":
353 TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
354 "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
356 "artist %d album %d" % (i, i*100),
357 "text to be searched artist %d album %d" % (i, i*100)) for i in range (0, 4)]
359 model = gtk.ListStore (str, str, str, str, str, str, str, str)
364 window = MussorgskyEditPanel ()
365 window.set_artist_alternatives (["Artist %d" % i for i in range (0, 4)])
366 window.set_album_alternatives (["Album %d" % (i*100) for i in range (0, 4)])
367 window.set_model (model.filter_new ())
368 window.connect ("destroy", gtk.main_quit)