Fixing a Maemo 5 issue
[watersofshiloah] / src / windows / _base.py
index d855fd8..8a14489 100644 (file)
@@ -2,6 +2,7 @@ from __future__ import with_statement
 
 import ConfigParser
 import logging
+import webbrowser
 
 import gobject
 import gtk
@@ -47,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
@@ -63,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
@@ -97,6 +132,7 @@ class BasicWindow(gobject.GObject, go_utils.AutoSignal):
                                        e.section,
                                )
                        )
+                       windowInFullscreen = self._windowInFullscreen
 
                if windowInFullscreen:
                        self._window.fullscreen()
@@ -106,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
@@ -135,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
@@ -168,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,8 +295,8 @@ class ListWindow(BasicWindow):
 
                self._separator = gtk.HSeparator()
                self._presenter = presenter.NavControl(self._player, self._store)
-               self._presenter.connect("home", self._on_home)
-               self._presenter.connect("jump-to", self._on_jump)
+               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)
@@ -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
@@ -533,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("""
+<big><b>Waters of Shiloah</b></big>
+<i>Maemo Edition</i>
+Version %s
+""" % (constants.__version__, ))
+               self._titleLabel.set_property("justify", gtk.JUSTIFY_CENTER)
+
+               self._copyLabel = gtk.Label()
+               self._copyLabel.set_markup("""
+<small>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</small>
+""")
+               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()