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

Source Code for Module muntjac.ui.css_layout

  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 a layout component that can be used in browser environment 
 17  only.""" 
 18   
 19  from muntjac.ui.abstract_layout import AbstractLayout 
 20  from muntjac.terminal.gwt.client.event_id import EventId 
 21   
 22  from muntjac.event.layout_events import \ 
 23      ILayoutClickNotifier, LayoutClickEvent, ILayoutClickListener 
 24   
 25   
26 -class CssLayout(AbstractLayout, ILayoutClickNotifier):
27 """CssLayout is a layout component that can be used in browser environment 28 only. It simply renders components and their captions into a same div 29 element. Component layout can then be adjusted with css. 30 31 In comparison to L{HorizontalLayout} and L{VerticalLayout} 32 33 - rather similar server side api 34 - no spacing, alignment or expand ratios 35 - much simpler DOM that can be styled by skilled web developer 36 - no abstraction of browser differences (developer must ensure that 37 the result works properly on each browser) 38 - different kind of handling for relative sizes (that are set from 39 server side) (*) 40 - noticeably faster rendering time in some situations as we rely more 41 on the browser's rendering engine. 42 43 With L{CustomLayout} one can often achieve similar results (good 44 looking layouts with web technologies), but with CustomLayout developer 45 needs to work with fixed templates. 46 47 By extending CssLayout one can also inject some css rules straight to 48 child components using L{getCss}. 49 50 (*) Relative sizes (set from server side) are treated bit differently than 51 in other layouts in Muntjac. In cssLayout the size is calculated relatively 52 to CSS layouts content area which is pretty much as in html and css. In 53 other layouts the size of component is calculated relatively to the "slot" 54 given by layout. 55 56 Also note that client side framework in Muntjac modifies inline style 57 properties width and height. This happens on each update to component. If 58 one wants to set component sizes with CSS, component must have undefined 59 size on server side (which is not the default for all components) and the 60 size must be defined with class styles - not by directly injecting width 61 and height. 62 """ 63 64 CLIENT_WIDGET = None #ClientWidget(VCssLayout) 65 66 _CLICK_EVENT = EventId.LAYOUT_CLICK 67 68
69 - def __init__(self):
70 super(CssLayout, self).__init__() 71 72 # Custom layout slots containing the components. 73 self.components = list()
74 75
76 - def addComponent(self, c, index=None):
77 """Add a component into this container. The component is added to 78 the right/under the previous component or into indexed position in 79 this container. 80 81 @param c: 82 the component to be added. 83 @param index: 84 the Index of the component position. The components 85 currently in and after the position are shifted forwards. 86 """ 87 if index is None: 88 self.components.append(c) 89 try: 90 super(CssLayout, self).addComponent(c) 91 self.requestRepaint() 92 except ValueError, e: 93 self.components.remove(c) 94 raise e 95 else: 96 self.components.insert(index, c) 97 try: 98 super(CssLayout, self).addComponent(c) 99 self.requestRepaint() 100 except ValueError, e: 101 self.components.remove(c) 102 raise e
103 104
105 - def addComponentAsFirst(self, c):
106 """Adds a component into this container. The component is added to 107 the left or on top of the other components. 108 109 @param c: 110 the component to be added. 111 """ 112 self.components.insert(0, c) 113 try: 114 super(CssLayout, self).addComponent(c) 115 self.requestRepaint() 116 except ValueError, e: 117 self.components.remove(c) 118 raise e
119 120
121 - def removeComponent(self, c):
122 """Removes the component from this container. 123 124 @param c: the component to be removed. 125 """ 126 if c in self.components: 127 self.components.remove(c) 128 super(CssLayout, self).removeComponent(c) 129 self.requestRepaint()
130 131
132 - def getComponentIterator(self):
133 """Gets the component container iterator for going trough all the 134 components in the container. 135 136 @return: the iterator of the components inside the container. 137 """ 138 return iter(self.components)
139 140
141 - def getComponentCount(self):
142 """Gets the number of contained components. Consistent with the 143 iterator returned by L{getComponentIterator}. 144 145 @return: the number of contained components 146 """ 147 return len(self.components)
148 149
150 - def paintContent(self, target):
151 """Paints the content of this component. 152 153 @param target: 154 the Paint Event. 155 @raise PaintException: 156 if the paint operation failed. 157 """ 158 super(CssLayout, self).paintContent(target) 159 componentCss = None 160 # Adds all items in all the locations 161 for c in self.components: 162 # Paint child component UIDL 163 c.paint(target) 164 componentCssString = self.getCss(c) 165 if componentCssString is not None: 166 if componentCss is None: 167 componentCss = dict() 168 componentCss[c] = componentCssString 169 if componentCss is not None: 170 target.addAttribute('css', componentCss)
171 172
173 - def getCss(self, c):
174 """Returns styles to be applied to given component. Override this 175 method to inject custom style rules to components. 176 177 Note that styles are injected over previous styles before actual 178 child rendering. Previous styles are not cleared, but overridden. 179 180 Note that one most often achieves better code style, by separating 181 styling to theme (with custom theme and L{addStyleName}. 182 With own custom styles it is also very easy to break browser 183 compatibility. 184 185 @param c: the component 186 @return: css rules to be applied to component 187 """ 188 return None
189 190
191 - def replaceComponent(self, oldComponent, newComponent):
192 # Gets the locations 193 oldLocation = -1 194 newLocation = -1 195 location = 0 196 for component in self.components: 197 198 if component == oldComponent: 199 oldLocation = location 200 if component == newComponent: 201 newLocation = location 202 203 location += 1 204 205 if oldLocation == -1: 206 self.addComponent(newComponent) 207 elif newLocation == -1: 208 self.removeComponent(oldComponent) 209 self.addComponent(newComponent, oldLocation) 210 else: 211 if oldLocation > newLocation: 212 self.components.remove(oldComponent) 213 self.components.append(newLocation, oldComponent) 214 self.components.remove(newComponent) 215 self.components.append(oldLocation, newComponent) 216 else: 217 self.components.remove(newComponent) 218 self.components.append(oldLocation, newComponent) 219 self.components.remove(oldComponent) 220 self.components.append(newLocation, oldComponent) 221 self.requestRepaint()
222 223
224 - def addListener(self, listener, iface=None):
225 if (isinstance(listener, ILayoutClickListener) and 226 (iface is None or issubclass(iface, ILayoutClickListener))): 227 self.registerListener(self._CLICK_EVENT, 228 LayoutClickEvent, listener, 229 ILayoutClickListener.clickMethod) 230 231 super(CssLayout, self).addListener(listener, iface)
232 233
234 - def addCallback(self, callback, eventType=None, *args):
235 if eventType is None: 236 eventType = callback._eventType 237 238 if issubclass(eventType, LayoutClickEvent): 239 self.registerCallback(LayoutClickEvent, callback, None, *args) 240 else: 241 super(CssLayout, self).addCallback(callback, eventType, *args)
242 243
244 - def removeListener(self, listener, iface=None):
245 if (isinstance(listener, ILayoutClickListener) and 246 (iface is None or issubclass(iface, ILayoutClickListener))): 247 self.withdrawListener(self._CLICK_EVENT, LayoutClickEvent, 248 listener) 249 250 super(CssLayout, self).removeListener(listener, iface)
251 252
253 - def removeCallback(self, callback, eventType=None):
254 if eventType is None: 255 eventType = callback._eventType 256 257 if issubclass(eventType, LayoutClickEvent): 258 self.withdrawCallback(LayoutClickEvent, callback, 259 self._CLICK_EVENT) 260 else: 261 super(CssLayout, self).removeCallback(callback, eventType)
262