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"
23 _ = i18n.language.gettext
25 class MussorgskyEditPanel (hildon.StackableWindow):
28 hildon.StackableWindow.__init__ (self)
29 self.set_border_width (12)
30 self.album_change_handler = -1
31 self.artist_change_handler = -1
32 self.writer = MutagenBackend ()
33 self.player = MediaPlayer ()
35 self.data_loaded = False
36 self.artist_list = None
37 self.albums_list = None
39 self.connect ("delete-event", self.close_function)
41 def close_function (self, widget, event):
42 if (not self.data_loaded):
45 if self.__is_view_dirty ():
49 def update_title (self):
50 self.set_title (_("Edit song") + " (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
53 def get_current_row (self):
54 if (not self.current):
56 return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
58 def set_model (self, model, current=None):
59 assert type(model) == gtk.TreeModelFilter
61 if self.artists_list or self.albums_list:
63 except AttributeError, e:
64 print "**** Set album and artist alternatives before setting a model"
69 self.current = current
71 self.current = self.model.get_iter_first ()
72 self.data_loaded = True
73 self.set_data_in_view (self.get_current_row ())
76 def set_current (self, current):
78 Iterator to current element
80 self.current = current
81 self.set_data_in_view (self.get_current_row ())
85 def set_artist_alternatives (self, alternatives):
86 self.artists_list = alternatives
87 artist_selector = hildon.TouchSelectorEntry (text=True)
88 for a in self.artists_list:
89 artist_selector.append_text (a)
90 self.artist_button.set_selector (artist_selector)
92 def set_album_alternatives (self, alternatives):
93 self.albums_list = alternatives
94 album_selector = hildon.TouchSelectorEntry (text=True)
95 for a in self.albums_list:
96 album_selector.append_text (a)
97 self.album_button.set_selector (album_selector)
100 def press_back_cb (self, widget):
101 if (self.player.is_playing ()):
104 if self.__is_view_dirty ():
105 print "Modified data. Save!"
106 self.save_metadata ()
108 path = self.model.get_path (self.current)
112 new_path = ( path[0] -1, )
113 self.current = self.model.get_iter (new_path)
114 self.set_data_in_view (self.get_current_row ())
117 def press_next_cb (self, widget):
118 if (self.player.is_playing ()):
121 if self.__is_view_dirty ():
122 print "Modified data. Save!"
123 self.save_metadata ()
125 self.current = self.model.iter_next (self.current)
126 if (not self.current):
129 self.set_data_in_view (self.get_current_row ())
133 def save_metadata (self):
134 # Save the data in the online model to show the appropiate data
135 # in the UI while tracker process the update.
137 # 0 - filename -> doesn't change
138 # 1 - "Music" -> doesn't change
139 # 5 - mimetype -> doesn't change
140 m = self.model.get_model ()
141 c = self.model.convert_iter_to_child_iter (self.current)
143 artist = self.artist_button.get_value ()
144 title = self.title_entry.get_text ()
145 album = self.album_button.get_value ()
146 text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
147 escape_html (artist) + " / " + escape_html (album))
148 search_str = artist.lower () + " " + title.lower () + " " + album.lower ()
150 uri, mime = m.get (c, URI_COLUMN, MIME_COLUMN)
152 ARTIST_COLUMN, artist,
156 SEARCH_COLUMN, search_str)
158 self.writer.save_metadata_on_file (uri,
160 self.artist_button.get_value (),
161 self.title_entry.get_text (),
162 self.album_button.get_value ())
164 # This error in case of tracker returning unexistent files.
165 # Uhm.... for instance after removing a memory card we are editing!
169 def __is_view_dirty (self):
171 True if the data has been modified in the widgets
173 song = self.get_current_row ()
175 return not (self.filename_data.get_text() == song[URI_COLUMN] and
176 self.artist_button.get_value () == song[ARTIST_COLUMN] and
177 self.title_entry.get_text () == song[TITLE_COLUMN] and
178 self.album_button.get_value () == song[ALBUM_COLUMN] )
181 def __create_view (self):
182 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
184 filename_row = gtk.HBox ()
185 self.filename_data = gtk.Label ("")
186 filename_row.pack_start (self.filename_data, expand=True)
188 #filename_row.pack_start (play_button, expand=False, fill=False)
189 view_vbox.pack_start (filename_row, expand=False);
191 central_panel = gtk.HBox (spacing=12)
193 table = gtk.Table (3, 2, False)
194 table.set_col_spacings (12)
195 table.set_row_spacings (12)
197 central_panel.pack_start (table, fill=True)
198 view_vbox.pack_start (central_panel, expand=True, fill=True)
201 label_title = gtk.Label (_("Title:"))
202 table.attach (label_title, 0, 1, 0, 1, 0)
203 self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
204 table.attach (self.title_entry, 1, 2, 0, 1)
207 self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
208 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
209 self.artist_button.set_title (_("Artist:"))
210 # Set data will set the selector
211 table.attach (self.artist_button, 0, 2, 1, 2)
215 self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
216 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
217 self.album_button.set_title (_("Album:"))
218 # set_data will set the selector
219 table.attach (self.album_button, 0, 2, 2, 3)
223 self.album_art = gtk.Image ()
224 self.album_art.set_size_request (124, 124)
225 central_panel.pack_start (self.album_art, expand=False, fill=False)
228 button_box = gtk.Toolbar ()
229 play_image = os.path.join (THEME_PATH, "mediaplayer", "Play.png")
230 play_button = gtk.ToolButton (gtk.image_new_from_file (play_image))
231 play_button.connect ("clicked", self.clicked_play)
232 play_button.set_expand (True)
233 button_box.insert (play_button, -1)
235 separator = gtk.SeparatorToolItem ()
236 separator.set_expand (True)
237 button_box.insert (separator, -1)
239 back_image = os.path.join (THEME_PATH, "mediaplayer", "Back.png")
240 back_button = gtk.ToolButton (gtk.image_new_from_file (back_image))
241 back_button.connect ("clicked", self.press_back_cb)
242 back_button.set_expand (True)
243 button_box.insert (back_button, -1)
245 next_image = os.path.join (THEME_PATH, "mediaplayer", "Forward.png")
246 next_button = gtk.ToolButton (gtk.image_new_from_file (next_image))
247 next_button.connect ("clicked", self.press_next_cb)
248 next_button.set_expand (True)
249 button_box.insert (next_button, -1)
251 self.add_toolbar (button_box)
256 def set_data_in_view (self, song):
258 Place in the screen the song information.
259 Song is a tuple like (filename, 'Music', title, artist, album, mime)
261 assert len (song) == 6
263 self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
264 self.title_entry.set_text (song[TITLE_COLUMN])
267 # Disconnect the value-change signal to avoid extra album art retrievals
268 if (self.album_button.handler_is_connected (self.album_change_handler)):
269 self.album_button.disconnect (self.album_change_handler)
271 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
272 self.artist_button.disconnect (self.artist_change_handler)
274 # Set values in the picker buttons
276 self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
278 print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
279 self.artist_button.set_value ("")
280 except AttributeError:
281 print "WARNING: Use set_artist_alternatives method to set a list of artists"
284 self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
286 print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
287 self.album_button.set_value ("")
288 except AttributeError:
289 print "WARNING: Use set_album_alternatives method to set a list of artists"
291 # Reconnect the signals!
292 self.album_change_handler = self.album_button.connect ("value-changed",
293 self.album_selection_cb)
295 self.artist_change_handler = self.artist_button.connect ("value-changed",
296 self.artist_selection_cb)
298 # Set the album art given the current data
299 self.set_album_art (song[ALBUM_COLUMN])
301 if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
302 self.artist_button.set_sensitive (False)
303 self.album_button.set_sensitive (False)
304 self.title_entry.set_sensitive (False)
306 self.artist_button.set_sensitive (True)
307 self.album_button.set_sensitive (True)
308 self.title_entry.set_sensitive (True)
310 def set_album_art (self, album):
313 thumb = album_art_spec.getCoverArtThumbFileName (album)
314 print "%s -> %s" % (album, thumb)
315 if (os.path.exists (thumb)):
316 self.album_art.set_from_file (thumb)
320 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
323 def clicked_play (self, widget):
324 if (self.player.is_playing ()):
327 song = self.get_current_row ()
328 self.player.play ("file://" + song[URI_COLUMN])
330 def album_selection_cb (self, widget):
332 On album change, add the album the local list of albums and the selector
333 if it doesn't exist already. So we show the new entry in the selector next time.
335 song = self.get_current_row ()
336 if (not widget.get_value () in self.albums_list):
337 print "Inserting ", widget.get_value ()
338 widget.get_selector ().prepend_text (widget.get_value ())
339 self.albums_list.insert (0, widget.get_value ())
340 self.set_album_art (widget.get_value ())
342 def artist_selection_cb (self, widget):
344 On artist change, add the artist the local list of artists and the selector
345 if it doesn't exist already. So we show the new entry in the selector next time
347 song = self.get_current_row ()
348 if (not widget.get_value () in self.artists_list):
349 print "Inserting artist", widget.get_value ()
350 widget.get_selector ().prepend_text (widget.get_value ())
351 self.artists_list.insert (0, widget.get_value ())
354 if __name__ == "__main__":
356 TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
357 "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
359 "artist %d album %d" % (i, i*100),
360 "text to be searched artist %d album %d" % (i, i*100)) for i in range (0, 4)]
362 model = gtk.ListStore (str, str, str, str, str, str, str, str)
367 window = MussorgskyEditPanel ()
368 window.set_artist_alternatives (["Artist %d" % i for i in range (0, 4)])
369 window.set_album_alternatives (["Album %d" % (i*100) for i in range (0, 4)])
370 window.set_model (model.filter_new ())
371 window.connect ("destroy", gtk.main_quit)