Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gtk, gobject, pango
import sys
from functions import *
class Playlist(gobject.GObject):
COLUMN_MAP = { "ID" : 1, "Title" : 2, "Artist" : 3, "Album" : 4, "Duration" : 5, "Bitrate" : 6 }
__gproperties__ = {
"initital-playlist-complete" : (gobject.TYPE_BOOLEAN,
"population of playlist is complete",
"when this is True, the Playlist has been downloaded from the server",
False,
gobject.PARAM_READWRITE),
"items-count" : (gobject.TYPE_INT,
"number of playlist items",
"for checking whether the initial population is complete and for showing how many items are in playlist",
-1,
sys.maxint,
0,
gobject.PARAM_READWRITE),
"ids" : (gobject.TYPE_PYOBJECT,
"list of playlist ids",
"this list is downloaded from the server when the playlist is first initialized",
gobject.PARAM_READWRITE),
"current-pos" : (gobject.TYPE_INT,
"the current position in the playlist",
"which playlist item is playing?",
-1,
sys.maxint,
0,
gobject.PARAM_READWRITE),
"marked" : (gobject.TYPE_INT,
"the current marked entry",
"the items that is currently highlighted (should be the currently playing one)",
-1,
sys.maxint,
-1,
gobject.PARAM_READWRITE),
"column-dict" : (gobject.TYPE_PYOBJECT,
"list of columns to show",
"defines which columns are shown on the treeview and their initial size",
gobject.PARAM_READWRITE),
"change" : (gobject.TYPE_PYOBJECT,
"a change to the playlist",
"this gets updated whenever the server notifies me of a change to the playlist",
gobject.PARAM_READWRITE),
"plfilter" : (gobject.TYPE_STRING,
"the current filter",
"this gets updated whenever the user types something into the Filter: TextBox",
"",
gobject.PARAM_READWRITE)
}
def do_get_property(self, property):
if property.name == "initital-playlist-complete":
return self.initital_playlist_complete
elif property.name == "items-count":
return self.items_count
elif property.name == "ids":
return self.ids
elif property.name == "current-pos":
return self.current_pos
elif property.name == "marked":
return self.marked
elif property.name == "column-dict":
return self.column_dict
elif property.name == "change":
return self.change
elif property.name == "plfilter":
return self.plfilter
else:
raise AttributeError, "Unknown property %s" % property.name
def do_set_property(self, property, value):
if property.name == "initital-playlist-complete":
self.initital_playlist_complete = value
elif property.name == "items-count":
self.items_count = value
elif property.name == "ids":
self.ids = value
elif property.name == "current-pos":
self.current_pos = value
elif property.name == "marked":
self.marked = value
elif property.name == "column-dict":
self.column_dict = value
elif property.name == "change":
self.change = value
elif property.name == "plfilter":
self.plfilter = value
else:
raise AttributeError, "Unknown property %s" % property.name
def __init__(self, player):
self.player = player
self.remove_handler = None
#self.set_property("marked", -1)
#self.set_property("filter", "")
self.view = gtk.TreeView()
self.view.set_enable_search(False)
self.view.set_rules_hint(True)
#self.view.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 0), ('text/plain', 0, 1)], gtk.gdk.ACTION_COPY)
self.view.enable_model_drag_dest([('text/plain', 0, 0), ('text/uri-list', 0, 1)],
gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
self.view.connect('row-activated', self.on_view_row_activated)
self.view.connect("drag-drop", self.on_view_drag_drop)
self.view.connect("drag-data-received", self.on_view_drag_data_received)
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
self.storefilter = self.store.filter_new()
self.storefilter.set_visible_func(self.visible_func)
self.selection = self.view.get_selection()
self.selection.set_mode(gtk.SELECTION_MULTIPLE)
gobject.GObject.__init__(self)
self.initital_playlist_complete = False
self.items_count = 0
self.ids = [ ]
self.current_pos = -1
self.marked = -1
self.column_dict = { }
self.change = { }
self.plfilter = ""
self.window = gtk.ScrolledWindow()
self.window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.window.add(self.view)
self.view.show()
self.connect("notify::ids", self.populate)
self.connect("notify::initital-playlist-complete", self.attach_filter)
self.connect("notify::items-count", self.initial_check_complete_cb)
self.connect("notify::current-pos", self.update_marked)
self.connect("notify::change", self.update)
self.connect("notify::plfilter", self.refilter)
self.connect("notify::column-dict", self.view_modify_columns)
def visible_func(self, model, iter):
udata = self.get_property("plfilter")
try:
title = model.get_value(iter, 2).lower()
except AttributeError:
title = ""
try:
artist = model.get_value(iter, 3).lower()
except AttributeError:
artist = ""
try:
album = model.get_value(iter, 4).lower()
except AttributeError:
album = ""
udata = udata.lower()
if udata in title or udata in artist or udata in album:
a = True
else:
a = False
return a
def attach_filter(self, *args):
value = self.get_property("initital-playlist-complete")
if value == True:
self.view.set_model(self.storefilter)
print "attached filter to playlist"
else:
self.view.set_model(None)
print "detached filter from playlist"
def populate(self, *args):
playlist = self.get_property("ids")
self.store.clear()
self.set_property("initital-playlist-complete", False)
self.set_property("items-count", 0)
for entry in playlist:
self.player.client.medialib_get_info(entry, self.populate_cb)
def populate_cb(self, res):
mlib_info = res.value()
final_row = format_playlist_entry(mlib_info)
self.store.append(final_row)
count = self.get_property("items-count") + 1
self.set_property("items-count", count)
def initial_check_complete_cb(self, *args):
value = self.get_property("items-count")
target = len(self.get_property("ids"))
complete = self.get_property("initital-playlist-complete")
if complete == False:
if target == value:
self.set_property("initital-playlist-complete", True)
print "done populating playlist"
pos = self.get_property("current-pos")
self.update_marked(pos)
else:
return
def update_marked(self, *args):
marked = self.get_property("marked")
pos = self.get_property("current-pos")
if marked >= 0:
try:
iiter = self.store.get_iter(marked)
self.store.set_value(iiter, 0, None)
except ValueError:
#assume that the marked entry got removed
self.set_property("marked", -1)
if pos >= 0:
iiter = self.store.get_iter(pos)
#color = u'#ffc600'
color = '#ffd850'
self.store.set_value(iiter, 0, color)
self.set_property("marked", pos)
def update(self, *args):
entry = self.get_property("change")
action = entry['type']
print "playlist change action:", action
if action == 0:
ident = entry['id']
print "new entry with id", ident, "added"
self.add_entry(ident)
elif action == 1:
pos = entry['position']
ident = entry['id']
print "new entry with id", ident, "inserted at position", pos
self.insert_entry(pos, ident)
elif action == 2:
print "playlist shuffled, redownloading playlist"
self.player.playlist_refresh()
elif action == 3:
pos = entry['position']
print "entry at position", pos, "was removed"
self.remove_entry(pos)
elif action == 4:
print "playlist cleared"
self.clear()
elif action == 5:
pos = entry['position']
newpos = entry['newposition']
ident = entry['id']
self.move_entry(pos, newpos, ident)
else:
print "unknown operation:", entry
def add_entry(self, ident):
self.player.client.medialib_get_info(ident, self.add_entry_cb)
def add_entry_cb(self, res):
mlib_info = res.value()
final_row = format_playlist_entry(mlib_info)
self.store.append(final_row)
count = self.get_property("items-count") + 1
self.set_property("items-count", count)
def insert_entry(self, pos, ident):
self.to_insert.append(pos)
self.player.client.medialib_get_info(ident, self.insert_entry_cb)
def insert_entry_cb(self, res):
pos = self.to_insert[0]
mlib_info = res.value()
final_row = format_playlist_entry(mlib_info)
self.store.insert(pos, final_row)
print "entry inserted at", pos
count = self.properties.get_property('items-count') + 1
self.properties.update('items-count', count)
del self.to_insert[0]
def remove_entry(self, pos):
riter = self.store.get_iter((pos))
self.store.remove(riter)
print "removed entry at ", pos
count = self.get_property('items-count') - 1
self.set_property('items-count', count)
print "updated property"
def move_entry(self, pos, newpos, ident):
if pos < newpos:
print "moving entry with id", ident, "at", pos, "after", newpos
iterator = self.store.get_iter(pos)
target_iterator = self.store.get_iter(newpos)
self.store.move_after(iterator, target_iterator)
elif pos > newpos:
print "moving entry with id", ident, "at", pos, "before", newpos
iterator = self.store.get_iter(pos)
target_iterator = self.store.get_iter(newpos)
self.store.move_before(iterator, target_iterator)
def clear(self):
self.store.clear()
self.set_property('items_count', 0)
def remove_selected(self, *args):
def remove_by_reference():
ref = self.remove_ref_list[0]
current_path = ref.get_path()
current_path = current_path[0]
print "removing", current_path
self.player.client.playlist_remove(current_path)
del self.remove_ref_list[0]
model, paths = self.selection.get_selected_rows()
if self.remove_handler:
if self.remove_ref_list != []:
remove_by_reference()
return
else:
self.disconnect(self.remove_handler)
self.remove_handler = None
return
if paths == []:
return
self.remove_ref_list = []
for path in paths:
child_path = self.storefilter.convert_path_to_child_path(path)
ref = gtk.TreeRowReference(self.store, child_path)
self.remove_ref_list.append(ref)
self.remove_handler = self.connect("notify::change", self.remove_selected)
remove_by_reference()
def refilter(self, *args):
gobject.idle_add(self.storefilter.refilter)
def on_view_row_activated(self, treeview, path, view_column):
iter = self.storefilter.get_iter(path)
iter_child = self.storefilter.convert_iter_to_child_iter(iter)
pos = self.store.get_path(iter_child)[0]
self.player.client.playlist_set_next(pos)
self.player.client.playback_tickle()
status = self.player.get_property('playback_status')
if not status == 1:
self.player.playback_start()
def on_view_drag_drop(self, widget, drag_context, x, y, timestamp):
#self.view.emit_stop_by_name("drag-drop")
print ">>>drag and drop"
print "drag_context:", drag_context
print "x, y:", x, y
#print "selection_data:", selection_data
#print "info:", info
print "time:", timestamp
#print "data", data
return True
def on_view_drag_data_received(widget, drag_context, x, y, selection_data, info, timestamp):
#self.view.emit_stop_by_name("drag-data-received")
print ">>>drag data received"
print "drag_context:", drag_context
print "x, y:", x, y
print "selection_data:", selection_data
print " > data:", selection_data.data
print "info:", info
print "time:", timestamp
return True
def view_modify_columns(self, *args):
new_columns = self.get_property("column_dict").keys()
current_columns = self.view.get_columns()
current_columns_names = [ ]
for col in current_columns:
name = col.get_title()
current_columns_names.append(name)
for col in current_columns:
if col.get_title() in new_columns:
continue
elif not col.get_title() in new_columns:
self.view.remove_column(col)
for new_col in new_columns:
if not new_col in current_columns_names:
column = gtk.TreeViewColumn(new_col)
pl_text_renderer = gtk.CellRendererText()
pl_text_renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
pl_text_renderer.set_property("width-chars", self.get_property("column_dict")[new_col])
column.pack_start(pl_text_renderer, True)
column.add_attribute(pl_text_renderer, 'text', self.COLUMN_MAP[new_col])
column.add_attribute(pl_text_renderer, 'background', 0)
column.set_resizable(True)
self.view.append_column(column)