1 #!/usr/bin/env python2.5
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
16 class MussorgskyEditPanel (hildon.StackableWindow):
19 hildon.StackableWindow.__init__ (self)
20 self.set_border_width (12)
21 self.album_callback_id = -1
22 self.album_change_handler = -1
23 self.artist_change_handler = -1
24 self.writer = MutagenBackend ()
25 self.player = MediaPlayer ()
27 self.data_loaded = False
29 def update_title (self):
30 self.set_title ("Edit (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
33 def get_current_row (self):
34 if (not self.current):
36 return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
38 def set_model (self, model, current=None):
41 self.current = current
43 self.current = self.model.get_iter_first ()
45 self.set_data_in_view (self.get_current_row ())
48 def set_artist_alternatives (self, alternatives):
49 self.artists_list = alternatives
50 artist_selector = hildon.TouchSelectorEntry (text=True)
51 for a in self.artists_list:
52 artist_selector.append_text (a)
53 self.artist_button.set_selector (artist_selector)
55 def set_album_alternatives (self, alternatives):
56 self.albums_list = alternatives
57 album_selector = hildon.TouchSelectorEntry (text=True)
58 for a in self.albums_list:
59 album_selector.append_text (a)
60 self.album_button.set_selector (album_selector)
63 def press_back_cb (self, widget):
64 if (self.player.is_playing ()):
67 if (self.album_callback_id != -1):
68 gobject.source_remove (self.album_callback_id)
69 self.album_callback_id = -1
71 if self.__is_view_dirty ():
72 print "Modified data. Save!"
75 self.current = self.model.iter_next (self.current)
76 if (not self.current):
79 self.set_data_in_view (self.get_current_row ())
81 def press_next_cb (self, widget):
82 if (self.player.is_playing ()):
85 if (self.album_callback_id != -1):
86 gobject.source_remove (self.album_callback_id)
87 self.album_callback_id = -1
89 if self.__is_view_dirty ():
90 print "Modified data. Save!"
93 self.current = self.model.iter_next (self.current)
94 if (not self.current):
98 self.set_data_in_view (self.get_current_row ())
101 def save_metadata (self):
102 # Save the data in the online model to show the appropiate data
103 # in the UI while tracker process the update.
105 # 0 - filename -> doesn't change
106 # 1 - "Music" -> doesn't change
107 # 5 - mimetype -> doesn't change
108 if (type (self.model) == gtk.TreeModelFilter):
109 m = self.model.get_model ()
113 2, self.artist_button.get_value (),
114 3, self.title_entry.get_text (),
115 4, self.album_button.get_value ())
116 new_song = self.get_current_row ()
118 self.writer.save_metadata_on_file (new_song[FILE_URI],
120 self.artist_button.get_value (),
121 self.title_entry.get_text (),
122 self.album_button.get_value ())
124 # This error in case of tracker returning unexistent files.
125 # Uhm.... for instance after removing a memory card we are editing!
126 dialog = gtk.MessageDialog (self,
127 gtk.DIALOG_DESTROY_WITH_PARENT,
135 def __is_view_dirty (self):
137 True if the data has been modified in the widgets
139 song = self.get_current_row ()
141 return not (self.filename_data.get_text() == song[FILE_URI] and
142 self.artist_button.get_value () == song[ARTIST_KEY] and
143 self.title_entry.get_text () == song[TITLE_KEY] and
144 self.album_button.get_value () == song[ALBUM_KEY] )
147 def __create_view (self):
148 view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
150 filename_row = gtk.HBox ()
151 filename_label = gtk.Label ("Filename:")
152 filename_row.pack_start (filename_label, expand=False, padding=12);
153 self.filename_data = gtk.Label ("")
154 filename_row.pack_start (self.filename_data, expand=True)
156 play_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
157 img = gtk.image_new_from_stock (gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON)
158 play_button.set_image (img)
159 play_button.connect ("clicked", self.clicked_play)
160 filename_row.pack_start (play_button, expand=False, fill=False)
161 view_vbox.pack_start (filename_row, expand=False);
163 central_panel = gtk.HBox (spacing=12)
165 table = gtk.Table (3, 2, False)
166 table.set_col_spacings (12)
167 table.set_row_spacings (12)
169 central_panel.pack_start (table, fill=True)
170 view_vbox.pack_start (central_panel, expand=True, fill=True)
173 label_title = gtk.Label ("Title:")
174 table.attach (label_title, 0, 1, 0, 1, 0)
175 self.title_entry = gtk.Entry()
176 table.attach (self.title_entry, 1, 2, 0, 1)
179 self.artist_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
180 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
181 self.artist_button.set_title ("Artist: ")
182 # Set data will set the selector
183 table.attach (self.artist_button, 0, 2, 1, 2)
187 self.album_button = hildon.PickerButton (hildon.BUTTON_STYLE_NORMAL,
188 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
189 self.album_button.set_title ("Album: ")
190 # set_data will set the selector
191 table.attach (self.album_button, 0, 2, 2, 3)
195 self.album_art = gtk.Image ()
196 self.album_art.set_size_request (124, 124)
197 central_panel.pack_start (self.album_art, expand=False, fill=False)
200 button_box = gtk.HButtonBox ()
201 button_box.set_layout (gtk.BUTTONBOX_END)
203 back_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
204 img = gtk.image_new_from_stock (gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
205 back_button.set_image (img)
206 back_button.connect ("clicked", self.press_back_cb)
207 button_box.pack_start (back_button, expand=True, fill=True, padding=6)
209 next_button = hildon.Button (hildon.BUTTON_STYLE_NORMAL, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
210 img = gtk.image_new_from_stock (gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
211 next_button.set_image (img)
212 next_button.connect ("clicked", self.press_next_cb)
213 button_box.pack_start (next_button, expand=True, fill=True, padding=6)
215 view_vbox.pack_start (button_box, expand=False, fill=True, padding=6)
220 def go_to_cb (self, widget):
223 def set_data_in_view (self, song):
225 Place in the screen the song information.
226 Song is a tuple like (filename, 'Music', title, artist, album, mime)
228 assert len (song) == 6
230 self.filename_data.set_text (song[FILE_URI])
231 self.title_entry.set_text (song[TITLE_KEY])
234 # Disconnect the value-change signal to avoid extra album art retrievals
235 if (self.album_button.handler_is_connected (self.album_change_handler)):
236 self.album_button.disconnect (self.album_change_handler)
238 if (self.artist_button.handler_is_connected (self.artist_change_handler)):
239 self.artist_button.disconnect (self.artist_change_handler)
241 # Set values in the picker buttons
243 self.artist_button.set_active (self.artists_list.index(song[ARTIST_KEY]))
245 print "'%s' not in artist list!?" % (song[ARTIST_KEY])
246 self.artist_button.set_value ("")
249 self.album_button.set_active (self.albums_list.index (song[ALBUM_KEY]))
251 print "'%s' is not in the album list!?" % (song[ALBUM_KEY])
252 self.album_button.set_value ("")
254 # Reconnect the signals!
255 self.album_change_handler = self.album_button.connect ("value-changed",
256 self.album_selection_cb)
258 self.artist_change_handler = self.artist_button.connect ("value-changed",
259 self.artist_selection_cb)
261 # Set the album art given the current data
262 self.set_album_art (song[ALBUM_KEY])
264 if (not song[MIME_KEY] in self.writer.get_supported_mimes ()):
265 self.artist_button.set_sensitive (False)
266 self.album_button.set_sensitive (False)
267 self.title_entry.set_sensitive (False)
269 self.artist_button.set_sensitive (True)
270 self.album_button.set_sensitive (True)
271 self.title_entry.set_sensitive (True)
273 def set_album_art (self, album):
276 thumb = album_art_spec.getCoverArtThumbFileName (album)
277 print "%s -> %s" % (album, thumb)
278 if (os.path.exists (thumb)):
279 self.album_art.set_from_file (thumb)
283 self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
286 def clicked_play (self, widget):
287 if (self.player.is_playing ()):
290 song = self.songs_list [self.song_counter]
291 self.player.play ("file://" + song[FILE_URI])
293 def clicked_album_art (self, widget):
294 print "implement me, please"
296 def album_selection_cb (self, widget):
298 On album change, add the album the local list of albums and the selector
299 if it doesn't exist already. So we show the new entry in the selector next time.
301 song = self.get_current_row ()
302 if (not widget.get_value () in self.albums_list):
303 print "Inserting ", widget.get_value ()
304 widget.get_selector ().prepend_text (widget.get_value ())
305 self.albums_list.insert (0, widget.get_value ())
306 self.set_album_art (widget.get_value ())
308 def artist_selection_cb (self, widget):
310 On artist change, add the artist the local list of artists and the selector
311 if it doesn't exist already. So we show the new entry in the selector next time
313 song = self.get_current_row ()
314 if (not widget.get_value () in self.artists_list):
315 print "Inserting artist", widget.get_value ()
316 widget.get_selector ().prepend_text (widget.get_value ())
317 self.artists_list.insert (0, widget.get_value ())
320 if __name__ == "__main__":
322 TEST_DATA = [("/home/user/Music/dylan.mp3", "Music", "Bob Dylan", "Subterranean homesick blues", "Bring it all back home", "audio/mpeg"),
323 ("/home/user/mufix/a.mp3", "Music", "", "title", "Album 2", "a/b"),
324 ("/media/mmc1/Attachments/b.m4a", "Music", "", "b", "Album 9", "audio/mpeg"),
325 ("/home/user/mufix/3.mp2", "Music", "", "titlex", "Album 3", "audio/mpeg")]
327 model = gtk.ListStore (str, str, str, str, str, str)
331 window = MussorgskyEditPanel ()
332 window.set_model (model)
333 window.connect ("destroy", gtk.main_quit)