summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Kukkonen <jussi.kukkonen@intel.com>2013-03-06 15:25:14 +0200
committerJussi Kukkonen <jussi.kukkonen@intel.com>2013-03-07 11:19:23 +0200
commit3abecf3805b266dece43a9b09c1acd20672a7a2c (patch)
treefd5f7c345d5cab7a200167405047e31bbd74c274
parent1b8d6318fddb67b1edbd2d999e84dfa3f8f8c6a1 (diff)
downloaddleyna-control-3abecf3805b266dece43a9b09c1acd20672a7a2c.tar.gz
[Browse] Use the GenericModel for Browse
This removes a lot of duplicate code and makes Browse perform as well as Search. Note that BrowseModels are discarded as soon as the view changes to another "directory" (BrowseModel). Caching could be added later on. Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com>
-rw-r--r--AUTHORS1
-rw-r--r--src/msd/msd_browse.py238
-rw-r--r--src/msd/msd_main_window.py67
-rw-r--r--src/msd/msd_upnp.py6
4 files changed, 68 insertions, 244 deletions
diff --git a/AUTHORS b/AUTHORS
index 3bd81c5..f2bb834 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,2 @@
Mark Ryan <mark.d.ryan@intel.com>
+Jussi Kukkonen <jussi.kukkonen@intel.com>
diff --git a/src/msd/msd_browse.py b/src/msd/msd_browse.py
index 1c1b087..de677d3 100644
--- a/src/msd/msd_browse.py
+++ b/src/msd/msd_browse.py
@@ -16,219 +16,51 @@
# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
#
# Mark Ryan <mark.d.ryan@intel.com>
+# Jussi Kukkonen <jussi.kukkonen@intel.com>
#
import pygtk
pygtk.require('2.0')
import gtk
-import dateutil.parser
-import datetime
+from msd_generic_model import *
from msd_sort_order import *
from msd_upnp import *
-class TreeNode(object):
+class BrowseModel(GenericModel):
+ def __init__(self, root, sort_order):
+ super(BrowseModel, self).__init__()
- filter = ["Artist", "DisplayName", "URLs", "Date", "Path",
- "Type"]
- buffer_size = 50
-
- def __init__(self, props, parent, sort_order):
- self.__props = props
- self.__container = None
- self.__max_items = 0
- self.__parent = parent
self.__sort_order = sort_order
- if self.is_container():
- self.__container = Container(props["Path"])
- try:
- self.__max_items = self.__container.get_prop("ChildCount")
- except Exception:
- pass
- self.__children = [None] * self.__max_items
-
- def is_container(self):
- return self.__props["Type"] == "container"
-
- def reset_children(self):
- self.__children = [None] * self.__max_items
-
- def get_num_children(self):
- return self.__max_items
-
- def get_props(self):
- return self.__props
-
- def get_parent(self):
- return self.__parent
-
- def flush(self):
- self.__flush_down()
- if self.__parent:
- self.__parent.__flush_up(self)
-
- def __flush_down(self):
- i = 0;
- while i < self.__max_items:
- if self.__children[i]:
- self.__children[i].__flush_down()
- self.__children[i] = None
- i = i + 1
-
- def __flush_up(self, child):
- i = 0;
- while i < self.__max_items:
- if self.__children[i]:
- if child != self.__children[i]:
- self.__children[i].__flush_down()
- self.__children[i] = None
- i = i + 1
- if self.__parent:
- self.__parent.__flush_up(self)
-
- def get_child(self, child):
- retval = None
- if child < self.__max_items:
- retval = self.__children[child]
- if not retval:
- i = child + 1
- while (i < self.__max_items and (i - child) <
- TreeNode.buffer_size and not self.__children[i]):
- i = i + 1
- try:
- sort_descriptor = self.__sort_order.get_upnp_sort_order()
- try:
- result = self.__container.list_children(child,
- i - child,
- TreeNode.filter,
- sort_descriptor)
- except Exception:
- result = self.__container.list_children(child,
- i - child,
- TreeNode.filter)
- i = child
- for props in result:
- self.__children[i] = TreeNode(props, self,
- self.__sort_order)
- i = i + 1
- retval = self.__children[child]
- except Exception:
- pass
-
- return retval
-
-class BrowseModel(gtk.GenericTreeModel):
- columns = (("DisplayName", str), ("Artist", str), ("Date", str),
- ("Type",str), ("Path", str), ("URLs", str))
-
- def __init__(self, root):
- gtk.GenericTreeModel.__init__(self)
-
self.__root = root
- def flush(self):
- self.__root.flush()
-
- def on_get_flags(self):
- return gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST
-
- def on_get_n_columns(self):
- return len(BrowseModel.columns)
-
- def on_get_column_type(self, n):
- return BrowseModel.columns[n][1]
-
- def __get_num_of_children(self):
- num = self.__root.get_num_children()
- if self.__root.get_parent():
- num = num + 1
- return num
-
- def on_get_iter(self, path):
- if path[0] >= self.__get_num_of_children():
- raise ValueError("Invalid Path")
- return path[0]
-
- def on_get_path(self, rowref):
- return (rowref,)
-
- def adjusted_on_get_value(self, rowref, col):
- retval = None
- key = BrowseModel.columns[col][0]
- node = self.__root.get_child(rowref)
- props = node.get_props()
- if key in props:
- data = props[key]
- if node.is_container():
- if col == 0:
- retval = data
- else:
- if col == 2:
- date = dateutil.parser.parse(data)
- retval = date.strftime("%x")
- elif col == 3:
- data = data[0].upper() + data[1:]
- period = data.find('.')
- if period >=0:
- retval = data[:period]
- else:
- retval = data
- elif col == 5:
- retval = data[0]
- else:
- retval = data
- elif not node.is_container():
- if col == 1:
- retval = "Unknown"
- elif col == 2:
- retval = datetime.date.today().strftime("%x")
- else:
- retval = ""
-
- return retval
-
- def on_get_value(self, rowref, col):
- if self.__root.get_parent():
- if rowref == 0:
- if col == 0:
- retval = ".."
- else:
- retval = ""
- else:
- retval = self.adjusted_on_get_value(rowref - 1, col)
- else:
- retval = self.adjusted_on_get_value(rowref, col)
-
- return retval
-
- def on_iter_next(self, rowref):
- retval = None
- rowref = rowref + 1
- if rowref < self.__get_num_of_children():
- retval = rowref
-
- return retval
-
- def on_iter_children(self, rowref):
- retval = 0
- if rowref:
- retval = None
- return retval
-
- def on_iter_has_child(self, rowref):
- return False
-
- def on_iter_n_children(self, rowref):
- retval = 0
- if not rowref:
- retval = self.__get_num_of_children()
- return retval
-
- def on_iter_nth_child(self, rowref, child):
- retval = None
- if not rowref and child < self.__get_num_of_children():
- retval = child
- return retval
-
- def on_iter_parent(self, rowref):
- return None
+ try:
+ # if this container is in a container, add ".." row
+ parent = root.get_prop('Parent')
+ if (parent != root.get_prop('Path')):
+ self._set_static_row(["..",
+ None,
+ None,
+ "Container",
+ parent,
+ None,
+ False])
+ except:
+ pass
+
+ try:
+ self.__child_count = self.__root.get_prop("ChildCount")
+ except:
+ pass
+
+ self.set_request_range (0, GenericModel.max_items_per_fetch - 1)
+
+ def __on_browse_reply (self, result):
+ self._on_reply(result, self.__child_count)
+
+ def fetch_items(self, start, count):
+ sort_descriptor = self.__sort_order.get_upnp_sort_order()
+ self.__root.list_children(start, count,
+ GenericModel.filter,
+ sort_descriptor,
+ self.__on_browse_reply, self._on_error)
diff --git a/src/msd/msd_main_window.py b/src/msd/msd_main_window.py
index 43291e7..1b0e245 100644
--- a/src/msd/msd_main_window.py
+++ b/src/msd/msd_main_window.py
@@ -73,10 +73,8 @@ class MainWindow(object):
self.__search_view.set_model(search_model)
self.__search_path = path
elif self.__browse_path != path:
- props = { "Path" : path, "Type": "container" }
- self.__browse_tree = TreeNode(props, None, self.__sort_order)
- browse_model = BrowseModel(self.__browse_tree)
- self.__browse_node = self.__browse_tree
+ browse_model = BrowseModel(Container(path),
+ self.__sort_order)
self.__browse_view.set_model(browse_model)
self.__browse_path = path
@@ -129,23 +127,26 @@ class MainWindow(object):
tv.set_model(model)
def __cell_data_func(self, column, cell, model, tree_iter):
- # Only search model supports set_request_range at the moment
- if self.__search_view.get_model() == model:
- path = model.get_path (tree_iter)
-
- # This could be a lot smarter: should fetch data so that
- # there's always at least 1 visible_range preloaded:
- # that way e.g. pressing PgDn would not show "Loading"
- requested_range = model.get_request_range()
- if (path[0] >= requested_range[0] and
- path[0] <= requested_range[1]):
- return
+ path = model.get_path (tree_iter)
+ # This could be a lot smarter: should fetch data so that
+ # there's always at least 1 visible_range preloaded:
+ # that way e.g. pressing PgDn would not show "Loading"
+ requested_range = model.get_request_range()
+ if (path[0] >= requested_range[0] and
+ path[0] <= requested_range[1]):
+ return
+
+ if self.__notebook.get_current_page() == 0:
visible_range = self.__search_view.get_visible_range()
- if (visible_range):
- visible_count = visible_range[1][0] - visible_range[0][0]
- model.set_request_range(max(0, visible_range[0][0] - visible_count // 2),
- min(len(model) - 1, visible_range[1][0] + visible_count // 2))
+ else:
+ visible_range = self.__browse_view.get_visible_range()
+
+ if (visible_range):
+ visible_count = visible_range[1][0] - visible_range[0][0]
+ start = visible_range[0][0] - visible_count // 2
+ end = visible_range[1][0] + visible_count // 2
+ model.set_request_range(max(0, start), min(len(model) - 1, end))
def __create_column(self, treeview, name, col, width, sort_by, cell_data_func=None):
renderer = gtk.CellRendererText()
@@ -170,7 +171,13 @@ class MainWindow(object):
path = model.get_value(rowref, model.COL_PATH)
url = model.get_value(rowref, model.COL_URL)
- if url != "":
+ if (ctype == "Container"):
+ if self.__notebook.get_current_page() == 1:
+ browse_model = BrowseModel(Container(path),
+ self.__sort_order)
+ self.__browse_path = path
+ self.__browse_view.set_model(browse_model)
+ elif url != "":
if ctype == "Image":
self.__window.remove(self.__main_view)
self.__overlay = PlayWindowImage(name, url,
@@ -191,24 +198,6 @@ class MainWindow(object):
self.__close_overlay)
self.__window.add(self.__overlay.get_container())
- def __browse_content_clicked(self, treeview, path, col):
- if self.__browse_node != self.__browse_tree and path[0] == 0:
- self.__browse_node.reset_children()
- self.__browse_node = self.__browse_node.get_parent()
- browse_model = BrowseModel(self.__browse_node)
- self.__browse_view.set_model(browse_model)
- else:
- child = path[0]
- if self.__browse_node != self.__browse_tree:
- child = child - 1
- node = self.__browse_node.get_child(child)
- if node.is_container():
- self.__browse_node = node
- browse_model = BrowseModel(self.__browse_node)
- self.__browse_view.set_model(browse_model)
- else:
- self.__content_clicked(treeview, path, col)
-
def __create_common_list(self, store):
treeview = gtk.TreeView(store)
treeview.set_headers_visible(True)
@@ -230,7 +219,7 @@ class MainWindow(object):
def __create_browse_view(self, notebook):
tree_store = gtk.TreeStore(str, str, str, str)
scrollwin, treeview = self.__create_common_list(tree_store)
- treeview.connect("row-activated", self.__browse_content_clicked)
+ treeview.connect("row-activated", self.__content_clicked)
self.__browse_view = treeview;
notebook.append_page(scrollwin, gtk.Label("Browse"))
diff --git a/src/msd/msd_upnp.py b/src/msd/msd_upnp.py
index bb81c67..63bafc2 100644
--- a/src/msd/msd_upnp.py
+++ b/src/msd/msd_upnp.py
@@ -47,8 +47,10 @@ class Container(MediaObject):
reply_handler=on_reply,
error_handler=on_error)
- def list_children(self, offset, count, fltr, sort=""):
- return self.__containerIF.ListChildrenEx(offset, count, fltr, sort)
+ def list_children(self, offset, count, fltr, sort="", on_reply=None, on_error=None):
+ return self.__containerIF.ListChildrenEx(offset, count, fltr, sort,
+ reply_handler=on_reply,
+ error_handler=on_error)
class State(object):