Remove commented code
[mussorgsky] / src / edit_panel_tm.py
1 #!/usr/bin/env python2.5
2 import hildon
3 import gtk, gobject
4 from mutagen_backend import MutagenBackend
5 from player_backend import MediaPlayer
6 from utils import escape_html
7 import album_art_spec
8 import os
9
10 # Fields in the tuple!
11 # Shared with browse_panel
12 URI_COLUMN = 0
13 ARTIST_COLUMN = 2
14 TITLE_COLUMN = 3
15 ALBUM_COLUMN = 4
16 MIME_COLUMN = 5
17 UI_COLUMN = 6
18 SEARCH_COLUMN = 7
19
20 THEME_PATH = "/usr/share/themes/default"
21
22 class MussorgskyEditPanel (hildon.StackableWindow):
23
24     def __init__ (self):
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 ()
31         self.__create_view ()
32         self.data_loaded = False
33         self.artist_list = None
34         self.albums_list = None
35         self.connect ("delete-event", self.close_function)
36
37     def close_function (self, widget, event):
38         if (not self.data_loaded):
39             return
40         
41         if self.__is_view_dirty ():
42             self.save_metadata ()
43
44         
45     def update_title (self):
46         self.set_title ("Edit (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
47                                           len (self.model)))
48
49     def get_current_row (self):
50         if (not self.current):
51             return 6 * (None,)
52         return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
53
54     def set_model (self, model, current=None):
55         assert type(model) == gtk.TreeModelFilter
56         try:
57             if self.artists_list or self.albums_list:
58                 pass
59         except AttributeError, e:
60             print "**** Set album and artist alternatives before setting a model"
61             raise e
62         
63         self.model = model
64         if (current):
65             self.current = current
66         else:
67             self.current = self.model.get_iter_first ()
68         self.data_loaded = True
69         self.set_data_in_view (self.get_current_row ())
70         self.update_title ()
71
72     def set_current (self, current):
73         """
74         Iterator to current element
75         """
76         self.current = current
77         self.set_data_in_view (self.get_current_row ())
78         self.update_title ()
79
80
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)
87
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)
94
95
96     def press_back_cb (self, widget):
97         if (self.player.is_playing ()):
98             self.player.stop ()
99
100         if self.__is_view_dirty ():
101             print "Modified data. Save!"
102             self.save_metadata ()
103             
104         path = self.model.get_path (self.current)
105         if (path[0] == 0):
106             self.destroy ()
107         else:
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 ())
111             self.update_title ()
112
113     def press_next_cb (self, widget):
114         if (self.player.is_playing ()):
115             self.player.stop ()
116
117         if self.__is_view_dirty ():
118             print "Modified data. Save!"
119             self.save_metadata ()
120
121         self.current = self.model.iter_next (self.current)
122         if (not self.current):
123             self.destroy ()
124         else:
125             self.set_data_in_view (self.get_current_row ())
126             self.update_title ()
127
128             
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.
132
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)
138
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 ()
145
146         m.set (c,
147                ARTIST_COLUMN, artist,
148                TITLE_COLUMN, title,
149                ALBUM_COLUMN, album,
150                UI_COLUMN, text,
151                SEARCH_COLUMN, search_str)
152         new_song = self.get_current_row ()
153         try:
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 ())
159         except IOError, e:
160             # This error in case of tracker returning unexistent files.
161             # Uhm.... for instance after removing a memory card we are editing!
162             pass
163         
164
165     def __is_view_dirty (self):
166         """
167         True if the data has been modified in the widgets
168         """
169         song = self.get_current_row ()
170
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] )
175         
176
177     def __create_view (self):
178         view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
179
180         filename_row = gtk.HBox ()
181         self.filename_data = gtk.Label ("")
182         filename_row.pack_start (self.filename_data, expand=True)
183
184         #filename_row.pack_start (play_button, expand=False, fill=False)
185         view_vbox.pack_start (filename_row, expand=False);
186
187         central_panel = gtk.HBox (spacing=12)
188
189         table = gtk.Table (3, 2, False)
190         table.set_col_spacings (12)
191         table.set_row_spacings (12)
192
193         central_panel.pack_start (table, fill=True)
194         view_vbox.pack_start (central_panel, expand=True, fill=True)
195
196         # Title row
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)
201
202         # Artist row
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)
208
209
210         # Album row
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)
216         
217
218         # Album art space
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)
222         
223         # Buttons row
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)
230         
231         separator = gtk.SeparatorToolItem ()
232         separator.set_expand (True)
233         button_box.insert  (separator, -1)
234
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)
240
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)
246
247         self.add_toolbar (button_box)
248         
249         self.add (view_vbox)
250
251
252     def set_data_in_view (self, song):
253         """
254         Place in the screen the song information.
255         Song is a tuple like (filename, 'Music', title, artist, album, mime)
256         """
257         assert len (song) == 6
258         
259         self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
260         self.title_entry.set_text (song[TITLE_COLUMN])
261         
262
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)
266             
267         if (self.artist_button.handler_is_connected (self.artist_change_handler)):
268             self.artist_button.disconnect (self.artist_change_handler)
269
270         # Set values in the picker buttons
271         try:
272             self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
273         except ValueError:
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"
278             
279         try:
280             self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
281         except ValueError:
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"
286
287         # Reconnect the signals!
288         self.album_change_handler = self.album_button.connect ("value-changed",
289                                                                self.album_selection_cb)
290
291         self.artist_change_handler = self.artist_button.connect ("value-changed",
292                                                                  self.artist_selection_cb)
293
294         # Set the album art given the current data
295         self.set_album_art (song[ALBUM_COLUMN])
296
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)
301         else:
302             self.artist_button.set_sensitive (True)
303             self.album_button.set_sensitive (True)
304             self.title_entry.set_sensitive (True)
305
306     def set_album_art (self, album):
307         has_album = False
308         if (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)
313                 has_album = True
314             
315         if (not has_album):
316             self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
317
318         
319     def clicked_play (self, widget):
320         if (self.player.is_playing ()):
321             self.player.stop ()
322         else:
323             song = self.get_current_row ()
324             self.player.play ("file://" + song[URI_COLUMN])
325
326     def album_selection_cb (self, widget):
327         """
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.
330         """
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 ())
337
338     def artist_selection_cb (self, widget):
339         """
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
342         """
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 ())
348
349 # Testing porpuses
350 if __name__ == "__main__":
351
352     TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
353                   "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
354                   "audio/mpeg",
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)]
357
358     model = gtk.ListStore (str, str, str, str, str, str, str, str)
359     for t in TEST_DATA:
360         print t
361         model.append (t)
362
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)
368     window.show_all ()
369     gtk.main ()