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!
165 def __is_view_dirty (self):
167 True if the data has been modified in the widgets
169 song = self.get_current_row ()
171 return not (self.filename_data.get_text() == song[URI_COLUMN] and
172 self.artist_button.get_value () == song[ARTIST_COLUMN] and
173 self.title_entry.get_text () == song[TITLE_COLUMN] and
174 self.album_button.get_value () == song[ALBUM_COLUMN] )
177 def __create_view (self):
178 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
180 filename_row = gtk.HBox ()
181 self.filename_data = gtk.Label ("")
182 filename_row.pack_start (self.filename_data, expand=True)
184 #filename_row.pack_start (play_button, expand=False, fill=False)
185 view_vbox.pack_start (filename_row, expand=False);
187 central_panel = gtk.HBox (spacing=12)
189 table = gtk.Table (3, 2, False)
190 table.set_col_spacings (12)
191 table.set_row_spacings (12)
193 central_panel.pack_start (table, fill=True)
194 view_vbox.pack_start (central_panel, expand=True, fill=True)
197 label_title = gtk.Label ("Title:")
198 table.attach (label_title, 0, 1, 0, 1, 0)
199 self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
200 table.attach (self.title_entry, 1, 2, 0, 1)
203 self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
204 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
205 self.artist_button.set_title ("Artist: ")
206 # Set data will set the selector
207 table.attach (self.artist_button, 0, 2, 1, 2)
211 self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
212 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
213 self.album_button.set_title ("Album: ")
214 # set_data will set the selector
215 table.attach (self.album_button, 0, 2, 2, 3)
219 self.album_art = gtk.Image ()
220 self.album_art.set_size_request (124, 124)
221 central_panel.pack_start (self.album_art, expand=False, fill=False)
224 button_box = gtk.Toolbar ()
225 play_image = os.path.join (THEME_PATH, "mediaplayer", "Play.png")
226 play_button = gtk.ToolButton (gtk.image_new_from_file (play_image))
227 play_button.connect ("clicked", self.clicked_play)
228 play_button.set_expand (True)
229 button_box.insert (play_button, -1)
231 separator = gtk.SeparatorToolItem ()
232 separator.set_expand (True)
233 button_box.insert (separator, -1)
235 back_image = os.path.join (THEME_PATH, "mediaplayer", "Back.png")
236 back_button = gtk.ToolButton (gtk.image_new_from_file (back_image))
237 back_button.connect ("clicked", self.press_back_cb)
238 back_button.set_expand (True)
239 button_box.insert (back_button, -1)
241 next_image = os.path.join (THEME_PATH, "mediaplayer", "Forward.png")
242 next_button = gtk.ToolButton (gtk.image_new_from_file (next_image))
243 next_button.connect ("clicked", self.press_next_cb)
244 next_button.set_expand (True)
245 button_box.insert (next_button, -1)
247 self.add_toolbar (button_box)
252 def set_data_in_view (self, song):
254 Place in the screen the song information.
255 Song is a tuple like (filename, 'Music', title, artist, album, mime)
257 assert len (song) == 6
259 self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
260 self.title_entry.set_text (song[TITLE_COLUMN])
263 # Disconnect the value-change signal to avoid extra album art retrievals
264 if (self.album_button.handler_is_connected (self.album_change_handler)):
265 self.album_button.disconnect (self.album_change_handler)
267 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
268 self.artist_button.disconnect (self.artist_change_handler)
270 # Set values in the picker buttons
272 self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
274 print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
275 self.artist_button.set_value ("")
276 except AttributeError:
277 print "WARNING: Use set_artist_alternatives method to set a list of artists"
280 self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
282 print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
283 self.album_button.set_value ("")
284 except AttributeError:
285 print "WARNING: Use set_album_alternatives method to set a list of artists"
287 # Reconnect the signals!
288 self.album_change_handler = self.album_button.connect ("value-changed",
289 self.album_selection_cb)
291 self.artist_change_handler = self.artist_button.connect ("value-changed",
292 self.artist_selection_cb)
294 # Set the album art given the current data
295 self.set_album_art (song[ALBUM_COLUMN])
297 if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
298 self.artist_button.set_sensitive (False)
299 self.album_button.set_sensitive (False)
300 self.title_entry.set_sensitive (False)
302 self.artist_button.set_sensitive (True)
303 self.album_button.set_sensitive (True)
304 self.title_entry.set_sensitive (True)
306 def set_album_art (self, album):
309 thumb = album_art_spec.getCoverArtThumbFileName (album)
310 print "%s -> %s" % (album, thumb)
311 if (os.path.exists (thumb)):
312 self.album_art.set_from_file (thumb)
316 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
319 def clicked_play (self, widget):
320 if (self.player.is_playing ()):
323 song = self.get_current_row ()
324 self.player.play ("file://" + song[URI_COLUMN])
326 def album_selection_cb (self, widget):
328 On album change, add the album the local list of albums and the selector
329 if it doesn't exist already. So we show the new entry in the selector next time.
331 song = self.get_current_row ()
332 if (not widget.get_value () in self.albums_list):
333 print "Inserting ", widget.get_value ()
334 widget.get_selector ().prepend_text (widget.get_value ())
335 self.albums_list.insert (0, widget.get_value ())
336 self.set_album_art (widget.get_value ())
338 def artist_selection_cb (self, widget):
340 On artist change, add the artist the local list of artists and the selector
341 if it doesn't exist already. So we show the new entry in the selector next time
343 song = self.get_current_row ()
344 if (not widget.get_value () in self.artists_list):
345 print "Inserting artist", widget.get_value ()
346 widget.get_selector ().prepend_text (widget.get_value ())
347 self.artists_list.insert (0, widget.get_value ())
350 if __name__ == "__main__":
352 TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
353 "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
355 "artist %d album %d" % (i, i*100),
356 "text to be searched artist %d album %d" % (i, i*100)) for i in range (0, 4)]
358 model = gtk.ListStore (str, str, str, str, str, str, str, str)
363 window = MussorgskyEditPanel ()
364 window.set_artist_alternatives (["Artist %d" % i for i in range (0, 4)])
365 window.set_album_alternatives (["Album %d" % (i*100) for i in range (0, 4)])
366 window.set_model (model.filter_new ())
367 window.connect ("destroy", gtk.main_quit)