From: Ed Page Date: Thu, 13 May 2010 01:32:31 +0000 (-0500) Subject: Implementing Jump To with a couple of helpers along the way which also X-Git-Url: http://git.maemo.org/git/?p=watersofshiloah;a=commitdiff_plain;h=ebe1ebae53b120de4a6d0fdde1c6c71506b29c49 Implementing Jump To with a couple of helpers along the way which also simplified implementing highlighting the current row --- diff --git a/src/index.py b/src/index.py deleted file mode 100644 index 2ffb6c2..0000000 --- a/src/index.py +++ /dev/null @@ -1,364 +0,0 @@ -import weakref -import logging - -import util.misc as misc_utils -from util import go_utils -import backend - - -_moduleLogger = logging.getLogger(__name__) - - -class Connection(object): - - def __init__(self): - self._backend = backend.Backend() - self._indexing = go_utils.AsyncPool() - - def start(self): - self._indexing.start() - - def stop(self): - self._indexing.stop() - - def download(self, func, on_success, on_error, args = None, kwds = None): - if args is None: - args = () - if kwds is None: - kwds = {} - - self._indexing.clear_tasks() - self._indexing.add_task( - getattr(self._backend, func), - args, - kwds, - on_success, - on_error, - ) - - -class AudioIndex(object): - - def __init__(self): - self._connection = Connection() - self._languages = None - self._languagesRequest = None - self._sources = {} - - def start(self): - self._connection.start() - - def stop(self): - self._connection.stop() - - def get_languages(self, on_success, on_error): - if self._languages is None: - assert self._languagesRequest is None - self._languagesRequest = on_success, on_error - self._connection.download( - "get_languages", - self._on_get_languages, - self._on_languages_error - ) - else: - on_success(self._languages) - - def get_source(self, source, langId = None): - key = (source, langId) - if key in self._sources: - node = self._sources[key] - else: - if source == "radio": - node = RadioNode(self._connection) - elif source == "conferences": - assert langId is not None - node = ConferencesNode(self._connection, langId) - else: - raise NotImplementedError(source) - self._sources[key] = node - - return node - - @misc_utils.log_exception(_moduleLogger) - def _on_get_languages(self, languages): - assert self._languages is None - assert self._languagesRequest is not None - r = self._languagesRequest - self._languagesRequest = None - self._languages = languages - r[0](self._languages) - - @misc_utils.log_exception(_moduleLogger) - def _on_languages_error(self, e): - assert self._languages is None - assert self._languagesRequest is not None - r = self._languagesRequest - self._languagesRequest = None - r[1](self._languages) - - -class Node(object): - - def __init__(self, connection, parent, data): - self._connection = connection - self._parent = weakref.ref(parent) if parent is not None else None - self._data = data - self._children = None - - def get_children(self, on_success, on_error): - if self._children is None: - self._get_children(on_success, on_error) - else: - on_success(self._children) - - def get_parent(self): - if self._parent is None: - raise RuntimeError("") - parent = self._parent() - return parent - - def get_properties(self): - return self._data - - @property - def title(self): - raise NotImplementedError("On %s" % type(self)) - - def is_leaf(self): - raise NotImplementedError("") - - def _get_children(self, on_success, on_error): - raise NotImplementedError("") - - -class ParentNode(Node): - - def __init__(self, connection, parent, data): - Node.__init__(self, connection, parent, data) - self._request = None - - def is_leaf(self): - return False - - def _get_children(self, on_success, on_error): - assert self._request is None - assert self._children is None - self._request = on_success, on_error - - func, args, kwds = self._get_func() - - self._connection.download( - func, - self._on_success, - self._on_error, - args, - kwds, - ) - - def _get_func(self): - raise NotImplementedError() - - def _create_child(self, data): - raise NotImplementedError() - - @misc_utils.log_exception(_moduleLogger) - def _on_success(self, data): - r = self._request - self._request = None - try: - self._children = [ - self._create_child(child) - for child in data - ] - except Exception, e: - _moduleLogger.exception("Translating error") - self._children = None - r[1](e) - else: - r[0](self._children) - - @misc_utils.log_exception(_moduleLogger) - def _on_error(self, error): - r = self._request - self._request = None - r[1](error) - - -class LeafNode(Node): - - def __init__(self, connection, parent, data): - Node.__init__(self, connection, parent, data) - - def is_leaf(self): - return True - - @property - def can_navigate(self): - raise NotImplementedError("On %s" % type(self)) - - @property - def subtitle(self): - raise NotImplementedError("On %s" % type(self)) - - @property - def uri(self): - raise NotImplementedError("On %s" % type(self)) - - def _get_children(self, on_success, on_error): - raise RuntimeError("Not is a leaf") - - -class RadioNode(ParentNode): - - def __init__(self, connection): - ParentNode.__init__(self, connection, None, {}) - - @property - def title(self): - return "Radio" - - def _get_func(self): - return "get_radio_channels", (), {} - - def _create_child(self, data): - return RadioChannelNode(self._connection, self, data) - - -class RadioChannelNode(LeafNode): - - def __init__(self, connection, parent, data): - LeafNode.__init__(self, connection, parent, data) - self._extendedData = {} - self._request = None - - @property - def can_navigate(self): - return False - - @property - def title(self): - return "Radio" - - @property - def subtitle(self): - return "" - - @property - def uri(self): - return self._data["url"] - - def get_programming(self, date, on_success, on_error): - date = date.strftime("%Y-%m-%d") - try: - programming = self._extendedData[date] - except KeyError: - self._get_programming(date, on_success, on_error) - else: - on_success(programming) - - def _get_programming(self, date, on_success, on_error): - assert self._request is None - assert date not in self._extendedData - self._request = on_success, on_error, date - - self._connection.download( - "get_radio_channel_programming", - self._on_success, - self._on_error, - (self._data["id"], date), - {}, - ) - - @misc_utils.log_exception(_moduleLogger) - def _on_success(self, data): - r = self._request - date = r[2] - self._request = None - try: - self._extendedData[date] = [ - child - for child in data - ] - except Exception, e: - _moduleLogger.exception("Translating error") - del self._extendedData[date] - r[1](e) - else: - r[0](self._extendedData[date]) - - @misc_utils.log_exception(_moduleLogger) - def _on_error(self, error): - r = self._request - self._request = None - r[1](error) - - -class ConferencesNode(ParentNode): - - def __init__(self, connection, langId): - ParentNode.__init__(self, connection, None, {}) - self._langId = langId - - @property - def title(self): - return "Conferences" - - def _get_func(self): - return "get_conferences", (self._langId, ), {} - - def _create_child(self, data): - return ConferenceNode(self._connection, self, data) - - -class ConferenceNode(ParentNode): - - def __init__(self, connection, parent, data): - ParentNode.__init__(self, connection, parent, data) - - @property - def title(self): - return self._data["title"] - - def _get_func(self): - return "get_conference_sessions", (self._data["id"], ), {} - - def _create_child(self, data): - return SessionNode(self._connection, self, data) - - -class SessionNode(ParentNode): - - def __init__(self, connection, parent, data): - ParentNode.__init__(self, connection, parent, data) - - @property - def title(self): - return self._data["title"] - - def _get_func(self): - return "get_conference_talks", (self._data["id"], ), {} - - def _create_child(self, data): - return TalkNode(self._connection, self, data) - - -class TalkNode(LeafNode): - - def __init__(self, connection, parent, data): - LeafNode.__init__(self, connection, parent, data) - - @property - def can_navigate(self): - return True - - @property - def title(self): - return self._data["title"] - - @property - def subtitle(self): - return self._data["speaker"] - - @property - def uri(self): - return self._data["url"] diff --git a/src/mormonchannel_gtk.py b/src/mormonchannel_gtk.py index aa31895..1b18191 100755 --- a/src/mormonchannel_gtk.py +++ b/src/mormonchannel_gtk.py @@ -2,8 +2,6 @@ # -*- coding: utf-8 -*- """ -@todo Implement Jump TO -@todo Implement highlighting of current track @todo Restructure so there is a windows/ folder with a file per source @todo Add additional sources @bug All connect's need disconnects or else we will leak a bunch of objects @@ -31,7 +29,7 @@ import util.misc as misc_utils import imagestore import player -import index +import stream_index import windows @@ -44,7 +42,7 @@ class MormonChannelProgram(hildonize.get_app_class()): def __init__(self): super(MormonChannelProgram, self).__init__() self._store = imagestore.ImageStore("../data", "../data") - self._index = index.AudioIndex() + self._index = stream_index.AudioIndex() self._player = player.Player(self._index) self._index.start() diff --git a/src/stream_index.py b/src/stream_index.py new file mode 100644 index 0000000..8e83769 --- /dev/null +++ b/src/stream_index.py @@ -0,0 +1,406 @@ +import weakref +import logging + +import util.misc as misc_utils +from util import go_utils +import backend + + +_moduleLogger = logging.getLogger(__name__) + + +SOURCE_RADIO = "radio" +SOURCE_CONFERENCES = "conferences" +SOURCE_MAGAZINES = "magazines" +SOURCE_SCRIPTURES = "scriptures" + + +class Connection(object): + + def __init__(self): + self._backend = backend.Backend() + self._indexing = go_utils.AsyncPool() + + def start(self): + self._indexing.start() + + def stop(self): + self._indexing.stop() + + def download(self, func, on_success, on_error, args = None, kwds = None): + if args is None: + args = () + if kwds is None: + kwds = {} + + self._indexing.clear_tasks() + self._indexing.add_task( + getattr(self._backend, func), + args, + kwds, + on_success, + on_error, + ) + + +class AudioIndex(object): + + def __init__(self): + self._connection = Connection() + self._languages = None + self._languagesRequest = None + self._sources = {} + + def start(self): + self._connection.start() + + def stop(self): + self._connection.stop() + + def get_languages(self, on_success, on_error): + if self._languages is None: + assert self._languagesRequest is None + self._languagesRequest = on_success, on_error + self._connection.download( + "get_languages", + self._on_get_languages, + self._on_languages_error + ) + else: + on_success(self._languages) + + def get_source(self, source, langId = None): + key = (source, langId) + if key in self._sources: + node = self._sources[key] + else: + if source == SOURCE_RADIO: + node = RadioNode(self._connection) + elif source == SOURCE_CONFERENCES: + assert langId is not None + node = ConferencesNode(self._connection, langId) + else: + raise NotImplementedError(source) + self._sources[key] = node + + return node + + @misc_utils.log_exception(_moduleLogger) + def _on_get_languages(self, languages): + assert self._languages is None + assert self._languagesRequest is not None + r = self._languagesRequest + self._languagesRequest = None + self._languages = languages + r[0](self._languages) + + @misc_utils.log_exception(_moduleLogger) + def _on_languages_error(self, e): + assert self._languages is None + assert self._languagesRequest is not None + r = self._languagesRequest + self._languagesRequest = None + r[1](self._languages) + + +class Node(object): + + def __init__(self, connection, parent, data, id): + self._connection = connection + self._parent = weakref.ref(parent) if parent is not None else None + self._data = data + self._children = None + self._id = id + + def get_children(self, on_success, on_error): + if self._children is None: + self._get_children(on_success, on_error) + else: + on_success(self._children) + + def get_parent(self): + if self._parent is None: + raise RuntimeError("") + parent = self._parent() + return parent + + def get_properties(self): + return self._data + + @property + def title(self): + raise NotImplementedError("On %s" % type(self)) + + @property + def id(self): + return self._id + + def is_leaf(self): + raise NotImplementedError("") + + def _get_children(self, on_success, on_error): + raise NotImplementedError("") + + +class ParentNode(Node): + + def __init__(self, connection, parent, data, id): + Node.__init__(self, connection, parent, data, id) + self._request = None + + def is_leaf(self): + return False + + def _get_children(self, on_success, on_error): + assert self._request is None + assert self._children is None + self._request = on_success, on_error + + func, args, kwds = self._get_func() + + self._connection.download( + func, + self._on_success, + self._on_error, + args, + kwds, + ) + + def _get_func(self): + raise NotImplementedError() + + def _create_child(self, data, id): + raise NotImplementedError() + + @misc_utils.log_exception(_moduleLogger) + def _on_success(self, data): + r = self._request + self._request = None + try: + self._children = [ + self._create_child(child, i) + for i, child in enumerate(data) + ] + except Exception, e: + _moduleLogger.exception("Translating error") + self._children = None + r[1](e) + else: + r[0](self._children) + + @misc_utils.log_exception(_moduleLogger) + def _on_error(self, error): + r = self._request + self._request = None + r[1](error) + + +class LeafNode(Node): + + def __init__(self, connection, parent, data, id): + Node.__init__(self, connection, parent, data, id) + + def is_leaf(self): + return True + + @property + def can_navigate(self): + raise NotImplementedError("On %s" % type(self)) + + @property + def subtitle(self): + raise NotImplementedError("On %s" % type(self)) + + @property + def uri(self): + raise NotImplementedError("On %s" % type(self)) + + def _get_children(self, on_success, on_error): + raise RuntimeError("Not is a leaf") + + +class RadioNode(ParentNode): + + def __init__(self, connection): + ParentNode.__init__(self, connection, None, {}, SOURCE_RADIO) + + @property + def title(self): + return "Radio" + + def _get_func(self): + return "get_radio_channels", (), {} + + def _create_child(self, data, id): + return RadioChannelNode(self._connection, self, data, id) + + +class RadioChannelNode(LeafNode): + + def __init__(self, connection, parent, data, id): + LeafNode.__init__(self, connection, parent, data, id) + self._extendedData = {} + self._request = None + + @property + def can_navigate(self): + return False + + @property + def title(self): + return "Radio" + + @property + def subtitle(self): + return "" + + @property + def uri(self): + return self._data["url"] + + def get_programming(self, date, on_success, on_error): + date = date.strftime("%Y-%m-%d") + try: + programming = self._extendedData[date] + except KeyError: + self._get_programming(date, on_success, on_error) + else: + on_success(programming) + + def _get_programming(self, date, on_success, on_error): + assert self._request is None + assert date not in self._extendedData + self._request = on_success, on_error, date + + self._connection.download( + "get_radio_channel_programming", + self._on_success, + self._on_error, + (self._data["id"], date), + {}, + ) + + @misc_utils.log_exception(_moduleLogger) + def _on_success(self, data): + r = self._request + date = r[2] + self._request = None + try: + self._extendedData[date] = [ + child + for child in data + ] + except Exception, e: + _moduleLogger.exception("Translating error") + del self._extendedData[date] + r[1](e) + else: + r[0](self._extendedData[date]) + + @misc_utils.log_exception(_moduleLogger) + def _on_error(self, error): + r = self._request + self._request = None + r[1](error) + + +class ConferencesNode(ParentNode): + + def __init__(self, connection, langId): + ParentNode.__init__(self, connection, None, {}, SOURCE_CONFERENCES) + self._langId = langId + + @property + def title(self): + return "Conferences" + + def _get_func(self): + return "get_conferences", (self._langId, ), {} + + def _create_child(self, data, id): + return ConferenceNode(self._connection, self, data, id) + + +class ConferenceNode(ParentNode): + + def __init__(self, connection, parent, data, id): + ParentNode.__init__(self, connection, parent, data, id) + + @property + def title(self): + return self._data["title"] + + def _get_func(self): + return "get_conference_sessions", (self._data["id"], ), {} + + def _create_child(self, data, id): + return SessionNode(self._connection, self, data, id) + + +class SessionNode(ParentNode): + + def __init__(self, connection, parent, data, id): + ParentNode.__init__(self, connection, parent, data, id) + + @property + def title(self): + return self._data["title"] + + def _get_func(self): + return "get_conference_talks", (self._data["id"], ), {} + + def _create_child(self, data, id): + return TalkNode(self._connection, self, data, id) + + +class TalkNode(LeafNode): + + def __init__(self, connection, parent, data, id): + LeafNode.__init__(self, connection, parent, data, id) + + @property + def can_navigate(self): + return True + + @property + def title(self): + return self._data["title"] + + @property + def subtitle(self): + return self._data["speaker"] + + @property + def uri(self): + return self._data["url"] + + +def walk_ancestors(node): + while True: + yield node + try: + node = node.get_parent() + except RuntimeError: + return + + +def common_paths(targetNode, currentNode): + targetNodePath = list(walk_ancestors(targetNode)) + targetNodePath.reverse() + currentNodePath = list(walk_ancestors(currentNode)) + currentNodePath.reverse() + + ancestors = [] + descendants = [] + + for i, (t, c) in enumerate(zip(targetNodePath, currentNodePath)): + if t is not c: + return ancestors, None, descendants + ancestors.append(t) + + descendants.extend( + child + for child in targetNodePath[i+1:] + ) + + return ancestors, currentNode, descendants diff --git a/src/windows.py b/src/windows.py index 65947b3..a31d1a2 100644 --- a/src/windows.py +++ b/src/windows.py @@ -11,6 +11,7 @@ import constants import hildonize import util.misc as misc_utils +import stream_index import banners import playcontrol import presenter @@ -100,6 +101,9 @@ class BasicWindow(gobject.GObject): else: self._window.unfullscreen() + def jump_to(self, node): + raise NotImplementedError("On %s" % self) + @misc_utils.log_exception(_moduleLogger) def _on_destroy(self, *args): self._isDestroyed = True @@ -150,9 +154,7 @@ class BasicWindow(gobject.GObject): @misc_utils.log_exception(_moduleLogger) def _on_jump(self, source, node): - _moduleLogger.error("Jump is not implemented") - self.emit("jump-to", node) - self._window.destroy() + raise NotImplementedError("On %s" % self) @misc_utils.log_exception(_moduleLogger) def _on_quit(self, *args): @@ -170,22 +172,22 @@ class SourceSelector(BasicWindow): self._loadingBanner = banners.GenericBanner() self._radioButton = self._create_button("radio", "Radio") - self._radioButton.connect("clicked", self._on_source_selected, RadioWindow, "radio") + self._radioButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_RADIO) self._radioWrapper = gtk.VBox() self._radioWrapper.pack_start(self._radioButton, False, True) self._conferenceButton = self._create_button("conferences", "Conferences") - self._conferenceButton.connect("clicked", self._on_source_selected, ConferencesWindow, "conferences") + self._conferenceButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_CONFERENCES) self._conferenceWrapper = gtk.VBox() self._conferenceWrapper.pack_start(self._conferenceButton, False, True) self._magazineButton = self._create_button("magazines", "Magazines") - #self._magazineButton.connect("clicked", self._on_source_selected) + self._magazineButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_MAGAZINES) self._magazineWrapper = gtk.VBox() self._magazineWrapper.pack_start(self._magazineButton, False, True) self._scriptureButton = self._create_button("scriptures", "Scriptures") - #self._scriptureButton.connect("clicked", self._on_source_selected) + self._scriptureButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_SCRIPTURES) self._scriptureWrapper = gtk.VBox() self._scriptureWrapper.pack_start(self._scriptureButton, False, True) @@ -197,6 +199,7 @@ class SourceSelector(BasicWindow): self._buttonLayout.pack_start(self._scriptureWrapper, True, True) self._playcontrol = playcontrol.NavControl(player, store) + self._playcontrol.connect("jump-to", self._on_jump) self._layout.pack_start(self._loadingBanner.toplevel, False, False) self._layout.pack_start(self._buttonLayout, True, True) @@ -250,15 +253,35 @@ class SourceSelector(BasicWindow): self._hide_loading() self._errorBanner.push_message(str(exception)) - @misc_utils.log_exception(_moduleLogger) - def _on_source_selected(self, widget, Source, nodeName): - node = self._index.get_source(nodeName, self._languages[0]["id"]) + def _window_from_node(self, node): + if node.id == stream_index.SOURCE_RADIO: + Source = RadioWindow + elif node.id == stream_index.SOURCE_CONFERENCES: + Source = ConferencesWindow + elif node.id == stream_index.SOURCE_MAGAZINES: + pass + elif node.id == stream_index.SOURCE_SCRIPTURES: + pass sourceWindow = Source(self._player, self._store, node) sourceWindow.window.set_modal(True) sourceWindow.window.set_transient_for(self._window) sourceWindow.window.set_default_size(*self._window.get_size()) sourceWindow.connect("quit", self._on_quit) + sourceWindow.connect("jump-to", self._on_jump) sourceWindow.show() + return sourceWindow + + @misc_utils.log_exception(_moduleLogger) + def _on_jump(self, source, node): + targetNodePath = list(reversed(list(stream_index.walk_ancestors(node)))) + ancestor = targetNodePath[0] + window = self._window_from_node(ancestor) + window.jump_to(node) + + @misc_utils.log_exception(_moduleLogger) + def _on_source_selected(self, widget, nodeName): + node = self._index.get_source(nodeName, self._languages[0]["id"]) + self._window_from_node(node) gobject.type_register(SourceSelector) @@ -334,6 +357,9 @@ class RadioWindow(BasicWindow): self._refresh() + def jump_to(self, node): + _moduleLogger.info("Only 1 channel, nothing to jump to") + @property def _active(self): return self._player.node is self._childNode @@ -556,12 +582,51 @@ class ListWindow(BasicWindow): raise NotImplementedError("") def _get_current_row(self): + if self._player.node is None: + return -1 + ancestors, current, descendants = stream_index.common_paths(self._player.node, self._node) + if not descendants: + return -1 + activeChild = descendants[0] + for i, row in enumerate(self._model): + if activeChild is row[0]: + return i + else: + return -1 + + def jump_to(self, node): + ancestors, current, descendants = stream_index.common_paths(node, self._node) + if current is None: + raise RuntimeError("Cannot jump to node %s" % node) + if not descendants: + _moduleLogger.info("Current node is the target") + return + child = descendants[0] + window = self._window_from_node(child) + window.jump_to(node) + + def _window_from_node(self, node): raise NotImplementedError("") @misc_utils.log_exception(_moduleLogger) def _on_row_activated(self, view, path, column): raise NotImplementedError("") + @misc_utils.log_exception(_moduleLogger) + def _on_jump(self, source, node): + ancestors, current, descendants = stream_index.common_paths(node, self._node) + if current is None: + _moduleLogger.info("%s is not the target, moving up" % self._node) + self.emit("jump-to", node) + self._window.destroy() + return + if not descendants: + _moduleLogger.info("Current node is the target") + return + child = descendants[0] + window = self._window_from_node(child) + window.jump_to(node) + def _show_loading(self): animationPath = self._store.STORE_LOOKUP["loading"] animation = self._store.get_pixbuf_animation_from_store(animationPath) @@ -602,10 +667,6 @@ class ConferencesWindow(ListWindow): column.add_attribute(textrenderer, "text", 2) yield gobject.TYPE_STRING, column - def _get_current_row(self): - # @todo Not implemented yet - return 0 - def _refresh(self): ListWindow._refresh(self) self._node.get_children( @@ -634,18 +695,22 @@ class ConferencesWindow(ListWindow): self._hide_loading() self._errorBanner.push_message(str(exception)) - @misc_utils.log_exception(_moduleLogger) - def _on_row_activated(self, view, path, column): - itr = self._model.get_iter(path) - node = self._model.get_value(itr, 0) - + def _window_from_node(self, node): sessionsWindow = ConferenceSessionsWindow(self._player, self._store, node) sessionsWindow.window.set_modal(True) sessionsWindow.window.set_transient_for(self._window) sessionsWindow.window.set_default_size(*self._window.get_size()) sessionsWindow.connect("quit", self._on_quit) sessionsWindow.connect("home", self._on_home) + sessionsWindow.connect("jump-to", self._on_jump) sessionsWindow.show() + return sessionsWindow + + @misc_utils.log_exception(_moduleLogger) + def _on_row_activated(self, view, path, column): + itr = self._model.get_iter(path) + node = self._model.get_value(itr, 0) + self._window_from_node(node) gobject.type_register(ConferencesWindow) @@ -667,10 +732,6 @@ class ConferenceSessionsWindow(ListWindow): column.add_attribute(textrenderer, "text", 1) yield gobject.TYPE_STRING, column - def _get_current_row(self): - # @todo Not implemented yet - return 0 - def _refresh(self): ListWindow._refresh(self) self._node.get_children( @@ -699,18 +760,22 @@ class ConferenceSessionsWindow(ListWindow): self._hide_loading() self._errorBanner.push_message(str(exception)) - @misc_utils.log_exception(_moduleLogger) - def _on_row_activated(self, view, path, column): - itr = self._model.get_iter(path) - node = self._model.get_value(itr, 0) - + def _window_from_node(self, node): sessionsWindow = ConferenceTalksWindow(self._player, self._store, node) sessionsWindow.window.set_modal(True) sessionsWindow.window.set_transient_for(self._window) sessionsWindow.window.set_default_size(*self._window.get_size()) sessionsWindow.connect("quit", self._on_quit) sessionsWindow.connect("home", self._on_home) + sessionsWindow.connect("jump-to", self._on_jump) sessionsWindow.show() + return sessionsWindow + + @misc_utils.log_exception(_moduleLogger) + def _on_row_activated(self, view, path, column): + itr = self._model.get_iter(path) + node = self._model.get_value(itr, 0) + self._window_from_node(node) gobject.type_register(ConferenceSessionsWindow) @@ -732,10 +797,6 @@ class ConferenceTalksWindow(ListWindow): column.add_attribute(textrenderer, "text", 1) yield gobject.TYPE_STRING, column - def _get_current_row(self): - # @todo Not implemented yet - return 0 - def _refresh(self): ListWindow._refresh(self) self._node.get_children( @@ -764,18 +825,22 @@ class ConferenceTalksWindow(ListWindow): self._hide_loading() self._errorBanner.push_message(str(exception)) - @misc_utils.log_exception(_moduleLogger) - def _on_row_activated(self, view, path, column): - itr = self._model.get_iter(path) - node = self._model.get_value(itr, 0) - + def _window_from_node(self, node): sessionsWindow = ConferenceTalkWindow(self._player, self._store, node) sessionsWindow.window.set_modal(True) sessionsWindow.window.set_transient_for(self._window) sessionsWindow.window.set_default_size(*self._window.get_size()) sessionsWindow.connect("quit", self._on_quit) sessionsWindow.connect("home", self._on_home) + sessionsWindow.connect("jump-to", self._on_jump) sessionsWindow.show() + return sessionsWindow + + @misc_utils.log_exception(_moduleLogger) + def _on_row_activated(self, view, path, column): + itr = self._model.get_iter(path) + node = self._model.get_value(itr, 0) + self._window_from_node(node) gobject.type_register(ConferenceTalksWindow) @@ -817,6 +882,9 @@ class ConferenceTalkWindow(BasicWindow): ) self._set_context(self._player.state) + def jump_to(self, node): + assert self._node is node + @property def _active(self): return self._player.node is self._node