Vesion 019
[rox-musicbox.git] / playlistui.py
blobbfb93be2cb8e2769a689dc5a83e440c0ac9c71d4
1 """
2 playlistui.py
3 Playlist UI for MusicBox application.
5 Copyright 2004 Kenneth Hayber <khayber@socal.rr.com>
6 All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License.
12 This program is distributed in the hope that it will be useful
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 """
22 from __future__ import generators
24 import gtk, gobject, os, sys, re
26 import rox
27 from rox import Menu, saving, loading, mime
29 import playlist
30 from playlist import COL_FILE, COL_TITLE, COL_TRACK, COL_ALBUM, COL_ARTIST, COL_GENRE, COL_LENGTH, COL_TYPE
33 #Who am I and how did I get here?
34 APP_NAME = "MusicBox"
35 APP_DIR = rox.app_dir
37 #View options
38 VIEW_DEFAULT_SIZE = (760, 400)
41 COLUMNS = [
42 # (_("Filename"), COL_FILE, str, 100),
43 (_("Artist"), COL_ARTIST, str, 200),
44 (_("Album"), COL_ALBUM, str, 200),
45 (_("Title"), COL_TITLE, str, 200),
46 (_("Track"), COL_TRACK, int, 50),
47 (_("Genre"), COL_GENRE, str, 80),
48 # (_("Length"), COL_LENGTH, int, 60),
49 # (_("Type"), COL_TYPE, str, 60),
52 DND_TYPES = ['audio/x-mp3' 'application/ogg' 'inode/directory']
54 class PlaylistUI(rox.Window, loading.XDSLoader):
55 """the playlist UI for MusicBox"""
57 def __init__(self, the_playlist, musicbox):
58 """Constructor"""
59 rox.Window.__init__(self)
60 loading.XDSLoader.__init__(self, DND_TYPES)
62 self.playlist = the_playlist #this is a reference to the main playlist
63 self.library = []
64 self.replace_library = True
65 self.musicbox = musicbox
67 self.set_title(APP_NAME+' - '+_("Playlist"))
68 self.set_role("PlayList")
69 self.set_border_width(0)
70 self.set_default_size(VIEW_DEFAULT_SIZE[0], VIEW_DEFAULT_SIZE[1])
71 self.set_position(gtk.WIN_POS_NONE)
73 #capture wm delete event
74 self.connect('delete_event', self.delete_event)
76 # Menu
77 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
78 self.connect('button-press-event', self.button_press)
80 Menu.set_save_name(APP_NAME)
81 self.menu = Menu.Menu('main', [
82 # Menu.SubMenu(_('Filter'), [
83 # Menu.Action(_("All songs"), 'filter_none', ''),
84 # Menu.Action(_("This Artist"), 'filter_artist', ''),
85 # Menu.Action(_("This Album"), 'filter_album', ''),
86 # Menu.Action(_("This Genre"), 'filter_genre', ''),
87 # Menu.Action(_("New Filter..."), 'filter_new', '')
88 # ]),
89 # Menu.Separator(),
90 Menu.Action(_("Save"), 'save', '', gtk.STOCK_SAVE),
91 Menu.Separator(),
92 Menu.Action(_("Close"), 'close', '', gtk.STOCK_CLOSE),
94 self.menu.attach(self,self)
96 # Playlist
97 swin = gtk.ScrolledWindow()
98 self.scroll_window = swin
100 swin.set_border_width(0)
101 swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
103 # view = gtk.TreeView(self.playlist.song_list.filter_new())
104 view = gtk.TreeView(self.playlist.song_list)
105 self.view = view
106 swin.add(view)
107 view.set_rules_hint(True)
108 self.view.set_reorderable(True)
109 self.view.set_search_column(COL_TITLE)
111 #enable for drag from playlist to other apps (doesn't work yet)
112 # self.view.drag_source_set(gtk.gdk.BUTTON_PRESS_MASK, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY)
113 # self.view.connect('drag_data_get', self.drag_data_get)
115 self.view.add_events(gtk.gdk.BUTTON_PRESS_MASK)
116 self.view.connect('button-press-event', self.button_press)
118 #TODO: A little icon showing the current song playing...
119 #cell = gtk.CellRendererPixbuf()
120 #column = gtk.TreeViewColumn('', cell)
121 #view.append_column(column)
122 #column.set_resizable(False)
123 #column.set_reorderable(False)
125 for n in range(len(COLUMNS)):
126 cell = gtk.CellRendererText()
127 column = gtk.TreeViewColumn(COLUMNS[n][0], cell, text = COLUMNS[n][1])
128 view.append_column(column)
129 column.set_sort_column_id(COLUMNS[n][1])
130 column.set_resizable(True)
131 column.set_reorderable(True)
132 column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
133 column.set_fixed_width(COLUMNS[n][3])
134 column.connect('clicked', self.col_activate)
136 view.connect('row-activated', self.activate)
137 self.selection = view.get_selection()
138 self.handler = self.selection.connect('changed', self.set_selection)
139 self.view.set_search_column(COL_ARTIST)
141 #TODO: Multiple Selections
142 #self.selection.set_mode(gtk.SELECTION_MULTIPLE)
144 # Create layout, pack and show widgets
145 self.vbox = gtk.VBox()
146 self.add(self.vbox)
147 self.vbox.pack_start(self.scroll_window, True, True, 0)
148 self.vbox.show_all()
150 self.show()
151 self.sync()
153 def drag_data_get(self, widget, context, selection, targetType, eventTime):
154 print >>sys.stderr, selection.target, selection.format, selection.data
155 if selection.target == 'text/uri-list':
156 selection.set(selection.target, 8, 'test.fil\n')
158 def load(self):
159 """Load the playlist either from a saved xml file, or from source dirs"""
160 try:
161 if self.replace_library:
162 self.musicbox.load_songs(self.library)
163 else:
164 self.musicbox.add_songs(self.library)
165 except:
166 rox.report_exception()
168 def save(self):
169 """Save the current list"""
170 box = saving.SaveBox(self.playlist, rox.choices.save(APP_NAME, 'Library.xml'), 'text/xml')
171 box.show()
173 def sync(self):
174 """Scroll the playlistUI to the currently selected song"""
175 try:
176 index = self.playlist.get_index()
177 self.view.set_cursor((index,))
178 self.view.scroll_to_cell((index,))
179 except:
180 pass
182 def play(self):
183 """Play the current song"""
184 try:
185 self.musicbox.play()
186 except:
187 rox.report_exception()
189 def activate(self, view, path, column):
190 """Double-click handler, plays the song"""
191 self.playlist.set(path[0])
192 self.play()
194 def set_selection(self, selection):
195 """Tell the playlist what we currently have selected"""
196 #print selection
197 pass
199 def delete_event(self, ev, e1):
200 """Same as close, but called from the window manager"""
201 self.close()
203 def close(self, button = None):
204 """Destroy ourselves and all our children"""
205 self.destroy()
207 def button_press(self, text, event):
208 """Popup menu handler"""
209 if event.button != 3:
210 return 0
211 self.menu.popup(self, event)
212 return 1
214 def col_activate(self, column):
215 """Set the selected column as the search <Ctrl-S> column"""
216 self.view.set_search_column(column.get_sort_column_id())
218 def xds_drag_drop(self, widget, context, data, info, time):
219 """Check if the Shift key is pressed or not when Dropping files"""
220 if context.actions & gtk.gdk.ACTION_COPY:
221 self.replace_library = False
222 else:
223 self.replace_library = True
224 return loading.XDSLoader.xds_drag_drop(self, widget, context, data, info, time)
226 def xds_load_uris(self, uris):
227 """Accept files and folders dropped on us as new Library"""
228 path = []
229 #strip off the 'file://' part and concatenate them
230 for s in uris:
231 path.append(rox.get_local_path(s))
232 self.library = path
233 self.load()