Package muntjac :: Package ui :: Module abstract_component_container
[hide private]
[frames] | no frames]

Source Code for Module muntjac.ui.abstract_component_container

  1  # Copyright (C) 2012 Vaadin Ltd.  
  2  # Copyright (C) 2012 Richard Lincoln 
  3  #  
  4  # Licensed under the Apache License, Version 2.0 (the "License");  
  5  # you may not use this file except in compliance with the License.  
  6  # You may obtain a copy of the License at  
  7  #  
  8  #     http://www.apache.org/licenses/LICENSE-2.0  
  9  #  
 10  # Unless required by applicable law or agreed to in writing, software  
 11  # distributed under the License is distributed on an "AS IS" BASIS,  
 12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
 13  # See the License for the specific language governing permissions and  
 14  # limitations under the License. 
 15   
 16  """Defines the default implementation for the methods in IComponentContainer. 
 17  """ 
 18   
 19  from muntjac.ui.abstract_component import AbstractComponent 
 20   
 21  from muntjac.ui.component_container import \ 
 22      ComponentAttachEvent, IComponentAttachListener, IComponentContainer, \ 
 23      ComponentDetachEvent, IComponentDetachListener 
 24   
 25   
 26  _COMPONENT_ATTACHED_METHOD = getattr(IComponentAttachListener, 
 27          'componentAttachedToContainer') 
 28   
 29  _COMPONENT_DETACHED_METHOD = getattr(IComponentDetachListener, 
 30          'componentDetachedFromContainer') 
 31   
 32   
