1 # registry - zavai resource registry
3 # Copyright (C) 2009 Enrico Zini <enrico@enricozini.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 "Get the parent name for s"
25 if pos == -1: return None
27 if res == "menu": return None
31 "Compute a default label given the last element of a path"
33 if pos == -1: return s.capitalize()
34 return s[pos+1:].capitalize()
37 class Registry(object):
38 """Collection of resources.
40 Various factories can be registered by name on the registry. Then when an
41 object is requested for the first time, it is created using the factory.
42 When it is requested again, the existing object is reused.
46 self.factories = dict()
50 def register(self, obj, name=None):
51 """Register an object at the given path.
53 Name the path to this object, like "menu.gps.monitor".
58 if name in self.objects:
59 return KeyError("%s is already registered", name)
60 zavai.info("Registering", name)
61 self.objects[name] = obj
63 if name.startswith("menu."):
64 self.add_to_menu(name)
66 def register_factory(self, fac, name, label = None):
67 """Register an object factory at the given path.
69 Name the path to this object, like "menu.gps.monitor".
71 if name in self.factories:
72 return KeyError("Factory %s is already registered", name)
73 zavai.info("Registering factory", name)
74 self.factories[name] = fac
75 if label is not None: self.labels[name] = label
77 def add_to_menu(self, name):
78 "Add the applet with the given name to the menu structure"
79 parent = get_parent(name)
80 if parent is not None:
81 zavai.info("Add to menu", name, parent)
82 menu = self.menu(parent)
84 obj = self.resource(name)
85 if isinstance(obj, gtk.ToggleAction):
86 menu.add_child(zavai.ToggleButton(self, name, action=obj))
87 elif isinstance(obj, gtk.Action):
88 menu.add_child(zavai.LinkButton(self, name, action=obj))
90 menu.add_child(zavai.LinkButton(self, name, self.label(name)))
92 def label(self, name):
93 "Return the label for the object with the given name"
94 res = self.labels.get(name)
98 obj = self.resource(name)
99 return obj.props.label
101 return default_label(name)
103 def resource(self, name):
104 """Get a resource from the registry.
106 If no resource exists at `name` but there is a factory, instantiate the
107 object using the factory.
109 If not even a factory exists at `name`, returns None.
111 res = self.objects.get(name, None)
113 fac = self.factories.get(name, None)
115 res = self.objects[name] = fac(self, name)
118 def menu(self, name):
119 """Get a menu resource, automatically creating it if it is missing.
121 Menus are created automatically linked to a parent menu, according to
122 the hierarchy in `name`.
124 res = self.resource(name)
126 # Check if it is a toplevel menu
127 if name.startswith("menu."):
128 parent = get_parent(name[5:])
129 if parent is not None:
130 parent = "menu." + parent
132 parent = get_parent(name)
134 res = zavai.Menu(self, name, parent)
135 self.register(res, name)
139 """Shut down all objects in this Registry.
141 After shutting down, all objects cannot be used anymore"""
142 for o in self.objects.itervalues():
143 if isinstance(o, Resource):
147 class Resource(object):
149 super(Resource, self).__init__()
152 """Shut down this resource.
154 Normally one does nothing here, but it is important to give resources a
155 chance to do cleanup when the program quits.
157 This can be used for tasks like closing the tags on a GPX track,
158 releasing a FSO resource, restoring mixer settings and so on.
162 class Service(Resource):
163 "Service that is activated only when someone is listening"
165 super(Service, self).__init__()
166 self.callbacks = set()
172 "Activate the service"
176 "Deactivate the service"
179 def notify(self, *args, **kw):
180 "Call all callbacks with the given parameters"
181 for cb in self.callbacks:
184 def connect(self, callback):
185 "Connect a callback to this resource, activating it if needed"
186 do_start = not self.callbacks
187 self.callbacks.add(callback)
191 def disconnect(self, callback):
192 "Disconnect a callback to this resource, activating it if needed"
193 if not self.callbacks: return
194 self.callbacks.discard(callback)
195 if not self.callbacks: