]> git.meshlink.io Git - catta/blob - avahi-utils/avahi/SimpleGladeApp.py
fix some small bugs in publishing and resolving, and make uninstall work
[catta] / avahi-utils / avahi / SimpleGladeApp.py
1 """
2  SimpleGladeApp.py
3  Module that provides an object oriented abstraction to pygtk and libglade.
4  Copyright (C) 2004 Sandino Flores Moreno
5 """
6
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 # USA
21
22 import os
23 import sys
24 import re
25
26 import tokenize
27 import gtk
28 import gtk.glade
29 import weakref
30 import inspect
31
32 __version__ = "1.0"
33 __author__ = 'Sandino "tigrux" Flores-Moreno'
34
35 def bindtextdomain(app_name, locale_dir=None):
36     """    
37     Bind the domain represented by app_name to the locale directory locale_dir.
38     It has the effect of loading translations, enabling applications for different
39     languages.
40
41     app_name:
42         a domain to look for translations, tipically the name of an application.
43
44     locale_dir:
45         a directory with locales like locale_dir/lang_isocode/LC_MESSAGES/app_name.mo
46         If omitted or None, then the current binding for app_name is used.
47     """    
48     try:
49         import locale
50         import gettext
51         locale.setlocale(locale.LC_ALL, "")
52         gtk.glade.bindtextdomain(app_name, locale_dir)
53         gettext.install(app_name, locale_dir, unicode=1)
54     except (IOError,locale.Error), e:
55         print "Warning", app_name, e
56         __builtins__.__dict__["_"] = lambda x : x
57
58
59 class SimpleGladeApp:
60
61     def __init__(self, path, root=None, domain=None, **kwargs):
62         """
63         Load a glade file specified by glade_filename, using root as
64         root widget and domain as the domain for translations.
65
66         If it receives extra named arguments (argname=value), then they are used
67         as attributes of the instance.
68
69         path:
70             path to a glade filename.
71             If glade_filename cannot be found, then it will be searched in the
72             same directory of the program (sys.argv[0])
73
74         root:
75             the name of the widget that is the root of the user interface,
76             usually a window or dialog (a top level widget).
77             If None or ommited, the full user interface is loaded.
78
79         domain:
80             A domain to use for loading translations.
81             If None or ommited, no translation is loaded.
82
83         **kwargs:
84             a dictionary representing the named extra arguments.
85             It is useful to set attributes of new instances, for example:
86                 glade_app = SimpleGladeApp("ui.glade", foo="some value", bar="another value")
87             sets two attributes (foo and bar) to glade_app.
88         """        
89         if os.path.isfile(path):
90             self.glade_path = path
91         else:
92             glade_dir = os.path.dirname( sys.argv[0] )
93             self.glade_path = os.path.join(glade_dir, path)
94         for key, value in kwargs.items():
95             try:
96                 setattr(self, key, weakref.proxy(value) )
97             except TypeError:
98                 setattr(self, key, value)
99         self.glade = None
100         self.install_custom_handler(self.custom_handler)
101         self.glade = self.create_glade(self.glade_path, root, domain)
102         if root:
103             self.main_widget = self.get_widget(root)
104         else:
105             self.main_widget = None
106         self.normalize_names()
107         self.add_callbacks(self)
108         self.new()
109
110     def __repr__(self):
111         class_name = self.__class__.__name__
112         if self.main_widget:
113             root = gtk.Widget.get_name(self.main_widget)
114             repr = '%s(path="%s", root="%s")' % (class_name, self.glade_path, root)
115         else:
116             repr = '%s(path="%s")' % (class_name, self.glade_path)
117         return repr
118
119     def new(self):
120         """
121         Method called when the user interface is loaded and ready to be used.
122         At this moment, the widgets are loaded and can be refered as self.widget_name
123         """
124         pass
125
126     def add_callbacks(self, callbacks_proxy):
127         """
128         It uses the methods of callbacks_proxy as callbacks.
129         The callbacks are specified by using:
130             Properties window -> Signals tab
131             in glade-2 (or any other gui designer like gazpacho).
132
133         Methods of classes inheriting from SimpleGladeApp are used as
134         callbacks automatically.
135
136         callbacks_proxy:
137             an instance with methods as code of callbacks.
138             It means it has methods like on_button1_clicked, on_entry1_activate, etc.
139         """        
140         self.glade.signal_autoconnect(callbacks_proxy)
141
142     def normalize_names(self):
143         """
144         It is internally used to normalize the name of the widgets.
145         It means a widget named foo:vbox-dialog in glade
146         is refered self.vbox_dialog in the code.
147
148         It also sets a data "prefixes" with the list of
149         prefixes a widget has for each widget.
150         """
151         for widget in self.get_widgets():
152             widget_name = gtk.Widget.get_name(widget)
153             prefixes_name_l = widget_name.split(":")
154             prefixes = prefixes_name_l[ : -1]
155             widget_api_name = prefixes_name_l[-1]
156             widget_api_name = "_".join( re.findall(tokenize.Name, widget_api_name) )
157             gtk.Widget.set_name(widget, widget_api_name)
158             if hasattr(self, widget_api_name):
159                 raise AttributeError("instance %s already has an attribute %s" % (self,widget_api_name))
160             else:
161                 setattr(self, widget_api_name, widget)
162                 if prefixes:
163                     gtk.Widget.set_data(widget, "prefixes", prefixes)
164
165     def add_prefix_actions(self, prefix_actions_proxy):
166         """
167         By using a gui designer (glade-2, gazpacho, etc)
168         widgets can have a prefix in theirs names
169         like foo:entry1 or foo:label3
170         It means entry1 and label3 has a prefix action named foo.
171
172         Then, prefix_actions_proxy must have a method named prefix_foo which
173         is called everytime a widget with prefix foo is found, using the found widget
174         as argument.
175
176         prefix_actions_proxy:
177             An instance with methods as prefix actions.
178             It means it has methods like prefix_foo, prefix_bar, etc.
179         """        
180         prefix_s = "prefix_"
181         prefix_pos = len(prefix_s)
182
183         is_method = lambda t : callable( t[1] )
184         is_prefix_action = lambda t : t[0].startswith(prefix_s)
185         drop_prefix = lambda (k,w): (k[prefix_pos:],w)
186
187         members_t = inspect.getmembers(prefix_actions_proxy)
188         methods_t = filter(is_method, members_t)
189         prefix_actions_t = filter(is_prefix_action, methods_t)
190         prefix_actions_d = dict( map(drop_prefix, prefix_actions_t) )
191
192         for widget in self.get_widgets():
193             prefixes = gtk.Widget.get_data(widget, "prefixes")
194             if prefixes:
195                 for prefix in prefixes:
196                     if prefix in prefix_actions_d:
197                         prefix_action = prefix_actions_d[prefix]
198                         prefix_action(widget)
199
200     def custom_handler(self,
201             glade, function_name, widget_name,
202             str1, str2, int1, int2):
203         """
204         Generic handler for creating custom widgets, internally used to
205         enable custom widgets (custom widgets of glade).
206
207         The custom widgets have a creation function specified in design time.
208         Those creation functions are always called with str1,str2,int1,int2 as
209         arguments, that are values specified in design time.
210
211         Methods of classes inheriting from SimpleGladeApp are used as
212         creation functions automatically.
213
214         If a custom widget has create_foo as creation function, then the
215         method named create_foo is called with str1,str2,int1,int2 as arguments.
216         """
217         try:
218             handler = getattr(self, function_name)
219             return handler(str1, str2, int1, int2)
220         except AttributeError:
221             return None
222
223     def gtk_widget_show(self, widget, *args):
224         """
225         Predefined callback.
226         The widget is showed.
227         Equivalent to widget.show()
228         """
229         widget.show()
230
231     def gtk_widget_hide(self, widget, *args):
232         """
233         Predefined callback.
234         The widget is hidden.
235         Equivalent to widget.hide()
236         """
237         widget.hide()
238
239     def gtk_widget_grab_focus(self, widget, *args):
240         """
241         Predefined callback.
242         The widget grabs the focus.
243         Equivalent to widget.grab_focus()
244         """
245         widget.grab_focus()
246
247     def gtk_widget_destroy(self, widget, *args):
248         """
249         Predefined callback.
250         The widget is destroyed.
251         Equivalent to widget.destroy()
252         """
253         widget.destroy()
254
255     def gtk_window_activate_default(self, window, *args):
256         """
257         Predefined callback.
258         The default widget of the window is activated.
259         Equivalent to window.activate_default()
260         """
261         widget.activate_default()
262
263     def gtk_true(self, *args):
264         """
265         Predefined callback.
266         Equivalent to return True in a callback.
267         Useful for stopping propagation of signals.
268         """
269         return True
270
271     def gtk_false(self, *args):
272         """
273         Predefined callback.
274         Equivalent to return False in a callback.
275         """
276         return False
277
278     def gtk_main_quit(self, *args):
279         """
280         Predefined callback.
281         Equivalent to self.quit()
282         """
283         self.quit()
284
285     def main(self):
286         """
287         Starts the main loop of processing events.
288         The default implementation calls gtk.main()
289
290         Useful for applications that needs a non gtk main loop.
291         For example, applications based on gstreamer needs to override
292         this method with gst.main()
293
294         Do not directly call this method in your programs.
295         Use the method run() instead.
296         """
297         gtk.main()
298
299     def quit(self):
300         """
301         Quit processing events.
302         The default implementation calls gtk.main_quit()
303         
304         Useful for applications that needs a non gtk main loop.
305         For example, applications based on gstreamer needs to override
306         this method with gst.main_quit()
307         """
308         gtk.main_quit()
309
310     def run(self):
311         """
312         Starts the main loop of processing events checking for Control-C.
313
314         The default implementation checks wheter a Control-C is pressed,
315         then calls on_keyboard_interrupt().
316
317         Use this method for starting programs.
318         """
319         try:
320             self.main()
321         except KeyboardInterrupt:
322             self.on_keyboard_interrupt()
323
324     def on_keyboard_interrupt(self):
325         """
326         This method is called by the default implementation of run()
327         after a program is finished by pressing Control-C.
328         """
329         pass
330
331     def install_custom_handler(self, custom_handler):
332         gtk.glade.set_custom_handler(custom_handler)
333
334     def create_glade(self, glade_path, root, domain):
335         return gtk.glade.XML(self.glade_path, root, domain)
336
337     def get_widget(self, widget_name):
338         return self.glade.get_widget(widget_name)
339
340     def get_widgets(self):
341         return self.glade.get_widget_prefix("")