Updated help string
[rox-lib/lack.git] / ROX-Lib2 / python / rox / templates.py
blob207603f41ee75ada62b3780fe020c9b952a9485b
1 """Support for loading glade files from your application directory.
3 The simplest interface will be templates.load() which will return a set
4 of widgets loaded from $APP_DIR/Templates.glade, e.g.
5 widgets=templates.load()
6 class MyWindow:
7 def __init__(self):
8 self.window=widgets.getWindow('main')
9 self.entry=widgets['text_entry']
10 widgets.autoConnect(self)
11 self.window.show_all()
13 If you wish to re-use a window then you should use the Templates class:
14 widgets=templates.Templates()
15 windows=[]
16 for i in range(10):
17 set=widgets.getWidgetSet('main')
18 # ... connect signal handlers
19 window=set.getWindow('main')
20 windows.append(window)
22 To use a template as part of a class, derive a class from ProxyWindow
24 class MyWindow(templates.ProxyWindow):
25 def __init__(self):
26 self.widgets=rox.templates.load(None, 'main_window', self)
27 templates.ProxyWindow.__init__(self, self.widgets['main_window'])
28 # ...
31 """
33 import os, sys
34 import errno
36 import rox
37 import gtk.glade as glade
39 def _get_templates_file_name(fname):
40 if not fname:
41 fname='Templates.glade'
42 if not os.path.isabs(fname):
43 fname=os.path.join(rox.app_dir, fname)
44 return fname
46 class Templates:
47 """Class holding a loaded glade file."""
49 def __init__(self, name=None):
50 """Load the glade file. If name is an absolute path name then load
51 it, if a relative path name load that from the appdir or if None
52 the load $APP_DIR/Templates.glade."""
53 self.fname=_get_templates_file_name(name)
55 # Ideally we should cache the file then generate the widgets
56 # using glade.xml_new_from_buffer(), but that is too buggy
57 #self.xml=file(self.fname, 'r').read()
58 self.connect_to=None
59 self.signals={}
61 def autoConnect(self, dict_or_instance):
62 """Specify what to use to connect the signals when an instance of the
63 widgets is created. dict_or_instance is either a dictionary where the
64 signal handlers are indexed by the name of the handler in the glade
65 file, or an instance of a class where the methods have the same
66 names as given in the glade file."""
68 self.connect_to=dict_or_instance
70 def connect(self, handler_name, func):
71 """Manually specify the handler function for a signal. These are
72 not set until getWidgetSet is called."""
74 self.signals[handler_name]=func
76 def getWidgetSet(self, root=''):
77 """Return a WidgetSet instance containing the widgets defined by
78 the glade file. If root is given it is the top level widget to return.
79 The signal handlers specified in connect() or autoConnect() are
80 connected at this point.
81 """
83 widgets=WidgetSet(fname=self.fname, root=root)
84 if self.connect_to:
85 widgets.autoConnect(self.connect_to)
86 for name in self.signals:
87 widgets.connect(name, self.signals[name])
88 return widgets
90 class WidgetSet:
91 """A set of widget instances created from a glade file."""
93 def __init__(self, xml=None, fname=None, root=''):
94 """A set of widget instances created from the glade file.
95 xml - the contents of the glade file.
96 fname - file name to load the glade file from
97 root - top level widget to create (and all is contained widgets), or
98 '' to create all.
99 NOTE: one of xml or fname must be specified
102 assert xml or fname
104 if fname:
105 self.widgets=glade.XML(fname, root)
106 else:
107 self.widgets=glade.xml_new_from_buffer(xml, len(xml), root)
109 def autoConnect(self, dict_or_instance):
110 """Specify what to use to connect the signals.
111 dict_or_instance is either a dictionary where the
112 signal handlers are indexed by the name of the handler in the glade
113 file, or an instance of a class where the methods have the same
114 names as given in the glade file."""
116 self.widgets.signal_autoconnect(dict_or_instance)
118 def connect(self, name, func):
119 """Manually specify the handler function for a signal."""
121 self.widgets.signal_connect(name, func)
123 def getWidget(self, name):
124 """Return the named widget."""
125 return self.widgets.get_widget(name)
127 def getWindow(self, name):
128 """Return the named widget, which should be a gtk.Window. The
129 window is tracked by the window counting system, see
130 rox.toplevel_ref()."""
131 return ProxyWindow(self.getWidget(name))
133 def __getitem__(self, key):
134 """Return the named widget."""
136 widget=self.widgets.get_widget(key)
137 if not widget:
138 raise KeyError, key
139 return widget
141 class ProxyWindow:
142 """This acts as a proxy for a GtkWindow or GtkDialog, except that
143 it calls the toplevel_(un)ref functions for you automatically.
144 It is designed to wrap a window loaded from a Glade template. You
145 can sub-class this to create your own classes."""
147 def __init__(self, window):
148 """Act as a proxy for window. Call toplevel_ref() and arrange
149 for toplevel_unref to be called on destruction."""
151 self._window=window
152 assert self._window
154 rox.toplevel_ref()
155 self._window.connect('destroy', rox.toplevel_unref)
157 def __getattr__(self, name):
158 """Get unrecognized attributes from the window we are proxying
159 for."""
160 try:
161 win=self.__dict__['_window']
162 except:
163 raise AttributeError, '_window'
165 if hasattr(win, name):
166 return getattr(win, name)
167 raise AttributeError, name
169 def load(fname=None, root='', dict_or_instance=None):
170 """Load the templates file and return the set of widgets.
171 fname - path to templates file: If it is an absolute path name then load
172 it, if a relative path name load that from the appdir or if None
173 the load $APP_DIR/Templates.glade.
174 root - name of top level widget (and all child widgets) to create
175 dict_or_instance - what to use to connect the signals.
176 It is either a dictionary where the
177 signal handlers are indexed by the name of the handler in the glade
178 file, or an instance of a class where the methods have the same
179 names as given in the glade file.
181 template=Templates(fname)
182 if dict_or_instance:
183 template.autoConnect(dict_or_instance)
184 return template.getWidgetSet(root)