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
35 self.connect ("delete-event", self.close_function)
37 def close_function (self, widget, event):
38 if (not self.data_loaded):
41 if self.__is_view_dirty ():
45 def update_title (self):
46 self.set_title ("Edit (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
49 def get_current_row (self):
50 if (not self.current):
52 return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
54 def set_model (self, model, current=None):
55 assert type(model) == gtk.TreeModelFilter
57 if self.artists_list or self.albums_list:
59 except AttributeError, e:
60 print "**** Set album and artist alternatives before setting a model"
65 self.current = current
67 self.current = self.model.get_iter_first ()
68 self.data_loaded = True
69 self.set_data_in_view (self.get_current_row ())
72 def set_current (self, current):
74 Iterator to current element
76 self.current = current
77 self.set_data_in_view (self.get_current_row ())
81 def set_artist_alternatives (self, alternatives):
82 self.artists_list = alternatives
83 artist_selector = hildon.TouchSelectorEntry (text=True)
84 for a in self.artists_list:
85 artist_selector.append_text (a)
86 self.artist_button.set_selector (artist_selector)
88 def set_album_alternatives (self, alternatives):
89 self.albums_list = alternatives
90 album_selector = hildon.TouchSelectorEntry (text=True)
91 for a in self.albums_list:
92 album_selector.append_text (a)
93 self.album_button.set_selector (album_selector)
96 def press_back_cb (self, widget):
97 if (self.player.is_playing ()):
100 if self.__is_view_dirty ():
101 print "Modified data. Save!"
102 self.save_metadata ()
104 path = self.model.get_path (self.current)
108 new_path = ( path[0] -1, )
109 self.current = self.model.get_iter (new_path)
110 self.set_data_in_view (self.get_current_row ())
113 def press_next_cb (self, widget):
114 if (self.player.is_playing ()):
117 if self.__is_view_dirty ():
118 print "Modified data. Save!"
119 self.save_metadata ()
121 self.current = self.model.iter_next (self.current)
122 if (not self.current):
125 self.set_data_in_view (self.get_current_row ())
129 def save_metadata (self):
130 # Save the data in the online model to show the appropiate data
131 # in the UI while tracker process the update.
133 # 0 - filename -> doesn't change
134 # 1 - "Music" -> doesn't change
135 # 5 - mimetype -> doesn't change
136 m = self.model.get_model ()
137 c = self.model.convert_iter_to_child_iter (self.current)
139 artist = self.artist_button.get_value ()
140 title = self.title_entry.get_text ()
141 album = self.album_button.get_value ()
142 text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
143 escape_html (artist) + " / " + escape_html (album))
144 search_str = artist.lower () + " " + title.lower () + " " + album.lower ()
147 ARTIST_COLUMN, artist,
151 SEARCH_COLUMN, search_str)
152 new_song = self.get_current_row ()
154 self.writer.save_metadata_on_file (new_song[URI_COLUMN],
155 new_song[MIME_COLUMN],
156 self.artist_button.get_value (),
157 self.title_entry.get_text (),
158 self.album_button.get_value ())
160 # This error in case of tracker returning unexistent files.
161 # Uhm.... for instance after removing a memory card we are editing!
163 #dialog = gtk.MessageDialog (self,
164 # gtk.DIALOG_DESTROY_WITH_PARENT,
171 def __is_view_dirty (self):
173 True if the data has been modified in the widgets
175 song = self.get_current_row ()
177 return not (self.filename_data.get_text() == song[URI_COLUMN] and
178 self.artist_button.get_value () == song[ARTIST_COLUMN] and
179 self.title_entry.get_text () == song[TITLE_COLUMN] and
180 self.album_button.get_value () == song[ALBUM_COLUMN] )
183 def __create_view (self):
184 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
186 filename_row = gtk.HBox ()
187 self.filename_data = gtk.Label ("")
188 filename_row.pack_start (self.filename_data, expand=True)
190 #filename_row.pack_start (play_button, expand=False, fill=False)
191 view_vbox.pack_start (filename_row, expand=False);
193 central_panel = gtk.HBox (spacing=12)
195 table = gtk.Table (3, 2, False)
196 table.set_col_spacings (12)
197 table.set_row_spacings (12)
199 central_panel.pack_start (table, fill=True)
200 view_vbox.pack_start (central_panel, expand=True, fill=True)
203 label_title = gtk.Label ("Title:")
204 table.attach (label_title, 0, 1, 0, 1, 0)
205 self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
206 table.attach (self.title_entry, 1, 2, 0, 1)
209 self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
210 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
211 self.artist_button.set_title ("Artist: ")
212 # Set data will set the selector
213 table.attach (self.artist_button, 0, 2, 1, 2)
217 self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
218 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
219 self.album_button.set_title ("Album: ")
220 # set_data will set the selector
221 table.attach (self.album_button, 0, 2, 2, 3)
225 self.album_art = gtk.Image ()
226 self.album_art.set_size_request (124, 124)
227 central_panel.pack_start (self.album_art, expand=False, fill=False)
230 button_box = gtk.Toolbar ()
231 play_image = os.path.join (THEME_PATH, "mediaplayer", "Play.png")
232 play_button = gtk.ToolButton (gtk.image_new_from_file (play_image))
233 play_button.connect ("clicked", self.clicked_play)
234 play_button.set_expand (True)
235 button_box.insert (play_button, -1)
237 separator = gtk.SeparatorToolItem ()
238 separator.set_expand (True)
239 button_box.insert (separator, -1)
241 back_image = os.path.join (THEME_PATH, "mediaplayer", "Back.png")
242 back_button = gtk.ToolButton (gtk.image_new_from_file (back_image))
243 back_button.connect ("clicked", self.press_back_cb)
244 back_button.set_expand (True)
245 button_box.insert (back_button, -1)
247 next_image = os.path.join (THEME_PATH, "mediaplayer", "Forward.png")
248 next_button = gtk.ToolButton (gtk.image_new_from_file (next_image))
249 next_button.connect ("clicked", self.press_next_cb)
250 next_button.set_expand (True)
251 button_box.insert (next_button, -1)
253 self.add_toolbar (button_box)
258 def set_data_in_view (self, song):
260 Place in the screen the song information.
261 Song is a tuple like (filename, 'Music', title, artist, album, mime)
263 assert len (song) == 6
265 self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
266 self.title_entry.set_text (song[TITLE_COLUMN])
269 # Disconnect the value-change signal to avoid extra album art retrievals
270 if (self.album_button.handler_is_connected (self.album_change_handler)):
271 self.album_button.disconnect (self.album_change_handler)
273 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
274 self.artist_button.disconnect (self.artist_change_handler)
276 # Set values in the picker buttons
278 self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
280 print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
281 self.artist_button.set_value ("")
282 except AttributeError:
283 print "WARNING: Use set_artist_alternatives method to set a list of artists"
286 self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
288 print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
289 self.album_button.set_value ("")
290 except AttributeError:
291 print "WARNING: Use set_album_alternatives method to set a list of artists"
293 # Reconnect the signals!
294 self.album_change_handler = self.album_button.connect ("value-changed",
295 self.album_selection_cb)
297 self.artist_change_handler = self.artist_button.connect ("value-changed",
298 self.artist_selection_cb)
300 # Set the album art given the current data
301 self.set_album_art (song[ALBUM_COLUMN])
303 if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
304 self.artist_button.set_sensitive (False)
305 self.album_button.set_sensitive (False)
306 self.title_entry.set_sensitive (False)
308 self.artist_button.set_sensitive (True)
309 self.album_button.set_sensitive (True)
310 self.title_entry.set_sensitive (True)
312 def set_album_art (self, album):
315 thumb = album_art_spec.getCoverArtThumbFileName (album)
316 print "%s -> %s" % (album, thumb)
317 if (os.path.exists (thumb)):
318 self.album_art.set_from_file (thumb)
322 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
325 def clicked_play (self, widget):
326 if (self.player.is_playing ()):
329 song = self.get_current_row ()
330 self.player.play ("file://" + song[URI_COLUMN])
332 def album_selection_cb (self, widget):
334 On album change, add the album the local list of albums and the selector
335 if it doesn't exist already. So we show the new entry in the selector next time.
337 song = self.get_current_row ()
338 if (not widget.get_value () in self.albums_list):
339 print "Inserting ", widget.get_value ()
340 widget.get_selector ().prepend_text (widget.get_value ())
341 self.albums_list.insert (0, widget.get_value ())
342 self.set_album_art (widget.get_value ())
344 def artist_selection_cb (self, widget):
346 On artist change, add the artist the local list of artists 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.artists_list):
351 print "Inserting artist", widget.get_value ()
352 widget.get_selector ().prepend_text (widget.get_value ())
353 self.artists_list.insert (0, widget.get_value ())
356 if __name__ == "__main__":
358 TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
359 "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
361 "artist %d album %d" % (i, i*100),
362 "text to be searched artist %d album %d" % (i, i*100)) for i in range (0, 4)]
364 model = gtk.ListStore (str, str, str, str, str, str, str, str)
369 window = MussorgskyEditPanel ()
370 window.set_artist_alternatives (["Artist %d" % i for i in range (0, 4)])
371 window.set_album_alternatives (["Album %d" % (i*100) for i in range (0, 4)])
372 window.set_model (model.filter_new ())
373 window.connect ("destroy", gtk.main_quit)