1
# -*- coding: utf-8 -*-
2
# Copyright 2004-2005 Joe Wreschnig, Michael Urman, Iñigo Serna
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License version 2 as
6
# published by the Free Software Foundation
8
# $Id: queue.py 3834 2006-09-10 21:01:20Z piman $
18
from qltk.ccb import ConfigCheckButton
19
from qltk.songlist import SongList
20
from qltk.songsmenu import SongsMenu
21
from qltk.x import Tooltips
23
QUEUE = os.path.join(const.USERDIR, "queue")
25
class QueueExpander(gtk.Expander):
26
def __init__(self, menu, library, player):
27
super(QueueExpander, self).__init__()
28
sw = gtk.ScrolledWindow()
29
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
30
sw.set_shadow_type(gtk.SHADOW_IN)
31
self.queue = PlayQueue(library, player)
33
hb = gtk.HBox(spacing=12)
35
hb2 = gtk.HBox(spacing=3)
36
state = gtk.image_new_from_stock(
37
gtk.STOCK_MEDIA_STOP, gtk.ICON_SIZE_MENU)
40
l = gtk.Label(_("_Queue"))
43
l.set_use_underline(True)
45
clear = gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
48
b.connect('clicked', self.__clear_queue)
50
b.set_relief(gtk.RELIEF_NONE)
51
hb.pack_start(b, expand=False, fill=False)
56
cb = ConfigCheckButton(
57
_("_Random"), "memory", "shufflequeue")
58
cb.connect('toggled', self.__queue_shuffle, self.queue.model)
59
cb.set_active(config.getboolean("memory", "shufflequeue"))
62
self.set_label_widget(hb)
64
self.connect_object('notify::expanded', self.__expand, cb, b)
66
targets = [("text/x-quodlibet-songs", gtk.TARGET_SAME_APP, 1)]
68
gtk.DEST_DEFAULT_ALL, targets, gtk.gdk.ACTION_COPY)
69
self.connect('drag-motion', self.__motion)
71
'drag-data-received', self.__drag_data_received, library)
73
self.model = self.queue.model
76
self.queue.model.connect_after('row-changed', self.__check_expand, l2)
77
self.queue.model.connect_after('row-deleted', self.__update_count, l2)
81
tips.set_tip(b, _("Remove all songs from the queue"))
82
self.connect_object('notify::visible', self.__visible, cb, menu, b)
83
self.__update_count(self.model, None, l2)
85
player.connect('song-started', self.__update_state_icon, state)
86
player.connect('paused', self.__update_state_icon_pause,
87
state, gtk.STOCK_MEDIA_PAUSE)
88
player.connect('unpaused', self.__update_state_icon_pause,
89
state, gtk.STOCK_MEDIA_PLAY)
91
def __update_state_icon(self, player, song, state):
92
if self.model.sourced: icon = gtk.STOCK_MEDIA_PLAY
93
else: icon = gtk.STOCK_MEDIA_STOP
94
state.set_from_stock(icon, gtk.ICON_SIZE_MENU)
96
def __update_state_icon_pause(self, player, state, icon):
97
if self.model.sourced:
98
state.set_from_stock(icon, gtk.ICON_SIZE_MENU)
100
def __clear_queue(self, activator):
103
def __motion(self, wid, context, x, y, time):
104
context.drag_status(gtk.gdk.ACTION_COPY, time)
107
def __update_count(self, model, path, lab):
108
if len(model) == 0: text = ""
110
time = sum([row[0].get("~#length", 0) for row in model])
111
text = ngettext("%(count)d song (%(time)s)",
112
"%(count)d songs (%(time)s)",
114
"count": len(model), "time": util.format_time(time) }
117
def __check_expand(self, model, path, iter, lab):
118
if not self.get_property('visible'):
119
self.set_expanded(False)
120
self.__update_count(model, path, lab)
123
def __drag_data_received(self, library, ctx, x, y, sel, info, etime):
124
filenames = sel.data.split("\x00")
125
songs = filter(None, map(library.librarian.get, filenames))
126
for song in songs: self.model.append(row=[song])
127
ctx.finish(bool(songs), False, etime)
129
def __queue_shuffle(self, button, model):
130
model.order = button.get_active()
132
def __expand(self, cb, prop, clear):
133
cb.set_property('visible', self.get_expanded())
134
clear.set_property('visible', self.get_expanded())
136
def __visible(self, cb, prop, menu, clear):
137
value = self.get_property('visible')
138
config.set("memory", "queue", str(value))
139
menu.set_active(value)
140
self.set_expanded(not self.model.is_empty())
141
cb.set_property('visible', self.get_expanded())
142
clear.set_property('visible', self.get_expanded())
144
class PlayQueue(SongList):
145
class CurrentColumn(gtk.TreeViewColumn):
146
# Match MainSongList column sizes by default.
147
header_name = "~current"
149
super(PlayQueue.CurrentColumn, self).__init__()
150
self.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
151
self.set_fixed_width(24)
153
def __init__(self, library, player):
154
super(PlayQueue, self).__init__(library, player)
155
self.set_size_request(-1, 120)
156
self.model = self.get_model()
157
self.connect('row-activated', self.__go_to, player)
159
self.connect_object('popup-menu', self.__popup, library)
161
self.connect_object('destroy', self.__write, self.model)
164
self.connect('key-press-event', self.__delete_key_pressed)
166
def __delete_key_pressed(self, widget, event):
167
if (event.keyval, event.state) == gtk.accelerator_parse("Delete"):
172
def __go_to(self, view, path, column, player):
173
self.model.go_to(self.model.get_iter(path))
176
def __fill(self, library):
177
try: filenames = file(QUEUE, "rU").readlines()
178
except EnvironmentError: pass
180
filenames = map(str.strip, filenames)
181
songs = filter(None, map(library.librarian.get, filenames))
183
self.model.append([song])
185
def __write(self, model):
186
filenames = "\n".join([row[0]["~filename"] for row in model])
191
def __popup(self, library):
192
songs = self.get_selected_songs()
196
library, songs, queue=False, remove=False, delete=False)
198
remove = gtk.ImageMenuItem(gtk.STOCK_REMOVE)
199
remove.connect('activate', self.__remove)
202
return self.popup_menu(menu, 0, gtk.get_current_event_time())
204
def __remove(self, item):
205
model, paths = self.get_selection().get_selected_rows()
206
if model: map(self.model.remove, map(model.get_iter, paths))
208
def set_sort_by(self, *args): pass
209
def get_sort_by(self, *args): return "", False