VERSION 0.1.4 faire un .deb
authorJuke <juke@free.fr>
Mon, 8 Feb 2010 23:44:25 +0000 (00:44 +0100)
committerJuke <juke@free.fr>
Mon, 8 Feb 2010 23:44:25 +0000 (00:44 +0100)
TODO
example.cfg [deleted file]
gtk_transilien.py [deleted file]
portrait.py [deleted file]
src/example.cfg [new file with mode: 0644]
src/masstransit.py [new file with mode: 0755]
src/portrait.py [new file with mode: 0644]

diff --git a/TODO b/TODO
index 63914b4..2cc4fbd 100644 (file)
--- a/TODO
+++ b/TODO
     TODO : faire des try sur les import
     TODO : documenter les classes
     
-    
     DONE 0.1.1 : Mod√©lisation Objet
     DONE 0.1.2 : Corriger l'indentation
     DONE 0.1.3 : Faire un objet ListeHoraire
-    
-    
-
-
-
-
+    DONE 0.1.4 : Faire un .deb
diff --git a/example.cfg b/example.cfg
deleted file mode 100644 (file)
index b7d87ce..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[ListeDesGares]
-bibliotheque francois mitterand = BFM
-savigny sur orge  = SAO
-melun = MEL
-juvisy = JY
-gare de lyon = PAA
-chatelet = CLX
-villeneuve st georges = VSG
-le mee = WEE
-
diff --git a/gtk_transilien.py b/gtk_transilien.py
deleted file mode 100755 (executable)
index 85d9406..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/python
-import pygtk
-pygtk.require("2.0")
-import gtk
-import urllib2
-import HTMLParser
-import hildon
-import ConfigParser
-
-from portrait import FremantleRotation
-
-#main_window = mainWindow # your main hildon.StackableWindow
-app_name = 'NameOfYourApp' # the name of your app
-app_version = '1.0' # the version number of your app
-initial_mode = FremantleRotation.AUTOMATIC
-
-class LigneHoraire(object):
-    def __init__(self, code_mission, heure_de_passage):
-        self.code_mission = code_mission
-        self.heure_de_passage = heure_de_passage
-    
-    def add_to_treestore(self, treestore):
-        print treestore
-        treestore.append(None, [self.code_mission, self.heure_de_passage])
-    
-    
-
-class tableParser(HTMLParser.HTMLParser):
-    def __init__(self):
-        HTMLParser.HTMLParser.__init__(self)
-        self.table_horaires3 = False
-        self.code_de_mission = False
-        self.a_code_de_mission = False
-        self.heure_de_passage = False
-        self.liste_train = []
-        self.liste_horaire = []
-        self.list_ligne_horaire = []
-        
-    def handle_starttag(self, tag, attrs):
-        if (tag == 'table' and (dict(attrs)['class'] == 'horaires3')):
-            self.table_horaires3 = True
-        
-        elif self.table_horaires3 and tag == 'td':
-            try:
-                self.code_de_mission = (
-                    dict(attrs)['headers'] == 'Code_de_mission')
-                self.heure_de_passage = (
-                    dict(attrs)['headers'] == 'Heure_de_passage')
-            except KeyError:
-                if dict(attrs).has_key('headers'):
-                    raise
-                else:
-                    pass
-        else:
-            self.a_code_de_mission = (tag == 'a' and self.code_de_mission)
-        
-    def handle_data(self, data):
-        if self.a_code_de_mission:
-            self.liste_train.append(data.strip())
-        if self.heure_de_passage:
-            self.liste_horaire.append(data.strip())
-            
-    def handle_endtag(self,tag):
-        self.a_code_de_mission ^= (self.a_code_de_mission and tag == 'a')
-        self.heure_de_passage ^= (self.heure_de_passage and tag == 'td')
-    
-    def get_list_ligne_horaire(self):
-        print 'get_list_ligne_horaire'
-        z = 0
-        print self.liste_train
-        for i in self.liste_train:
-            self.list_ligne_horaire.append(LigneHoraire(code_mission=i, heure_de_passage=self.liste_horaire[z]))
-            z += 1
-        return self.list_ligne_horaire
-    
-    
-
-class Trajet(object):
-    def __init__(self, gare_source, gare_dest):
-        self.gare_source = gare_source
-        self.gare_dest = gare_dest
-        self.parse() 
-    def get_liste_train(self):
-        return self.p.liste_train 
-    def get_liste_horaire(self): 
-        return self.p.liste_horaire
-    def parse(self):
-        self.p = tableParser()
-        #print "URL:" 
-        #print 'http://www.transilien.com/web/ITProchainsTrainsAvecDest.do?codeTr3aDepart='+self.gare_source.shortname+'&codeTr3aDest='+self.gare_dest.shortname+'&urlModule=/site/pid/184&gareAcc=true'
-        rsrc = urllib2.urlopen('http://www.transilien.com/web/ITProchainsTrainsAvecDest.do?codeTr3aDepart='+self.gare_source.shortname+'&codeTr3aDest='+self.gare_dest.shortname+'&urlModule=/site/pid/184&gareAcc=true')
-        self.p.feed(rsrc.read())
-        print "parsing ok"
-        
-    def refresh_treestore(self, treestore):
-        print 'refresh'
-        print treestore
-        
-        treestore.clear()
-        liste_ligne_horaire = self.p.get_list_ligne_horaire()
-        print liste_ligne_horaire
-        for i in liste_ligne_horaire:
-            print i
-            i.add_to_treestore(treestore)
-
-class ConfFile(object):
-    def __init__(self, fichier):
-        self.c = ConfigParser.ConfigParser()
-        self.c.read(fichier)
-    def get_short_name(self, longname):
-        return self.c.get('ListeDesGares', longname)
-    def get_liste_des_gares(self):
-        return self.c.items('ListeDesGares') 
-
-class LongNameGare(object):
-    def __init__(self, longname):
-        self.longname = longname
-    def get_gare(self, conffile):
-        short_name = conffile.get_short_name(self.longname)
-        return Gare(short_name)
-
-class Gare(object):
-    def __init__(self, shortname):
-        self.shortname = shortname
-
-
-
-
-class TransilienUI:
-    def __init__(self):
-        mainWindow = hildon.Window()
-        mainWindow.set_title("Horaires des Prochains Trains")
-        mainWindow.connect("destroy", self.on_mainWindow_destroy)
-
-        rotation_object = FremantleRotation(app_name, mainWindow, app_version, initial_mode)
-        refreshButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT,
-                              hildon.BUTTON_ARRANGEMENT_HORIZONTAL, "Actualiser")
-        refreshButton.connect("clicked", self.on_refreshButton_clicked)
-
-        self.treestore = gtk.TreeStore(str, str)
-        self.treeview = gtk.TreeView(self.treestore)
-
-        self.tvcolumn_train = gtk.TreeViewColumn('Train', gtk.CellRendererText(), text=0)
-        self.treeview.append_column(self.tvcolumn_train)
-        
-        self.tvcolumn_horaire = gtk.TreeViewColumn('Horaire', gtk.CellRendererText(), text=1)
-        self.treeview.append_column(self.tvcolumn_horaire)
-
-
-        picker_button_source = hildon.PickerButton(gtk.HILDON_SIZE_AUTO,                            hildon.BUTTON_ARRANGEMENT_VERTICAL)
-        picker_button_source.set_title("Gare de Depart")
-        self.combo_source = hildon.TouchSelectorEntry(text=True)
-        self.combo_dest = hildon.TouchSelectorEntry(text=True)
-
-        for i in ConfFile('example.cfg').get_liste_des_gares():
-            self.combo_source.append_text(i[0])
-            self.combo_dest.append_text(i[0])
-        picker_button_source.set_selector(self.combo_source)
-        
-
-        picker_button_dest = hildon.PickerButton(gtk.HILDON_SIZE_AUTO,                            hildon.BUTTON_ARRANGEMENT_VERTICAL)
-        picker_button_dest.set_title("Gare d'arrivee")
-        picker_button_dest.set_selector(self.combo_dest)
-        
-        vBox = gtk.VBox()
-        hBox = gtk.HBox()
-        vBox.pack_start(hBox)
-        hBox.pack_start(picker_button_source)
-        hBox.pack_start(picker_button_dest)
-        vBox.pack_start(self.treeview)
-        vBox.pack_start(refreshButton)
-        
-
-        mainWindow.add(vBox)
-        mainWindow.show_all()
-
-    def on_mainWindow_destroy(self, widget):
-        gtk.main_quit()
-
-    def on_refreshButton_clicked(self, widget):
-        gare_source = LongNameGare(self.combo_source.get_current_text()).get_gare(ConfFile('example.cfg'))
-        gare_dest = LongNameGare(self.combo_dest.get_current_text()).get_gare(ConfFile('example.cfg'))
-        trajet = Trajet(gare_source , gare_dest)
-        print trajet
-        print self.treestore
-        trajet.refresh_treestore(self.treestore)
-
-
-if __name__ == "__main__":
-    TransilienUI()
-    gtk.main()
diff --git a/portrait.py b/portrait.py
deleted file mode 100644 (file)
index ce16aa8..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# gPodder - A media aggregator and podcast client
-# Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
-#
-# gPodder is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# gPodder is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-import dbus
-import dbus.glib
-
-import hildon
-import osso
-
-# Replace this with your own gettext() functionality
-import gpodder
-_ = gpodder.gettext
-
-
-class FremantleRotation(object):
-    """thp's screen rotation for Maemo 5
-
-    Simply instantiate an object of this class and let it auto-rotate
-    your StackableWindows depending on the device orientation.
-
-    If you need to relayout a window, connect to its "configure-event"
-    signal and measure the ratio of width/height and relayout for that.
-
-    You can set the mode for rotation to AUTOMATIC (default), NEVER or
-    ALWAYS with the set_mode() method.
-    """
-    AUTOMATIC, NEVER, ALWAYS = range(3)
-
-    # Human-readable captions for the above constants
-    MODE_CAPTIONS = (_('Automatic'), _('Landscape'), _('Portrait'))
-
-    # Privately-used constants
-    _PORTRAIT, _LANDSCAPE = ('portrait', 'landscape')
-    _ENABLE_ACCEL = 'req_accelerometer_enable'
-    _DISABLE_ACCEL = 'req_accelerometer_disable'
-
-    # Defined in mce/dbus-names.h
-    _MCE_SERVICE = 'com.nokia.mce'
-    _MCE_REQUEST_PATH = '/com/nokia/mce/request'
-    _MCE_REQUEST_IF = 'com.nokia.mce.request'
-
-    def __init__(self, app_name, main_window=None, version='1.0', mode=0):
-        """Create a new rotation manager
-
-        app_name    ... The name of your application (for osso.Context)
-        main_window ... The root window (optional, hildon.StackableWindow)
-        version     ... The version of your application (optional, string)
-        mode        ... Initial mode for this manager (default: AUTOMATIC)
-        """
-        self._orientation = None
-        self._main_window = main_window
-        self._stack = hildon.WindowStack.get_default()
-        self._mode = -1
-        self._last_dbus_orientation = None
-        app_id = '-'.join((app_name, self.__class__.__name__))
-        self._osso_context = osso.Context(app_id, version, False)
-        program = hildon.Program.get_instance()
-        program.connect('notify::is-topmost', self._on_topmost_changed)
-        system_bus = dbus.Bus.get_system()
-        system_bus.add_signal_receiver(self._on_orientation_signal, \
-                signal_name='sig_device_orientation_ind', \
-                dbus_interface='com.nokia.mce.signal', \
-                path='/com/nokia/mce/signal')
-        self.set_mode(mode)
-
-    def get_mode(self):
-        """Get the currently-set rotation mode
-
-        This will return one of three values: AUTOMATIC, ALWAYS or NEVER.
-        """
-        return self._mode
-
-    def set_mode(self, new_mode):
-        """Set the rotation mode
-
-        You can set the rotation mode to AUTOMATIC (use hardware rotation
-        info), ALWAYS (force portrait) and NEVER (force landscape).
-        """
-        if new_mode not in (self.AUTOMATIC, self.ALWAYS, self.NEVER):
-            raise ValueError('Unknown rotation mode')
-
-        if self._mode != new_mode:
-            if self._mode == self.AUTOMATIC:
-                # Remember the current "automatic" orientation for later
-                self._last_dbus_orientation = self._orientation
-                # Tell MCE that we don't need the accelerometer anymore
-                self._send_mce_request(self._DISABLE_ACCEL)
-
-            if new_mode == self.NEVER:
-                self._orientation_changed(self._LANDSCAPE)
-            elif new_mode == self.ALWAYS:
-                self._orientation_changed(self._PORTRAIT)
-            elif new_mode == self.AUTOMATIC:
-                # Restore the last-known "automatic" orientation
-                self._orientation_changed(self._last_dbus_orientation)
-                # Tell MCE that we need the accelerometer again
-                self._send_mce_request(self._ENABLE_ACCEL)
-
-            self._mode = new_mode
-
-    def _send_mce_request(self, request):
-        rpc = osso.Rpc(self._osso_context)
-        rpc.rpc_run(self._MCE_SERVICE, \
-                    self._MCE_REQUEST_PATH, \
-                    self._MCE_REQUEST_IF, \
-                    request, \
-                    use_system_bus=True)
-
-    def _on_topmost_changed(self, program, property_spec):
-        # XXX: This seems to never get called on Fremantle(?)
-        if self._mode == self.AUTOMATIC:
-            if program.get_is_topmost():
-                self._send_mce_request(self._ENABLE_ACCEL)
-            else:
-                self._send_mce_request(self._DISABLE_ACCEL)
-
-    def _get_main_window(self):
-        if self._main_window:
-            # If we have gotten the main window as parameter, return it and
-            # don't try "harder" to find another window using the stack
-            return self._main_window
-        else:
-            # The main window is at the "bottom" of the window stack, and as
-            # the list we get with get_windows() is sorted "topmost first", we
-            # simply take the last item of the list to get our main window
-            windows = self._stack.get_windows()
-            if windows:
-                return windows[-1]
-            else:
-                return None
-
-    def _orientation_changed(self, orientation):
-        if self._orientation == orientation:
-            # Ignore repeated requests
-            return
-
-        flags = hildon.PORTRAIT_MODE_SUPPORT
-        if orientation == self._PORTRAIT:
-            flags |= hildon.PORTRAIT_MODE_REQUEST
-
-        window = self._get_main_window()
-        if window is not None:
-            hildon.hildon_gtk_window_set_portrait_flags(window, flags)
-
-        self._orientation = orientation
-
-    def _on_orientation_signal(self, orientation, stand, face, x, y, z):
-        if orientation in (self._PORTRAIT, self._LANDSCAPE):
-            if self._mode == self.AUTOMATIC:
-                # Automatically set the rotation based on hardware orientation
-                self._orientation_changed(orientation)
-            else:
-                # Ignore orientation changes for non-automatic modes, but save
-                # the current orientation for "automatic" mode later on
-                self._last_dbus_orientation = orientation
-
diff --git a/src/example.cfg b/src/example.cfg
new file mode 100644 (file)
index 0000000..b7d87ce
--- /dev/null
@@ -0,0 +1,10 @@
+[ListeDesGares]
+bibliotheque francois mitterand = BFM
+savigny sur orge  = SAO
+melun = MEL
+juvisy = JY
+gare de lyon = PAA
+chatelet = CLX
+villeneuve st georges = VSG
+le mee = WEE
+
diff --git a/src/masstransit.py b/src/masstransit.py
new file mode 100755 (executable)
index 0000000..85d9406
--- /dev/null
@@ -0,0 +1,191 @@
+#!/usr/bin/python
+import pygtk
+pygtk.require("2.0")
+import gtk
+import urllib2
+import HTMLParser
+import hildon
+import ConfigParser
+
+from portrait import FremantleRotation
+
+#main_window = mainWindow # your main hildon.StackableWindow
+app_name = 'NameOfYourApp' # the name of your app
+app_version = '1.0' # the version number of your app
+initial_mode = FremantleRotation.AUTOMATIC
+
+class LigneHoraire(object):
+    def __init__(self, code_mission, heure_de_passage):
+        self.code_mission = code_mission
+        self.heure_de_passage = heure_de_passage
+    
+    def add_to_treestore(self, treestore):
+        print treestore
+        treestore.append(None, [self.code_mission, self.heure_de_passage])
+    
+    
+
+class tableParser(HTMLParser.HTMLParser):
+    def __init__(self):
+        HTMLParser.HTMLParser.__init__(self)
+        self.table_horaires3 = False
+        self.code_de_mission = False
+        self.a_code_de_mission = False
+        self.heure_de_passage = False
+        self.liste_train = []
+        self.liste_horaire = []
+        self.list_ligne_horaire = []
+        
+    def handle_starttag(self, tag, attrs):
+        if (tag == 'table' and (dict(attrs)['class'] == 'horaires3')):
+            self.table_horaires3 = True
+        
+        elif self.table_horaires3 and tag == 'td':
+            try:
+                self.code_de_mission = (
+                    dict(attrs)['headers'] == 'Code_de_mission')
+                self.heure_de_passage = (
+                    dict(attrs)['headers'] == 'Heure_de_passage')
+            except KeyError:
+                if dict(attrs).has_key('headers'):
+                    raise
+                else:
+                    pass
+        else:
+            self.a_code_de_mission = (tag == 'a' and self.code_de_mission)
+        
+    def handle_data(self, data):
+        if self.a_code_de_mission:
+            self.liste_train.append(data.strip())
+        if self.heure_de_passage:
+            self.liste_horaire.append(data.strip())
+            
+    def handle_endtag(self,tag):
+        self.a_code_de_mission ^= (self.a_code_de_mission and tag == 'a')
+        self.heure_de_passage ^= (self.heure_de_passage and tag == 'td')
+    
+    def get_list_ligne_horaire(self):
+        print 'get_list_ligne_horaire'
+        z = 0
+        print self.liste_train
+        for i in self.liste_train:
+            self.list_ligne_horaire.append(LigneHoraire(code_mission=i, heure_de_passage=self.liste_horaire[z]))
+            z += 1
+        return self.list_ligne_horaire
+    
+    
+
+class Trajet(object):
+    def __init__(self, gare_source, gare_dest):
+        self.gare_source = gare_source
+        self.gare_dest = gare_dest
+        self.parse() 
+    def get_liste_train(self):
+        return self.p.liste_train 
+    def get_liste_horaire(self): 
+        return self.p.liste_horaire
+    def parse(self):
+        self.p = tableParser()
+        #print "URL:" 
+        #print 'http://www.transilien.com/web/ITProchainsTrainsAvecDest.do?codeTr3aDepart='+self.gare_source.shortname+'&codeTr3aDest='+self.gare_dest.shortname+'&urlModule=/site/pid/184&gareAcc=true'
+        rsrc = urllib2.urlopen('http://www.transilien.com/web/ITProchainsTrainsAvecDest.do?codeTr3aDepart='+self.gare_source.shortname+'&codeTr3aDest='+self.gare_dest.shortname+'&urlModule=/site/pid/184&gareAcc=true')
+        self.p.feed(rsrc.read())
+        print "parsing ok"
+        
+    def refresh_treestore(self, treestore):
+        print 'refresh'
+        print treestore
+        
+        treestore.clear()
+        liste_ligne_horaire = self.p.get_list_ligne_horaire()
+        print liste_ligne_horaire
+        for i in liste_ligne_horaire:
+            print i
+            i.add_to_treestore(treestore)
+
+class ConfFile(object):
+    def __init__(self, fichier):
+        self.c = ConfigParser.ConfigParser()
+        self.c.read(fichier)
+    def get_short_name(self, longname):
+        return self.c.get('ListeDesGares', longname)
+    def get_liste_des_gares(self):
+        return self.c.items('ListeDesGares') 
+
+class LongNameGare(object):
+    def __init__(self, longname):
+        self.longname = longname
+    def get_gare(self, conffile):
+        short_name = conffile.get_short_name(self.longname)
+        return Gare(short_name)
+
+class Gare(object):
+    def __init__(self, shortname):
+        self.shortname = shortname
+
+
+
+
+class TransilienUI:
+    def __init__(self):
+        mainWindow = hildon.Window()
+        mainWindow.set_title("Horaires des Prochains Trains")
+        mainWindow.connect("destroy", self.on_mainWindow_destroy)
+
+        rotation_object = FremantleRotation(app_name, mainWindow, app_version, initial_mode)
+        refreshButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT,
+                              hildon.BUTTON_ARRANGEMENT_HORIZONTAL, "Actualiser")
+        refreshButton.connect("clicked", self.on_refreshButton_clicked)
+
+        self.treestore = gtk.TreeStore(str, str)
+        self.treeview = gtk.TreeView(self.treestore)
+
+        self.tvcolumn_train = gtk.TreeViewColumn('Train', gtk.CellRendererText(), text=0)
+        self.treeview.append_column(self.tvcolumn_train)
+        
+        self.tvcolumn_horaire = gtk.TreeViewColumn('Horaire', gtk.CellRendererText(), text=1)
+        self.treeview.append_column(self.tvcolumn_horaire)
+
+
+        picker_button_source = hildon.PickerButton(gtk.HILDON_SIZE_AUTO,                            hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        picker_button_source.set_title("Gare de Depart")
+        self.combo_source = hildon.TouchSelectorEntry(text=True)
+        self.combo_dest = hildon.TouchSelectorEntry(text=True)
+
+        for i in ConfFile('example.cfg').get_liste_des_gares():
+            self.combo_source.append_text(i[0])
+            self.combo_dest.append_text(i[0])
+        picker_button_source.set_selector(self.combo_source)
+        
+
+        picker_button_dest = hildon.PickerButton(gtk.HILDON_SIZE_AUTO,                            hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        picker_button_dest.set_title("Gare d'arrivee")
+        picker_button_dest.set_selector(self.combo_dest)
+        
+        vBox = gtk.VBox()
+        hBox = gtk.HBox()
+        vBox.pack_start(hBox)
+        hBox.pack_start(picker_button_source)
+        hBox.pack_start(picker_button_dest)
+        vBox.pack_start(self.treeview)
+        vBox.pack_start(refreshButton)
+        
+
+        mainWindow.add(vBox)
+        mainWindow.show_all()
+
+    def on_mainWindow_destroy(self, widget):
+        gtk.main_quit()
+
+    def on_refreshButton_clicked(self, widget):
+        gare_source = LongNameGare(self.combo_source.get_current_text()).get_gare(ConfFile('example.cfg'))
+        gare_dest = LongNameGare(self.combo_dest.get_current_text()).get_gare(ConfFile('example.cfg'))
+        trajet = Trajet(gare_source , gare_dest)
+        print trajet
+        print self.treestore
+        trajet.refresh_treestore(self.treestore)
+
+
+if __name__ == "__main__":
+    TransilienUI()
+    gtk.main()
diff --git a/src/portrait.py b/src/portrait.py
new file mode 100644 (file)
index 0000000..ce16aa8
--- /dev/null
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+#
+# gPodder - A media aggregator and podcast client
+# Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
+#
+# gPodder is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# gPodder is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import dbus
+import dbus.glib
+
+import hildon
+import osso
+
+# Replace this with your own gettext() functionality
+import gpodder
+_ = gpodder.gettext
+
+
+class FremantleRotation(object):
+    """thp's screen rotation for Maemo 5
+
+    Simply instantiate an object of this class and let it auto-rotate
+    your StackableWindows depending on the device orientation.
+
+    If you need to relayout a window, connect to its "configure-event"
+    signal and measure the ratio of width/height and relayout for that.
+
+    You can set the mode for rotation to AUTOMATIC (default), NEVER or
+    ALWAYS with the set_mode() method.
+    """
+    AUTOMATIC, NEVER, ALWAYS = range(3)
+
+    # Human-readable captions for the above constants
+    MODE_CAPTIONS = (_('Automatic'), _('Landscape'), _('Portrait'))
+
+    # Privately-used constants
+    _PORTRAIT, _LANDSCAPE = ('portrait', 'landscape')
+    _ENABLE_ACCEL = 'req_accelerometer_enable'
+    _DISABLE_ACCEL = 'req_accelerometer_disable'
+
+    # Defined in mce/dbus-names.h
+    _MCE_SERVICE = 'com.nokia.mce'
+    _MCE_REQUEST_PATH = '/com/nokia/mce/request'
+    _MCE_REQUEST_IF = 'com.nokia.mce.request'
+
+    def __init__(self, app_name, main_window=None, version='1.0', mode=0):
+        """Create a new rotation manager
+
+        app_name    ... The name of your application (for osso.Context)
+        main_window ... The root window (optional, hildon.StackableWindow)
+        version     ... The version of your application (optional, string)
+        mode        ... Initial mode for this manager (default: AUTOMATIC)
+        """
+        self._orientation = None
+        self._main_window = main_window
+        self._stack = hildon.WindowStack.get_default()
+        self._mode = -1
+        self._last_dbus_orientation = None
+        app_id = '-'.join((app_name, self.__class__.__name__))
+        self._osso_context = osso.Context(app_id, version, False)
+        program = hildon.Program.get_instance()
+        program.connect('notify::is-topmost', self._on_topmost_changed)
+        system_bus = dbus.Bus.get_system()
+        system_bus.add_signal_receiver(self._on_orientation_signal, \
+                signal_name='sig_device_orientation_ind', \
+                dbus_interface='com.nokia.mce.signal', \
+                path='/com/nokia/mce/signal')
+        self.set_mode(mode)
+
+    def get_mode(self):
+        """Get the currently-set rotation mode
+
+        This will return one of three values: AUTOMATIC, ALWAYS or NEVER.
+        """
+        return self._mode
+
+    def set_mode(self, new_mode):
+        """Set the rotation mode
+
+        You can set the rotation mode to AUTOMATIC (use hardware rotation
+        info), ALWAYS (force portrait) and NEVER (force landscape).
+        """
+        if new_mode not in (self.AUTOMATIC, self.ALWAYS, self.NEVER):
+            raise ValueError('Unknown rotation mode')
+
+        if self._mode != new_mode:
+            if self._mode == self.AUTOMATIC:
+                # Remember the current "automatic" orientation for later
+                self._last_dbus_orientation = self._orientation
+                # Tell MCE that we don't need the accelerometer anymore
+                self._send_mce_request(self._DISABLE_ACCEL)
+
+            if new_mode == self.NEVER:
+                self._orientation_changed(self._LANDSCAPE)
+            elif new_mode == self.ALWAYS:
+                self._orientation_changed(self._PORTRAIT)
+            elif new_mode == self.AUTOMATIC:
+                # Restore the last-known "automatic" orientation
+                self._orientation_changed(self._last_dbus_orientation)
+                # Tell MCE that we need the accelerometer again
+                self._send_mce_request(self._ENABLE_ACCEL)
+
+            self._mode = new_mode
+
+    def _send_mce_request(self, request):
+        rpc = osso.Rpc(self._osso_context)
+        rpc.rpc_run(self._MCE_SERVICE, \
+                    self._MCE_REQUEST_PATH, \
+                    self._MCE_REQUEST_IF, \
+                    request, \
+                    use_system_bus=True)
+
+    def _on_topmost_changed(self, program, property_spec):
+        # XXX: This seems to never get called on Fremantle(?)
+        if self._mode == self.AUTOMATIC:
+            if program.get_is_topmost():
+                self._send_mce_request(self._ENABLE_ACCEL)
+            else:
+                self._send_mce_request(self._DISABLE_ACCEL)
+
+    def _get_main_window(self):
+        if self._main_window:
+            # If we have gotten the main window as parameter, return it and
+            # don't try "harder" to find another window using the stack
+            return self._main_window
+        else:
+            # The main window is at the "bottom" of the window stack, and as
+            # the list we get with get_windows() is sorted "topmost first", we
+            # simply take the last item of the list to get our main window
+            windows = self._stack.get_windows()
+            if windows:
+                return windows[-1]
+            else:
+                return None
+
+    def _orientation_changed(self, orientation):
+        if self._orientation == orientation:
+            # Ignore repeated requests
+            return
+
+        flags = hildon.PORTRAIT_MODE_SUPPORT
+        if orientation == self._PORTRAIT:
+            flags |= hildon.PORTRAIT_MODE_REQUEST
+
+        window = self._get_main_window()
+        if window is not None:
+            hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+        self._orientation = orientation
+
+    def _on_orientation_signal(self, orientation, stand, face, x, y, z):
+        if orientation in (self._PORTRAIT, self._LANDSCAPE):
+            if self._mode == self.AUTOMATIC:
+                # Automatically set the rotation based on hardware orientation
+                self._orientation_changed(orientation)
+            else:
+                # Ignore orientation changes for non-automatic modes, but save
+                # the current orientation for "automatic" mode later on
+                self._last_dbus_orientation = orientation
+