1 # @todo Add icons to buttons/rows to indicate that the currently playing track is coming from that
12 import util.misc as misc_utils
20 _moduleLogger = logging.getLogger(__name__)
23 class BasicWindow(gobject.GObject):
27 gobject.SIGNAL_RUN_LAST,
32 gobject.SIGNAL_RUN_LAST,
37 gobject.SIGNAL_RUN_LAST,
39 (gobject.TYPE_PYOBJECT, ),
42 gobject.SIGNAL_RUN_LAST,
44 (gobject.TYPE_BOOLEAN, ),
47 gobject.SIGNAL_RUN_LAST,
49 (gobject.TYPE_BOOLEAN, ),
53 def __init__(self, player, store):
54 gobject.GObject.__init__(self)
55 self._isDestroyed = False
60 self._clipboard = gtk.clipboard_get()
61 self._windowInFullscreen = False
63 self._errorBanner = banners.StackingBanner()
65 self._layout = gtk.VBox()
66 self._layout.pack_start(self._errorBanner.toplevel, False, True)
68 self._window = gtk.Window()
69 self._window.add(self._layout)
70 self._window = hildonize.hildonize_window(self, self._window)
72 self._window.set_icon(self._store.get_pixbuf_from_store(self._store.STORE_LOOKUP["icon"]))
73 self._window.connect("key-press-event", self._on_key_press)
74 self._window.connect("window-state-event", self._on_window_state_change)
75 self._window.connect("destroy", self._on_destroy)
82 self._window.show_all()
84 def save_settings(self, config, sectionName):
85 config.add_section(sectionName)
86 config.set(sectionName, "fullscreen", str(self._windowInFullscreen))
88 def load_settings(self, config, sectionName):
90 self._windowInFullscreen = config.getboolean(sectionName, "fullscreen")
91 except ConfigParser.NoSectionError, e:
93 "Settings file %s is missing section %s" % (
94 constants._user_settings_,
99 if self._windowInFullscreen:
100 self._window.fullscreen()
102 self._window.unfullscreen()
104 def jump_to(self, node):
105 raise NotImplementedError("On %s" % self)
107 @misc_utils.log_exception(_moduleLogger)
108 def _on_destroy(self, *args):
109 self._isDestroyed = True
111 @misc_utils.log_exception(_moduleLogger)
112 def _on_window_state_change(self, widget, event, *args):
113 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
114 self._windowInFullscreen = True
116 self._windowInFullscreen = False
117 self.emit("fullscreen", self._windowInFullscreen)
119 @misc_utils.log_exception(_moduleLogger)
120 def _on_key_press(self, widget, event, *args):
121 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
122 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
124 event.keyval == gtk.keysyms.F6 or
125 event.keyval in RETURN_TYPES and isCtrl
127 # The "Full screen" hardware key has been pressed
128 if self._windowInFullscreen:
129 self._window.unfullscreen ()
131 self._window.fullscreen ()
134 event.keyval in (gtk.keysyms.w, ) and
135 event.get_state() & gtk.gdk.CONTROL_MASK
137 self._window.destroy()
139 event.keyval in (gtk.keysyms.q, ) and
140 event.get_state() & gtk.gdk.CONTROL_MASK
143 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
144 with open(constants._user_logpath_, "r") as f:
145 logLines = f.xreadlines()
146 log = "".join(logLines)
147 self._clipboard.set_text(str(log))
150 @misc_utils.log_exception(_moduleLogger)
151 def _on_home(self, *args):
153 self._window.destroy()
155 @misc_utils.log_exception(_moduleLogger)
156 def _on_jump(self, source, node):
157 raise NotImplementedError("On %s" % self)
159 @misc_utils.log_exception(_moduleLogger)
160 def _on_quit(self, *args):
162 self._window.destroy()
165 class SourceSelector(BasicWindow):
167 def __init__(self, player, store, index):
168 BasicWindow.__init__(self, player, store)
172 self._loadingBanner = banners.GenericBanner()
174 self._radioButton = self._create_button("radio", "Radio")
175 self._radioButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_RADIO)
176 self._radioWrapper = gtk.VBox()
177 self._radioWrapper.pack_start(self._radioButton, False, True)
179 self._conferenceButton = self._create_button("conferences", "Conferences")
180 self._conferenceButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_CONFERENCES)
181 self._conferenceWrapper = gtk.VBox()
182 self._conferenceWrapper.pack_start(self._conferenceButton, False, True)
184 self._magazineButton = self._create_button("magazines", "Magazines")
185 self._magazineButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_MAGAZINES)
186 self._magazineWrapper = gtk.VBox()
187 self._magazineWrapper.pack_start(self._magazineButton, False, True)
189 self._scriptureButton = self._create_button("scriptures", "Scriptures")
190 self._scriptureButton.connect("clicked", self._on_source_selected, stream_index.SOURCE_SCRIPTURES)
191 self._scriptureWrapper = gtk.VBox()
192 self._scriptureWrapper.pack_start(self._scriptureButton, False, True)
194 self._buttonLayout = gtk.VButtonBox()
195 self._buttonLayout.set_layout(gtk.BUTTONBOX_SPREAD)
196 self._buttonLayout.pack_start(self._radioWrapper, True, True)
197 self._buttonLayout.pack_start(self._conferenceWrapper, True, True)
198 self._buttonLayout.pack_start(self._magazineWrapper, True, True)
199 self._buttonLayout.pack_start(self._scriptureWrapper, True, True)
201 self._playcontrol = playcontrol.NavControl(player, store)
202 self._playcontrol.connect("jump-to", self._on_jump)
204 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
205 self._layout.pack_start(self._buttonLayout, True, True)
206 self._layout.pack_start(self._playcontrol.toplevel, False, True)
208 self._window.set_title(constants.__pretty_app_name__)
211 BasicWindow.show(self)
213 self._errorBanner.toplevel.hide()
214 self._playcontrol.toplevel.hide()
218 def _show_loading(self):
219 animationPath = self._store.STORE_LOOKUP["loading"]
220 animation = self._store.get_pixbuf_animation_from_store(animationPath)
221 self._loadingBanner.show(animation, "Loading...")
222 self._buttonLayout.set_sensitive(False)
224 def _hide_loading(self):
225 self._loadingBanner.hide()
226 self._buttonLayout.set_sensitive(True)
230 self._index.get_languages(self._on_languages, self._on_error)
232 def _create_button(self, icon, message):
233 image = self._store.get_image_from_store(self._store.STORE_LOOKUP[icon])
236 label.set_text(message)
238 buttonLayout = gtk.HBox(False, 5)
239 buttonLayout.pack_start(image, False, False)
240 buttonLayout.pack_start(label, False, True)
241 button = gtk.Button()
242 button.add(buttonLayout)
246 @misc_utils.log_exception(_moduleLogger)
247 def _on_languages(self, languages):
249 self._languages = list(languages)
251 @misc_utils.log_exception(_moduleLogger)
252 def _on_error(self, exception):
254 self._errorBanner.push_message(str(exception))
256 def _window_from_node(self, node):
257 if node.id == stream_index.SOURCE_RADIO:
259 elif node.id == stream_index.SOURCE_CONFERENCES:
260 Source = ConferencesWindow
261 elif node.id == stream_index.SOURCE_MAGAZINES:
263 elif node.id == stream_index.SOURCE_SCRIPTURES:
265 sourceWindow = Source(self._player, self._store, node)
266 sourceWindow.window.set_modal(True)
267 sourceWindow.window.set_transient_for(self._window)
268 sourceWindow.window.set_default_size(*self._window.get_size())
269 sourceWindow.connect("quit", self._on_quit)
270 sourceWindow.connect("jump-to", self._on_jump)
274 @misc_utils.log_exception(_moduleLogger)
275 def _on_jump(self, source, node):
276 targetNodePath = list(reversed(list(stream_index.walk_ancestors(node))))
277 ancestor = targetNodePath[0]
278 window = self._window_from_node(ancestor)
281 @misc_utils.log_exception(_moduleLogger)
282 def _on_source_selected(self, widget, nodeName):
283 node = self._index.get_source(nodeName, self._languages[0]["id"])
284 self._window_from_node(node)
287 gobject.type_register(SourceSelector)
290 class RadioWindow(BasicWindow):
292 def __init__(self, player, store, node):
293 BasicWindow.__init__(self, player, store)
295 self._childNode = None
297 self._player.connect("state-change", self._on_player_state_change)
298 self._player.connect("title-change", self._on_player_title_change)
300 self._loadingBanner = banners.GenericBanner()
302 headerPath = self._store.STORE_LOOKUP["radio_header"]
303 self._header = self._store.get_image_from_store(headerPath)
304 self._headerNavigation = presenter.NavigationBox()
305 self._headerNavigation.toplevel.add(self._header)
306 self._headerNavigation.connect("action", self._on_nav_action)
307 self._headerNavigation.connect("navigating", self._on_navigating)
309 self._programmingModel = gtk.ListStore(
314 textrenderer = gtk.CellRendererText()
315 timeColumn = gtk.TreeViewColumn("Time")
316 timeColumn.pack_start(textrenderer, expand=True)
317 timeColumn.add_attribute(textrenderer, "text", 0)
319 textrenderer = gtk.CellRendererText()
320 titleColumn = gtk.TreeViewColumn("Program")
321 titleColumn.pack_start(textrenderer, expand=True)
322 titleColumn.add_attribute(textrenderer, "text", 1)
324 self._treeView = gtk.TreeView()
325 self._treeView.set_headers_visible(False)
326 self._treeView.set_model(self._programmingModel)
327 self._treeView.append_column(timeColumn)
328 self._treeView.append_column(titleColumn)
329 self._treeView.get_selection().connect("changed", self._on_row_changed)
331 self._treeScroller = gtk.ScrolledWindow()
332 self._treeScroller.add(self._treeView)
333 self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
335 self._presenter = presenter.StreamMiniPresenter(self._store)
336 self._presenterNavigation = presenter.NavigationBox()
337 self._presenterNavigation.toplevel.add(self._presenter.toplevel)
338 self._presenterNavigation.connect("action", self._on_nav_action)
339 self._presenterNavigation.connect("navigating", self._on_navigating)
341 self._radioLayout = gtk.VBox(False)
342 self._radioLayout.pack_start(self._headerNavigation.toplevel, False, False)
343 self._radioLayout.pack_start(self._treeScroller, True, True)
344 self._radioLayout.pack_start(self._presenterNavigation.toplevel, False, True)
346 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
347 self._layout.pack_start(self._radioLayout, True, True)
349 self._window.set_title(self._node.title)
350 self._dateShown = datetime.datetime.now()
353 BasicWindow.show(self)
355 self._errorBanner.toplevel.hide()
356 self._loadingBanner.toplevel.hide()
360 def jump_to(self, node):
361 _moduleLogger.info("Only 1 channel, nothing to jump to")
365 return self._player.node is self._childNode
367 def _set_context(self, state):
368 if state == self._player.STATE_PLAY:
370 self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
372 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
373 elif state == self._player.STATE_PAUSE:
374 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
375 elif state == self._player.STATE_STOP:
376 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
378 _moduleLogger.info("Unhandled player state %s" % state)
379 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
381 def _show_loading(self):
382 animationPath = self._store.STORE_LOOKUP["loading"]
383 animation = self._store.get_pixbuf_animation_from_store(animationPath)
384 self._loadingBanner.show(animation, "Loading...")
386 def _hide_loading(self):
387 self._loadingBanner.hide()
391 self._programmingModel.clear()
392 self._node.get_children(
396 self._set_context(self._player.state)
398 def _get_current_row(self):
399 nowTime = self._dateShown.strftime("%H:%M:%S")
401 for i, row in enumerate(self._programmingModel):
410 @misc_utils.log_exception(_moduleLogger)
411 def _on_player_state_change(self, player, newState):
412 if self._headerNavigation.is_active() or self._presenterNavigation.is_active():
415 self._set_context(newState)
417 @misc_utils.log_exception(_moduleLogger)
418 def _on_player_title_change(self, player, node):
419 if node is not self._childNode or node is None:
420 _moduleLogger.info("Player title magically changed to %s" % player.title)
423 @misc_utils.log_exception(_moduleLogger)
424 def _on_navigating(self, widget, navState):
425 if navState == "clicking":
426 if self._player.state == self._player.STATE_PLAY:
431 elif self._player.state == self._player.STATE_PAUSE:
433 elif self._player.state == self._player.STATE_STOP:
437 _moduleLogger.info("Unhandled player state %s" % self._player.state)
438 elif navState == "down":
440 elif navState == "up":
442 elif navState == "left":
444 elif navState == "right":
447 self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
449 @misc_utils.log_exception(_moduleLogger)
450 def _on_nav_action(self, widget, navState):
451 self._set_context(self._player.state)
453 if navState == "clicking":
454 if self._player.state == self._player.STATE_PLAY:
458 self._player.set_piece_by_node(self._childNode)
460 elif self._player.state == self._player.STATE_PAUSE:
462 elif self._player.state == self._player.STATE_STOP:
463 self._player.set_piece_by_node(self._childNode)
466 _moduleLogger.info("Unhandled player state %s" % self._player.state)
467 elif navState == "down":
468 self.window.destroy()
469 elif navState == "up":
471 elif navState == "left":
472 self._dateShown += datetime.timedelta(days=1)
474 elif navState == "right":
475 self._dateShown -= datetime.timedelta(days=1)
478 @misc_utils.log_exception(_moduleLogger)
479 def _on_channels(self, channels):
480 if self._isDestroyed:
481 _moduleLogger.info("Download complete but window destroyed")
485 if 1 < len(channels):
486 _moduleLogger.warning("More channels now available!")
487 self._childNode = channels[0]
488 self._childNode.get_programming(
494 @misc_utils.log_exception(_moduleLogger)
495 def _on_channel(self, programs):
496 if self._isDestroyed:
497 _moduleLogger.info("Download complete but window destroyed")
501 for program in programs:
502 row = program["time"], program["title"]
503 self._programmingModel.append(row)
505 currentDate = datetime.datetime.now()
506 if currentDate.date() != self._dateShown.date():
507 self._treeView.get_selection().set_mode(gtk.SELECTION_NONE)
509 self._treeView.get_selection().set_mode(gtk.SELECTION_SINGLE)
510 path = (self._get_current_row(), )
511 self._treeView.scroll_to_cell(path)
512 self._treeView.get_selection().select_path(path)
514 @misc_utils.log_exception(_moduleLogger)
515 def _on_load_error(self, exception):
517 self._errorBanner.push_message(str(exception))
519 @misc_utils.log_exception(_moduleLogger)
520 def _on_row_changed(self, selection):
521 if len(self._programmingModel) == 0:
524 rowIndex = self._get_current_row()
526 if not selection.path_is_selected(path):
527 # Undo the user's changing of the selection
528 selection.select_path(path)
531 gobject.type_register(RadioWindow)
534 class ListWindow(BasicWindow):
536 def __init__(self, player, store, node):
537 BasicWindow.__init__(self, player, store)
540 self._loadingBanner = banners.GenericBanner()
542 modelTypes, columns = zip(*self._get_columns())
544 self._model = gtk.ListStore(*modelTypes)
546 self._treeView = gtk.TreeView()
547 self._treeView.connect("row-activated", self._on_row_activated)
548 self._treeView.set_headers_visible(False)
549 self._treeView.set_model(self._model)
550 for column in columns:
551 if column is not None:
552 self._treeView.append_column(column)
554 self._treeScroller = gtk.ScrolledWindow()
555 self._treeScroller.add(self._treeView)
556 self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
558 self._separator = gtk.HSeparator()
559 self._playcontrol = playcontrol.NavControl(self._player, self._store)
560 self._playcontrol.connect("home", self._on_home)
561 self._playcontrol.connect("jump-to", self._on_jump)
563 self._contentLayout = gtk.VBox(False)
564 self._contentLayout.pack_start(self._treeScroller, True, True)
565 self._contentLayout.pack_start(self._separator, False, True)
566 self._contentLayout.pack_start(self._playcontrol.toplevel, False, True)
568 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
569 self._layout.pack_start(self._contentLayout, True, True)
572 BasicWindow.show(self)
574 self._errorBanner.toplevel.hide()
575 self._loadingBanner.toplevel.hide()
578 self._playcontrol.refresh()
581 def _get_columns(cls):
582 raise NotImplementedError("")
584 def _get_current_row(self):
585 if self._player.node is None:
587 ancestors, current, descendants = stream_index.common_paths(self._player.node, self._node)
590 activeChild = descendants[0]
591 for i, row in enumerate(self._model):
592 if activeChild is row[0]:
597 def jump_to(self, node):
598 ancestors, current, descendants = stream_index.common_paths(node, self._node)
600 raise RuntimeError("Cannot jump to node %s" % node)
602 _moduleLogger.info("Current node is the target")
604 child = descendants[0]
605 window = self._window_from_node(child)
608 def _window_from_node(self, node):
609 raise NotImplementedError("")
611 @misc_utils.log_exception(_moduleLogger)
612 def _on_row_activated(self, view, path, column):
613 raise NotImplementedError("")
615 @misc_utils.log_exception(_moduleLogger)
616 def _on_jump(self, source, node):
617 ancestors, current, descendants = stream_index.common_paths(node, self._node)
619 _moduleLogger.info("%s is not the target, moving up" % self._node)
620 self.emit("jump-to", node)
621 self._window.destroy()
624 _moduleLogger.info("Current node is the target")
626 child = descendants[0]
627 window = self._window_from_node(child)
630 def _show_loading(self):
631 animationPath = self._store.STORE_LOOKUP["loading"]
632 animation = self._store.get_pixbuf_animation_from_store(animationPath)
633 self._loadingBanner.show(animation, "Loading...")
635 def _hide_loading(self):
636 self._loadingBanner.hide()
642 def _select_row(self):
643 path = (self._get_current_row(), )
644 self._treeView.scroll_to_cell(path)
645 self._treeView.get_selection().select_path(path)
648 class ConferencesWindow(ListWindow):
650 def __init__(self, player, store, node):
651 ListWindow.__init__(self, player, store, node)
652 self._window.set_title(self._node.title)
655 def _get_columns(cls):
656 yield gobject.TYPE_PYOBJECT, None
658 textrenderer = gtk.CellRendererText()
659 column = gtk.TreeViewColumn("Date")
660 column.pack_start(textrenderer, expand=True)
661 column.add_attribute(textrenderer, "text", 1)
662 yield gobject.TYPE_STRING, column
664 textrenderer = gtk.CellRendererText()
665 column = gtk.TreeViewColumn("Conference")
666 column.pack_start(textrenderer, expand=True)
667 column.add_attribute(textrenderer, "text", 2)
668 yield gobject.TYPE_STRING, column
671 ListWindow._refresh(self)
672 self._node.get_children(
673 self._on_conferences,
677 @misc_utils.log_exception(_moduleLogger)
678 def _on_conferences(self, programs):
679 if self._isDestroyed:
680 _moduleLogger.info("Download complete but window destroyed")
684 for programNode in programs:
685 program = programNode.get_properties()
686 row = programNode, program["title"], program["full_title"]
687 self._model.append(row)
689 path = (self._get_current_row(), )
690 self._treeView.scroll_to_cell(path)
691 self._treeView.get_selection().select_path(path)
693 @misc_utils.log_exception(_moduleLogger)
694 def _on_error(self, exception):
696 self._errorBanner.push_message(str(exception))
698 def _window_from_node(self, node):
699 sessionsWindow = ConferenceSessionsWindow(self._player, self._store, node)
700 sessionsWindow.window.set_modal(True)
701 sessionsWindow.window.set_transient_for(self._window)
702 sessionsWindow.window.set_default_size(*self._window.get_size())
703 sessionsWindow.connect("quit", self._on_quit)
704 sessionsWindow.connect("home", self._on_home)
705 sessionsWindow.connect("jump-to", self._on_jump)
706 sessionsWindow.show()
707 return sessionsWindow
709 @misc_utils.log_exception(_moduleLogger)
710 def _on_row_activated(self, view, path, column):
711 itr = self._model.get_iter(path)
712 node = self._model.get_value(itr, 0)
713 self._window_from_node(node)
716 gobject.type_register(ConferencesWindow)
719 class ConferenceSessionsWindow(ListWindow):
721 def __init__(self, player, store, node):
722 ListWindow.__init__(self, player, store, node)
723 self._window.set_title(self._node.title)
726 def _get_columns(cls):
727 yield gobject.TYPE_PYOBJECT, None
729 textrenderer = gtk.CellRendererText()
730 column = gtk.TreeViewColumn("Session")
731 column.pack_start(textrenderer, expand=True)
732 column.add_attribute(textrenderer, "text", 1)
733 yield gobject.TYPE_STRING, column
736 ListWindow._refresh(self)
737 self._node.get_children(
738 self._on_conference_sessions,
742 @misc_utils.log_exception(_moduleLogger)
743 def _on_conference_sessions(self, programs):
744 if self._isDestroyed:
745 _moduleLogger.info("Download complete but window destroyed")
749 for programNode in programs:
750 program = programNode.get_properties()
751 row = programNode, program["title"]
752 self._model.append(row)
754 path = (self._get_current_row(), )
755 self._treeView.scroll_to_cell(path)
756 self._treeView.get_selection().select_path(path)
758 @misc_utils.log_exception(_moduleLogger)
759 def _on_error(self, exception):
761 self._errorBanner.push_message(str(exception))
763 def _window_from_node(self, node):
764 sessionsWindow = ConferenceTalksWindow(self._player, self._store, node)
765 sessionsWindow.window.set_modal(True)
766 sessionsWindow.window.set_transient_for(self._window)
767 sessionsWindow.window.set_default_size(*self._window.get_size())
768 sessionsWindow.connect("quit", self._on_quit)
769 sessionsWindow.connect("home", self._on_home)
770 sessionsWindow.connect("jump-to", self._on_jump)
771 sessionsWindow.show()
772 return sessionsWindow
774 @misc_utils.log_exception(_moduleLogger)
775 def _on_row_activated(self, view, path, column):
776 itr = self._model.get_iter(path)
777 node = self._model.get_value(itr, 0)
778 self._window_from_node(node)
781 gobject.type_register(ConferenceSessionsWindow)
784 class ConferenceTalksWindow(ListWindow):
786 def __init__(self, player, store, node):
787 ListWindow.__init__(self, player, store, node)
788 self._window.set_title(self._node.title)
791 def _get_columns(cls):
792 yield gobject.TYPE_PYOBJECT, None
794 textrenderer = gtk.CellRendererText()
795 column = gtk.TreeViewColumn("Talk")
796 column.pack_start(textrenderer, expand=True)
797 column.add_attribute(textrenderer, "text", 1)
798 yield gobject.TYPE_STRING, column
801 ListWindow._refresh(self)
802 self._node.get_children(
803 self._on_conference_talks,
807 @misc_utils.log_exception(_moduleLogger)
808 def _on_conference_talks(self, programs):
809 if self._isDestroyed:
810 _moduleLogger.info("Download complete but window destroyed")
814 for programNode in programs:
815 program = programNode.get_properties()
816 row = programNode, "%s\n%s" % (program["title"], program["speaker"])
817 self._model.append(row)
819 path = (self._get_current_row(), )
820 self._treeView.scroll_to_cell(path)
821 self._treeView.get_selection().select_path(path)
823 @misc_utils.log_exception(_moduleLogger)
824 def _on_error(self, exception):
826 self._errorBanner.push_message(str(exception))
828 def _window_from_node(self, node):
829 sessionsWindow = ConferenceTalkWindow(self._player, self._store, node)
830 sessionsWindow.window.set_modal(True)
831 sessionsWindow.window.set_transient_for(self._window)
832 sessionsWindow.window.set_default_size(*self._window.get_size())
833 sessionsWindow.connect("quit", self._on_quit)
834 sessionsWindow.connect("home", self._on_home)
835 sessionsWindow.connect("jump-to", self._on_jump)
836 sessionsWindow.show()
837 return sessionsWindow
839 @misc_utils.log_exception(_moduleLogger)
840 def _on_row_activated(self, view, path, column):
841 itr = self._model.get_iter(path)
842 node = self._model.get_value(itr, 0)
843 self._window_from_node(node)
846 gobject.type_register(ConferenceTalksWindow)
849 class ConferenceTalkWindow(BasicWindow):
851 def __init__(self, player, store, node):
852 BasicWindow.__init__(self, player, store)
855 self._player.connect("state-change", self._on_player_state_change)
856 self._player.connect("title-change", self._on_player_title_change)
857 self._player.connect("error", self._on_player_error)
859 self._loadingBanner = banners.GenericBanner()
861 self._presenter = presenter.StreamPresenter(self._store)
862 self._presenterNavigation = presenter.NavigationBox()
863 self._presenterNavigation.toplevel.add(self._presenter.toplevel)
864 self._presenterNavigation.connect("action", self._on_nav_action)
865 self._presenterNavigation.connect("navigating", self._on_navigating)
867 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
868 self._layout.pack_start(self._presenterNavigation.toplevel, True, True)
870 self._window.set_title(self._node.title)
873 BasicWindow.show(self)
874 self._window.show_all()
875 self._errorBanner.toplevel.hide()
876 self._loadingBanner.toplevel.hide()
878 self._presenter.set_context(
879 self._store.STORE_LOOKUP["conference_background"],
881 self._player.subtitle,
883 self._set_context(self._player.state)
885 def jump_to(self, node):
886 assert self._node is node
890 return self._player.node is self._node
892 def _show_loading(self):
893 animationPath = self._store.STORE_LOOKUP["loading"]
894 animation = self._store.get_pixbuf_animation_from_store(animationPath)
895 self._loadingBanner.show(animation, "Loading...")
897 def _hide_loading(self):
898 self._loadingBanner.hide()
900 def _set_context(self, state):
901 if state == self._player.STATE_PLAY:
903 self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
905 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
906 elif state == self._player.STATE_PAUSE:
907 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
908 elif state == self._player.STATE_STOP:
909 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
911 _moduleLogger.info("Unhandled player state %s" % state)
913 @misc_utils.log_exception(_moduleLogger)
914 def _on_player_state_change(self, player, newState):
915 if self._presenterNavigation.is_active():
918 self._set_context(newState)
920 @misc_utils.log_exception(_moduleLogger)
921 def _on_player_title_change(self, player, node):
922 if node is not self._node or node is None:
923 _moduleLogger.info("Player title magically changed to %s" % player.title)
925 self._presenter.set_context(
926 self._store.STORE_LOOKUP["conference_background"],
928 self._player.subtitle,
931 @misc_utils.log_exception(_moduleLogger)
932 def _on_player_error(self, player, err, debug):
933 _moduleLogger.error("%r - %r" % (err, debug))
935 @misc_utils.log_exception(_moduleLogger)
936 def _on_navigating(self, widget, navState):
937 if navState == "clicking":
938 if self._player.state == self._player.STATE_PLAY:
943 elif self._player.state == self._player.STATE_PAUSE:
945 elif self._player.state == self._player.STATE_STOP:
948 _moduleLogger.info("Unhandled player state %s" % self._player.state)
949 elif navState == "down":
951 elif navState == "up":
953 elif navState == "left":
955 elif navState == "right":
958 self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
960 @misc_utils.log_exception(_moduleLogger)
961 def _on_nav_action(self, widget, navState):
962 self._set_context(self._player.state)
964 if navState == "clicking":
965 if self._player.state == self._player.STATE_PLAY:
969 self._player.set_piece_by_node(self._node)
971 elif self._player.state == self._player.STATE_PAUSE:
973 elif self._player.state == self._player.STATE_STOP:
974 self._player.set_piece_by_node(self._node)
977 _moduleLogger.info("Unhandled player state %s" % self._player.state)
978 elif navState == "down":
980 self._window.destroy()
981 elif navState == "up":
983 elif navState == "left":
985 elif navState == "right":
989 gobject.type_register(ConferenceTalkWindow)