X-Git-Url: http://git.maemo.org/git/?p=watersofshiloah;a=blobdiff_plain;f=src%2Fwindows%2F_base.py;h=8a144898e6a3508468e207ae700e4727de201478;hp=ac81df2823e65d52e9a57e54f01aa63baa39c172;hb=d0799512e99e286826e555b6cfa56fc2200c13a5;hpb=cdf15d55f698ad805313970b9aa245e6a5f77628 diff --git a/src/windows/_base.py b/src/windows/_base.py index ac81df2..8a14489 100644 --- a/src/windows/_base.py +++ b/src/windows/_base.py @@ -2,6 +2,7 @@ from __future__ import with_statement import ConfigParser import logging +import webbrowser import gobject import gtk @@ -13,7 +14,6 @@ import util.go_utils as go_utils import stream_index import banners -import playcontrol import presenter @@ -48,11 +48,17 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN, ), ), + 'rotate' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT, ), + ), } def __init__(self, app, player, store): gobject.GObject.__init__(self) self._isDestroyed = False + self._isPortrait = hildonize.IS_FREMANTLE_SUPPORTED self._app = app self._player = player @@ -64,18 +70,46 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): self._errorBanner = banners.StackingBanner() self._layout = gtk.VBox() - self._layout.pack_start(self._errorBanner.toplevel, False, True) self._window = gtk.Window() - go_utils.AutoSignal.__init__(self, self.window) self._window.add(self._layout) self._window = hildonize.hildonize_window(self._app, self._window) + go_utils.AutoSignal.__init__(self, self.window) self._window.set_icon(self._store.get_pixbuf_from_store(self._store.STORE_LOOKUP["icon"])) self._window.connect("key-press-event", self._on_key_press) self._window.connect("window-state-event", self._on_window_state_change) self._window.connect("destroy", self._on_destroy) + if hildonize.GTK_MENU_USED: + aboutMenuItem = gtk.MenuItem("About") + aboutMenuItem.connect("activate", self._on_about) + + helpMenu = gtk.Menu() + helpMenu.append(aboutMenuItem) + + helpMenuItem = gtk.MenuItem("Help") + helpMenuItem.set_submenu(helpMenu) + + menuBar = gtk.MenuBar() + menuBar.append(helpMenuItem) + + self._layout.pack_start(menuBar, False, False) + menuBar = hildonize.hildonize_menu( + self._window, + menuBar, + ) + else: + aboutMenuItem = gtk.Button("About") + aboutMenuItem.connect("clicked", self._on_about) + + appMenu = hildonize.hildon.AppMenu() + appMenu.append(aboutMenuItem) + appMenu.show_all() + self._window.set_app_menu(appMenu) + + self._layout.pack_start(self._errorBanner.toplevel, False, True) + @property def window(self): return self._window @@ -98,6 +132,7 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): e.section, ) ) + windowInFullscreen = self._windowInFullscreen if windowInFullscreen: self._window.fullscreen() @@ -107,6 +142,45 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): def jump_to(self, node): raise NotImplementedError("On %s" % self) + def set_orientation(self, orientation): + oldIsPortrait = self._isPortrait + if orientation == gtk.ORIENTATION_VERTICAL: + hildonize.window_to_portrait(self._window) + self._isPortrait = True + elif orientation == gtk.ORIENTATION_HORIZONTAL: + hildonize.window_to_landscape(self._window) + self._isPortrait = False + else: + raise NotImplementedError(orientation) + didChange = oldIsPortrait != self._isPortrait + if didChange: + self.emit("rotate", orientation) + return didChange + + def _configure_child(self, childWindow): + if not hildonize.IS_FREMANTLE_SUPPORTED: + childWindow.window.set_modal(True) + childWindow.window.set_transient_for(self._window) + childWindow.window.set_default_size(*self._window.get_size()) + if self._windowInFullscreen: + childWindow.window.fullscreen() + else: + childWindow.window.unfullscreen() + childWindow.set_orientation( + gtk.ORIENTATION_VERTICAL if self._isPortrait else gtk.ORIENTATION_HORIZONTAL + ) + childWindow.connect_auto(childWindow, "quit", self._on_quit) + childWindow.connect_auto(childWindow, "home", self._on_home) + childWindow.connect_auto(childWindow, "jump-to", self._on_jump) + childWindow.connect_auto(childWindow, "fullscreen", self._on_child_fullscreen) + childWindow.connect_auto(childWindow, "rotate", self._on_child_rotate) + + @misc_utils.log_exception(_moduleLogger) + def _on_about(self, *args): + sourceWindow = AboutWindow(self._app, self._player, self._store) + self._configure_child(sourceWindow) + sourceWindow.show() + @misc_utils.log_exception(_moduleLogger) def _on_destroy(self, *args): self._isDestroyed = True @@ -136,6 +210,12 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): else: self._window.fullscreen () return True + elif event.keyval == gtk.keysyms.o and event.get_state() & gtk.gdk.CONTROL_MASK: + if self._isPortrait: + self.set_orientation(gtk.ORIENTATION_HORIZONTAL) + else: + self.set_orientation(gtk.ORIENTATION_VERTICAL) + return True elif ( event.keyval in (gtk.keysyms.w, ) and event.get_state() & gtk.gdk.CONTROL_MASK @@ -169,6 +249,10 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal): self._window.unfullscreen() @misc_utils.log_exception(_moduleLogger) + def _on_child_rotate(self, source, orientation): + self.set_orientation(orientation) + + @misc_utils.log_exception(_moduleLogger) def _on_jump(self, source, node): raise NotImplementedError("On %s" % self) @@ -210,14 +294,14 @@ class ListWindow(BasicWindow): self._treeScroller = hildonize.hildonize_scrollwindow(self._treeScroller) self._separator = gtk.HSeparator() - self._playcontrol = playcontrol.NavControl(self._player, self._store) - self._playcontrol.connect("home", self._on_home) - self._playcontrol.connect("jump-to", self._on_jump) + self._presenter = presenter.NavControl(self._player, self._store) + self.connect_auto(self._presenter, "home", self._on_home) + self.connect_auto(self._presenter, "jump-to", self._on_jump) self._contentLayout = gtk.VBox(False) self._contentLayout.pack_start(self._treeScroller, True, True) self._contentLayout.pack_start(self._separator, False, True) - self._contentLayout.pack_start(self._playcontrol.toplevel, False, True) + self._contentLayout.pack_start(self._presenter.toplevel, False, True) self._layout.pack_start(self._loadingBanner.toplevel, False, False) self._layout.pack_start(self._contentLayout, True, True) @@ -229,7 +313,7 @@ class ListWindow(BasicWindow): self._loadingBanner.toplevel.hide() self._refresh() - self._playcontrol.refresh() + self._presenter.refresh() @classmethod def _get_columns(cls): @@ -270,6 +354,7 @@ class ListWindow(BasicWindow): @misc_utils.log_exception(_moduleLogger) def _on_player_title_change(self, player, node): + assert not self._isDestroyed self._select_row() @misc_utils.log_exception(_moduleLogger) @@ -350,14 +435,16 @@ class PresenterWindow(BasicWindow): self._presenter = presenter.StreamPresenter(self._store) self._presenter.set_context( - self._get_background(), + self._get_background( + gtk.ORIENTATION_VERTICAL if self._isPortrait else gtk.ORIENTATION_HORIZONTAL + ), self._node.title, self._node.subtitle, ) self._presenterNavigation = presenter.NavigationBox() self._presenterNavigation.toplevel.add(self._presenter.toplevel) - self._presenterNavigation.connect("action", self._on_nav_action) - self._presenterNavigation.connect("navigating", self._on_navigating) + self.connect_auto(self._presenterNavigation, "action", self._on_nav_action) + self.connect_auto(self._presenterNavigation, "navigating", self._on_navigating) self._seekbar = hildonize.create_seekbar() self._seekbar.connect("change-value", self._on_user_seek) @@ -366,9 +453,9 @@ class PresenterWindow(BasicWindow): self._layout.pack_start(self._presenterNavigation.toplevel, True, True) self._layout.pack_start(self._seekbar, False, False) - self._window.set_title(self._node.title) + self._window.set_title(self._node.get_parent().title) - def _get_background(self): + def _get_background(self, orientation): raise NotImplementedError() def show(self): @@ -382,6 +469,16 @@ class PresenterWindow(BasicWindow): def jump_to(self, node): assert self._node is node + def set_orientation(self, orientation): + didChange = BasicWindow.set_orientation(self, orientation) + if didChange: + self._presenter.set_orientation(orientation) + self._presenter.set_context( + self._get_background(orientation), + self._node.title, + self._node.subtitle, + ) + @property def _active(self): return self._playerNode is self._node @@ -420,6 +517,7 @@ class PresenterWindow(BasicWindow): @misc_utils.log_exception(_moduleLogger) def _on_player_state_change(self, player, newState): + assert not self._isDestroyed if self._active and self._player.state == self._player.STATE_PLAY: self._seekbar.show() assert self._updateSeek is None @@ -436,6 +534,7 @@ class PresenterWindow(BasicWindow): @misc_utils.log_exception(_moduleLogger) def _on_player_title_change(self, player, node): + assert not self._isDestroyed if not self._active or node in [None, self._node]: self._playerNode = node return @@ -445,6 +544,7 @@ class PresenterWindow(BasicWindow): @misc_utils.log_exception(_moduleLogger) def _on_player_error(self, player, err, debug): + assert not self._isDestroyed _moduleLogger.error("%r - %r" % (err, debug)) @misc_utils.log_exception(_moduleLogger) @@ -530,3 +630,73 @@ class PresenterWindow(BasicWindow): def _on_node_search_error(self, e): self._nextSearch = None self._errorBanner.push_message(str(e)) + + +class AboutWindow(BasicWindow): + + def __init__(self, app, player, store): + BasicWindow.__init__(self, app, player, store) + self._window.set_title(constants.__pretty_app_name__) + + self._titleLabel = gtk.Label() + self._titleLabel.set_markup(""" +Waters of Shiloah +Maemo Edition +Version %s +""" % (constants.__version__, )) + self._titleLabel.set_property("justify", gtk.JUSTIFY_CENTER) + + self._copyLabel = gtk.Label() + self._copyLabel.set_markup(""" +Developed by: Ed Page +Images by: Various Sources, See COPYING for author and license information (mix of various CC licenses, commercial, and non-commercial +This application nor various images are not endorsed by The Church of Jesus Christ of Latter-day Saints +""") + self._copyLabel.set_property("justify", gtk.JUSTIFY_CENTER) + + self._linkButton = gtk.LinkButton("http://watersofshiloah.garage.maemo.org") + self._linkButton.set_label("Waters of Shiloah") + self._linkButton.connect("clicked", self._on_website) + + self._radioLinkButton = gtk.LinkButton("http://radio.lds.org") + self._radioLinkButton.set_label("Mormon Channel") + self._radioLinkButton.connect("clicked", self._on_website) + + self._ldsLinkButton = gtk.LinkButton("http://www.lds.org") + self._ldsLinkButton.set_label("LDS.org") + self._ldsLinkButton.connect("clicked", self._on_website) + + self._spacedLayout = gtk.VBox(True) + self._spacedLayout.pack_start(self._titleLabel, False, False) + self._spacedLayout.pack_start(self._copyLabel, False, False) + self._spacedLayout.pack_start(self._linkButton, False, False) + self._spacedLayout.pack_start(self._radioLinkButton, False, False) + self._spacedLayout.pack_start(self._ldsLinkButton, False, False) + + self._separator = gtk.HSeparator() + self._presenter = presenter.NavControl(self._player, self._store) + self.connect_auto(self._presenter, "home", self._on_home) + self.connect_auto(self._presenter, "jump-to", self._on_jump) + + self._layout.pack_start(self._spacedLayout, True, True) + self._layout.pack_start(self._presenter.toplevel, False, True) + + def show(self): + BasicWindow.show(self) + self._window.show_all() + self._errorBanner.toplevel.hide() + self._presenter.refresh() + + @misc_utils.log_exception(_moduleLogger) + def _on_about(self, *args): + pass + + @misc_utils.log_exception(_moduleLogger) + def _on_website(self, widget): + uri = widget.get_uri() + webbrowser.open(uri) + + @misc_utils.log_exception(_moduleLogger) + def _on_jump(self, source, node): + self.emit("jump-to", node) + self._window.destroy()