1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Defines a container component with freely designed layout and style."""
17
18 from muntjac.ui.abstract_layout import AbstractLayout
19 from muntjac.ui.component import IComponent
20
21
23 """A container component with freely designed layout and style. The
24 layout consists of items with textually represented locations. Each item
25 contains one sub-component, which can be any Muntjac component, such as a
26 layout. The adapter and theme are responsible for rendering the layout
27 with a given style by placing the items in the defined locations.
28
29 The placement of the locations is not fixed - different themes can define
30 the locations in a way that is suitable for them. One typical example
31 would be to create visual design for a web site as a custom layout: the
32 visual design would define locations for "menu", "body", and "title", for
33 example. The layout would then be implemented as an XHTML template for
34 each theme.
35
36 The default theme handles the styles that are not defined by drawing the
37 subcomponents just as in OrderedLayout.
38
39 @author: Vaadin Ltd.
40 @author: Richard Lincoln
41 @author: Duy B. Vo
42 @version: 1.1.2
43 """
44
45 CLIENT_WIDGET = None
46
47 _BUFFER_SIZE = 10000
48
50 """Default constructor only used by subclasses. Subclasses are
51 responsible for setting the appropriate fields. Either
52 L{setTemplateName}, that makes layout fetch the template from theme,
53 or L{setTemplateContents}.
54
55 Template file is fetched from "<theme>/layout/<templateName>".
56
57 @raise IOException:
58 """
59 super(CustomLayout, self).__init__()
60
61
62 self._slots = dict()
63 self._templateContents = None
64 self._templateName = None
65
66 self.setWidth(100, self.UNITS_PERCENTAGE)
67
68 if template is not None:
69 if isinstance(template, basestring):
70 self._templateName = template
71 else:
72 self.initTemplateContentsFromInputStream(template)
73
74
76 self._templateContents = templateStream.getvalue()
77
78
80 """Adds the component into this container to given location. If
81 the location is already populated, the old component is removed.
82 If the component is added without specifying the location (empty
83 string is then used as location). Only one component can be added
84 to the default "" location and adding more components into that
85 location overwrites the old components.
86
87 @param c: the component to be added.
88 @param location: the location of the component.
89 """
90 old = self._slots.get(location)
91 if old is not None:
92 self.removeComponent(old)
93 self._slots[location] = c
94 c.setParent(self)
95 self.fireComponentAttachEvent(c)
96 self.requestRepaint()
97
98
100 """Removes the component from this container or the given location.
101
102 @param arg: the component to be removed or the location identifier
103 of the component.
104 """
105 if isinstance(arg, IComponent):
106 c = arg
107 if c is None:
108 return
109 for k, v in self._slots.iteritems():
110 if v == c:
111 del self._slots[k]
112 break
113 super(CustomLayout, self).removeComponent(c)
114 self.requestRepaint()
115 else:
116 location = arg
117 self.removeComponent(self._slots.get(location))
118
119
121 """Gets the component container iterator for going trough all
122 the components in the container.
123
124 @return: the iterator of the components inside the container.
125 """
126 return iter( self._slots.values() )
127
128
130 """Gets the number of contained components. Consistent with the
131 iterator returned by L{getComponentIterator}.
132
133 @return: the number of contained components
134 """
135 return len( self._slots.values() )
136
137
139 """Gets the child-component by its location.
140
141 @param location: the name of the location where the requested
142 component resides.
143 @return: the IComponent in the given location or null if not found.
144 """
145 return self._slots.get(location)
146
147
148 - def paintContent(self, target):
149 """Paints the content of this component.
150
151 @raise PaintException: if the paint operation failed.
152 """
153 super(CustomLayout, self).paintContent(target)
154
155 if self._templateName is not None:
156 target.addAttribute('template', self._templateName)
157 else:
158 target.addAttribute('templateContents', self._templateContents)
159
160
161 for location, c in self._slots.iteritems():
162 if c is not None:
163
164 target.startTag('location')
165 target.addAttribute('name', location)
166 c.paint(target)
167 target.endTag('location')
168
169
171
172 oldLocation = None
173 newLocation = None
174
175 for location, component in self._slots.iteritems():
176 if component == oldComponent:
177 oldLocation = location
178 if component == newComponent:
179 newLocation = location
180
181 if oldLocation is None:
182 self.addComponent(newComponent)
183
184 elif newLocation is None:
185 self.removeComponent(oldLocation)
186 self.addComponent(newComponent, oldLocation)
187
188 else:
189 self._slots[newLocation] = oldComponent
190 self._slots[oldLocation] = newComponent
191 self.requestRepaint()
192
193
195 """CustomLayout's template selecting was previously implemented
196 with setStyle. Overriding to improve backwards compatibility.
197
198 @param name: template name
199 @deprecated: Use L{setTemplateName} instead
200 """
201 self.setTemplateName(name)
202
203
205 """Get the name of the template"""
206 return self._templateName
207
208
210 """Get the contents of the template"""
211 return self._templateContents
212
213
215 """Set the name of the template used to draw custom layout.
216
217 With GWT-adapter, the template with name 'templatename' is loaded
218 from VAADIN/themes/themename/layouts/templatename.html. If the theme
219 has not been set (with Application.setTheme()), themename is
220 'default'.
221 """
222 self._templateName = templateName
223 self._templateContents = None
224 self.requestRepaint()
225
226
227 - def setTemplateContents(self, templateContents):
228 """Set the contents of the template used to draw the custom layout.
229 """
230 self._templateContents = templateContents
231 self._templateName = None
232 self.requestRepaint()
233
234
236 """Although most layouts support margins, CustomLayout does not.
237 The behaviour of this layout is determined almost completely by
238 the actual template.
239
240 @raise NotImplementedError: CustomLayout does not support margins
241 """
242 raise NotImplementedError, 'CustomLayout does not support margins.'
243