33 -class AbstractComponentContainer(AbstractComponent, IComponentContainer):
34 """Extension to L{AbstractComponent} that defines the default 35 implementation for the methods in L{IComponentContainer}. Basic 36 UI components that need to contain other components inherit this class 37 to easily qualify as a component container. 38 39 @author: Vaadin Ltd. 40 @version: 1.1.2 41 """ 42
43 - def __init__(self):
44 """Constructs a new component container.""" 45 super(AbstractComponentContainer, self).__init__()
46 47
48 - def removeAllComponents(self):
49 """Removes all components from the container. This should probably 50 be re-implemented in extending classes for a more powerful 51 implementation. 52 """ 53 l = list() 54 55 # Adds all components 56 for c in self.getComponentIterator(): 57 l.append(c) 58 59 # Removes all components 60 for c in l: 61 self.removeComponent(c)
62 63
64 - def moveComponentsFrom(self, source):
65 # Moves all components from an another container into this container. 66 components = list() 67 68 for c in self.getComponentIterator(): 69 components.append(c) 70 71 for c in components: 72 source.removeComponent(c) 73 self.addComponent(c)
74 75
76 - def attach(self):
77 """Notifies all contained components that the container is attached 78 to a window. 79 80 @see: L{IComponent.attach} 81 """ 82 super(AbstractComponentContainer, self).attach() 83 84 for c in self.getComponentIterator(): 85 c.attach()
86 87
88 - def detach(self):
89 """Notifies all contained components that the container is detached 90 from a window. 91 92 @see: L{IComponent.detach} 93 """ 94 # Events 95 super(AbstractComponentContainer, self).detach() 96 97 for c in self.getComponentIterator(): 98 c.detach()
99 100
101 - def addListener(self, listener, iface=None):
102 if (isinstance(listener, IComponentAttachListener) and 103 (iface is None or issubclass(iface, IComponentAttachListener))): 104 self.registerListener(ComponentAttachEvent, listener, 105 _COMPONENT_ATTACHED_METHOD) 106 107 if (isinstance(listener, IComponentDetachListener) and 108 (iface is None or issubclass(iface, IComponentDetachListener))): 109 self.registerListener(ComponentDetachEvent, listener, 110 _COMPONENT_DETACHED_METHOD) 111 112 super(AbstractComponentContainer, self).addListener(listener, iface)
113 114
115 - def addCallback(self, callback, eventType=None, *args):
116 if eventType is None: 117 eventType = callback._eventType 118 119 if issubclass(eventType, ComponentAttachEvent): 120 self.registerCallback(ComponentAttachEvent, callback, None, *args) 121 122 elif issubclass(eventType, ComponentDetachEvent): 123 self.registerCallback(ComponentDetachEvent, callback, None, *args) 124 125 else: 126 super(AbstractComponentContainer, self).addCallback(callback, 127 eventType, *args)
128 129
130 - def removeListener(self, listener, iface=None):
131 if (isinstance(listener, IComponentAttachListener) and 132 (iface is None or issubclass(iface, IComponentAttachListener))): 133 self.withdrawListener(ComponentAttachEvent, listener, 134 _COMPONENT_ATTACHED_METHOD) 135 136 if (isinstance(listener, IComponentDetachListener) and 137 (iface is None or issubclass(iface, IComponentDetachListener))): 138 self.withdrawListener(ComponentDetachEvent, listener, 139 _COMPONENT_DETACHED_METHOD) 140 141 super(AbstractComponentContainer, self).removeListener(listener, iface)
142 143
144 - def removeCallback(self, callback, eventType=None):
145 if eventType is None: 146 eventType = callback._eventType 147 148 if issubclass(eventType, ComponentAttachEvent): 149 self.withdrawCallback(ComponentAttachEvent, callback) 150 151 elif issubclass(eventType, ComponentDetachEvent): 152 self.withdrawCallback(ComponentDetachEvent, callback) 153 154 else: 155 super(AbstractComponentContainer, self).removeCallback(callback, 156 eventType)
157 158
159 - def fireComponentAttachEvent(self, component):
160 """Fires the component attached event. This should be called by 161 the addComponent methods after the component have been added to 162 this container. 163 164 @param component: 165 the component that has been added to this container. 166 """ 167 event = ComponentAttachEvent(self, component) 168 self.fireEvent(event)
169 170
171 - def fireComponentDetachEvent(self, component):
172 """Fires the component detached event. This should be called by 173 the removeComponent methods after the component have been removed 174 from this container. 175 176 @param component: 177 the component that has been removed from this container. 178 """ 179 event = ComponentDetachEvent(self, component) 180 self.fireEvent(event)
181 182
183 - def addComponent(self, c):
184 """This only implements the events and component parent calls. The 185 extending classes must implement component list maintenance and call 186 this method after component list maintenance. 187 188 @see: L{IComponentContainer.addComponent} 189 """ 190 if isinstance(c, IComponentContainer): 191 # Make sure we're not adding the component 192 # inside it's own content 193 parent = self 194 while parent is not None: 195 parent = parent.getParent() 196 if parent == c: 197 msg = 'Component cannot be added inside it\'s own content' 198 raise ValueError, msg 199 200 if c.getParent() is not None: 201 # If the component already has a parent, try to remove it 202 oldParent = c.getParent() 203 oldParent.removeComponent(c) 204 205 c.setParent(self) 206 self.fireComponentAttachEvent(c)
207 208
209 - def removeComponent(self, c):
210 """This only implements the events and component parent calls. The 211 extending classes must implement component list maintenance and call 212 this method before component list maintenance. 213 214 @see: L{IComponentContainer.removeComponent} 215 """ 216 if c.getParent() == self: 217 c.setParent(None) 218 self.fireComponentDetachEvent(c)
219 220
221 - def setEnabled(self, enabled):
222 super(AbstractComponentContainer, self).setEnabled(enabled) 223 224 if self.getParent() is not None and not self.getParent().isEnabled(): 225 # some ancestor still disabled, don't update children 226 return 227 else: 228 self.requestRepaintAll()
229 230
231 - def setWidth(self, width, unit=None):
232 if unit is not None: 233 from muntjac.terminal.gwt.server.component_size_validator import \ 234 ComponentSizeValidator # FIXME: circular import 235 236 # child tree repaints may be needed, due to our fall back support 237 # for invalid relative sizes 238 dirtyChildren = None 239 childrenMayBecomeUndefined = False 240 if (self.getWidth() == self.SIZE_UNDEFINED 241 and width != self.SIZE_UNDEFINED): 242 # children currently in invalid state may need repaint 243 dirtyChildren = self.getInvalidSizedChildren(False) 244 245 elif ((width == self.SIZE_UNDEFINED 246 and self.getWidth() != self.SIZE_UNDEFINED) 247 or (unit == self.UNITS_PERCENTAGE 248 and self.getWidthUnits() != self.UNITS_PERCENTAGE 249 and not ComponentSizeValidator.parentCanDefineWidth(self))): 250 251 # relative width children may get to invalid state if width 252 # becomes invalid. Width may also become invalid if units become 253 # percentage due to the fallback support 254 childrenMayBecomeUndefined = True 255 dirtyChildren = self.getInvalidSizedChildren(False) 256 257 super(AbstractComponentContainer, self).setWidth(width, unit) 258 self.repaintChangedChildTrees(dirtyChildren, 259 childrenMayBecomeUndefined, False) 260 else: 261 super(AbstractComponentContainer, self).setWidth(width)
262 263
264 - def repaintChangedChildTrees(self, invalidChildren, 265 childrenMayBecomeUndefined, vertical):
266 if childrenMayBecomeUndefined: 267 previouslyInvalidComponents = invalidChildren 268 269 invalidChildren = self.getInvalidSizedChildren(vertical) 270 271 if (previouslyInvalidComponents is not None 272 and invalidChildren is not None): 273 for component in invalidChildren: 274 if component in previouslyInvalidComponents: 275 # still invalid don't repaint 276 previouslyInvalidComponents.remove(component) 277 278 elif invalidChildren is not None: 279 stillInvalidChildren = self.getInvalidSizedChildren(vertical) 280 281 if stillInvalidChildren is not None: 282 for component in stillInvalidChildren: 283 # didn't become valid 284 invalidChildren.remove(component) 285 286 if invalidChildren is not None: 287 self.repaintChildTrees(invalidChildren)
288 289
290 - def getInvalidSizedChildren(self, vertical):
291 components = None 292 293 from muntjac.ui.panel import Panel # FIXME: circular import 294 from muntjac.terminal.gwt.server.component_size_validator import \ 295 ComponentSizeValidator # FIXME: circular import 296 297 if isinstance(self, Panel): 298 p = self 299 content = p.getContent() 300 if vertical: 301 valid = ComponentSizeValidator.checkHeights(content) 302 else: 303 valid = ComponentSizeValidator.checkWidths(content) 304 if not valid: 305 components = set() 306 components.add(content) 307 else: 308 for component in self.getComponentIterator(): 309 if vertical: 310 valid = ComponentSizeValidator.checkHeights(component) 311 else: 312 valid = ComponentSizeValidator.checkWidths(component) 313 if not valid: 314 if components is None: 315 components = set() 316 components.add(component) 317 318 return components
319 320
321 - def repaintChildTrees(self, dirtyChildren):
322 for c in dirtyChildren: 323 if isinstance(c, IComponentContainer): 324 c.requestRepaintAll() 325 else: 326 c.requestRepaint()
327 328
329 - def setHeight(self, height, unit=None):
330 if unit is not None: 331 from muntjac.terminal.gwt.server.component_size_validator import \ 332 ComponentSizeValidator # FIXME: circular import 333 334 # child tree repaints may be needed, due to our fall back support 335 # for invalid relative sizes 336 dirtyChildren = None 337 childrenMayBecomeUndefined = False 338 if (self.getHeight() == self.SIZE_UNDEFINED 339 and height != self.SIZE_UNDEFINED): 340 # children currently in invalid state may need repaint 341 dirtyChildren = self.getInvalidSizedChildren(True) 342 343 elif ((height == self.SIZE_UNDEFINED 344 and self.getHeight() != self.SIZE_UNDEFINED) 345 or (unit == self.UNITS_PERCENTAGE 346 and self.getHeightUnits() != self.UNITS_PERCENTAGE 347 and not ComponentSizeValidator.parentCanDefineHeight(self))): 348 349 # relative height children may get to invalid state if height 350 # becomes invalid. Height may also become invalid if units 351 # become percentage due to the fallback support. 352 childrenMayBecomeUndefined = True 353 dirtyChildren = self.getInvalidSizedChildren(True) 354 355 super(AbstractComponentContainer, self).setHeight(height, unit) 356 357 self.repaintChangedChildTrees(dirtyChildren, 358 childrenMayBecomeUndefined, True) 359 else: 360 super(AbstractComponentContainer, self).setHeight(height)
361 362
363 - def requestRepaintAll(self):
364 self.requestRepaint() 365 366 from muntjac.ui.form import Form # FIXME: circular import 367 from muntjac.ui.table import Table 368 369 for c in self.getComponentIterator(): 370 if isinstance(c, Form): 371 # Form has children in layout, but 372 # is not IComponentContainer 373 c.requestRepaint() 374 c.getLayout().requestRepaintAll() 375 elif isinstance(c, Table): 376 c.requestRepaintAll() 377 elif isinstance(c, IComponentContainer): 378 c.requestRepaintAll() 379 else: 380 c.requestRepaint()
381