No need to fullscreen: matchbox does it for us
[gregoa/zavai.git] / zavai / registry.py
index fae2a6372da4e9f7470b80d593cb5ece28f01f39..4af413c83e9e02c9dd4a313ece374d507c70de67 100644 (file)
@@ -1,4 +1,38 @@
+# registry - zavai resource registry
+#
+# Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
 import zavai
+import gtk
+
+def get_parent(s):
+    "Get the parent name for s"
+    pos = s.rfind(".")
+    if pos == -1: return None
+    res = s[:pos]
+    if res == "menu": return None
+    return res
+
+def default_label(s):
+    "Compute a default label given the last element of a path"
+    pos = s.rfind(".")
+    if pos == -1: return s.capitalize()
+    return s[pos+1:].capitalize()
+
 
 class Registry(object):
     """Collection of resources.
@@ -11,79 +45,106 @@ class Registry(object):
     def __init__(self):
         self.factories = dict()
         self.objects = dict()
+        self.labels = dict()
+
+    def register(self, obj, name=None):
+        """Register an object at the given path.
+
+        Name the path to this object, like "menu.gps.monitor".
+        """
+        if name is None:
+            name = obj.props.name
+
+        if name in self.objects:
+            return KeyError("%s is already registered", name)
+        zavai.info("Registering", name)
+        self.objects[name] = obj
+
+        if name.startswith("menu."):
+            self.add_to_menu(name)
+
+    def register_factory(self, fac, name, label = None):
+        """Register an object factory at the given path.
+
+        Name the path to this object, like "menu.gps.monitor".
+        """
+        if name in self.factories:
+            return KeyError("Factory %s is already registered", name)
+        zavai.info("Registering factory", name)
+        self.factories[name] = fac
+        if label is not None: self.labels[name] = label
+
+    def add_to_menu(self, name):
+        "Add the applet with the given name to the menu structure"
+        parent = get_parent(name)
+        if parent is not None:
+            zavai.info("Add to menu", name, parent)
+            menu = self.menu(parent)
+
+            obj = self.resource(name)
+            if isinstance(obj, gtk.ToggleAction):
+                menu.add_child(zavai.ToggleButton(self, name, action=obj))
+            elif isinstance(obj, gtk.Action):
+                menu.add_child(zavai.LinkButton(self, name, action=obj))
+            else:
+                menu.add_child(zavai.LinkButton(self, name, self.label(name)))
+
+    def label(self, name):
+        "Return the label for the object with the given name"
+        res = self.labels.get(name)
+        if res is not None:
+            return res
+        try:
+            obj = self.resource(name)
+            return obj.props.label
+        except:
+            return default_label(name)
 
     def resource(self, name):
-        """Get a resource, instantiating it if it has not been done yet.
+        """Get a resource from the registry.
 
-        First it tries to use the factory registered with `name` itself. If it
-        fails, it tries to use the factory registered one level above (using
-        the dot '.' as a separator).
+        If no resource exists at `name` but there is a factory, instantiate the
+        object using the factory.
 
-        If no suitable factory has been found, returns None.
+        If not even a factory exists at `name`, returns None.
         """
         res = self.objects.get(name, None)
         if res is None:
             fac = self.factories.get(name, None)
-            if fac is None:
-                root = name
-                while True:
-                    pos = root.rfind(".")
-                    if pos == -1: break
-                    root = root[:pos]
-                    fac = self.factories.get(root, None)
-                if fac is None:
-                    return None
-            res = fac(self, name)
-            if res is not None:
-                self.objects[name] = res
+            if fac is not None:
+                res = self.objects[name] = fac(self, name)
         return res
 
     def menu(self, name):
-        """Get a menu resource, instantiating it if it has not been done yet.
+        """Get a menu resource, automatically creating it if it is missing.
 
-        All menu resources share the same factory, which builds zavai.Menu
-        objects.
+        Menus are created automatically linked to a parent menu, according to
+        the hierarchy in `name`.
         """
-        return self.resource("menu." + name)
-
-    def menu_link(self, name, label):
-        """Return a MenuLink to the menu with the given name
-        """
-        return zavai.MenuLink(self, name, label)
-
-    def get_existing(self, name):
-        """Get a menu resource, but only if it has been already instantiated.
-
-        If the resource has not been instantiated yet, returns None.
-        """
-        return self.objects.get(name, None)
-
-    def register(self, name, factory):
-        """Register a factory for this registry.
-
-        Name is a name for this factory, like "menu.gps.monitor".
-
-        Factory is a function that creates a Resource object. The function will
-        be passed the Registry itself as the only parameter"""
-        if name in self.factories:
-            return KeyError("% is already registered as a factory", name)
-        self.factories[name] = factory
+        res = self.resource(name)
+        if res is None:
+            # Check if it is a toplevel menu
+            if name.startswith("menu."):
+                parent = get_parent(name[5:])
+                if parent is not None:
+                    parent = "menu." + parent
+            else:
+                parent = get_parent(name)
+
+            res = zavai.Menu(self, name, parent)
+            self.register(res, name)
+        return res
 
     def shutdown(self):
         """Shut down all objects in this Registry.
 
         After shutting down, all objects cannot be used anymore"""
         for o in self.objects.itervalues():
-            o.shutdown()
+            if isinstance(o, Resource):
+                o.shutdown()
         self.objects.clear()
 
 class Resource(object):
-    def __init__(self, registry, name, *args, **kw):
-        """The default constructor does nothing, but is there to eat the
-        parameters passed by Registry in case subclassers do not need a
-        constructor"""
-        pass
-
     def shutdown(self):
         """Shut down this resource.