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

Source Code for Module muntjac.ui.label

  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 component for showing non-editable short texts.""" 
 17   
 18  try: 
 19      from cStringIO import StringIO 
 20  except ImportError, e: 
 21      from StringIO import StringIO 
 22   
 23  from muntjac.data.util.object_property import ObjectProperty 
 24  from muntjac.ui.abstract_component import AbstractComponent 
 25  from muntjac.ui.component import Event as ComponentEvent 
 26   
 27  from muntjac.data import property as prop 
 28   
 29   
 30  _VALUE_CHANGE_METHOD = getattr(prop.IValueChangeListener, "valueChange") 
 31   
 32   
33 -class Label(AbstractComponent, prop.IProperty, prop.IViewer, 34 prop.IValueChangeListener, prop.IValueChangeNotifier):
35 """Label component for showing non-editable short texts. 36 37 The label content can be set to the modes specified by the final members 38 CONTENT_* 39 40 The contents of the label may contain simple formatting: 41 42 - B{<b>} Bold 43 - B{<i>} Italic 44 - B{<u>} Underlined 45 - B{<br/>} Linebreak 46 - B{<ul><li>item 1</li><li>item 2</li></ul>} List of items 47 48 The B{b},B{i},B{u} and B{li} tags can contain all the tags 49 in the list recursively. 50 51 @author: Vaadin Ltd. 52 @author: Richard Lincoln 53 @version: 1.1.2 54 """ 55 56 CLIENT_WIDGET = None #ClientWidget(VLabel, LoadStyle.EAGER) 57 58 #: Content mode, where the label contains only plain text. The getValue() 59 # result is coded to XML when painting. 60 CONTENT_TEXT = 0 61 62 #: Content mode, where the label contains preformatted text. 63 CONTENT_PREFORMATTED = 1 64 65 #: Formatted content mode, where the contents is XML restricted to the UIDL 66 # 1.0 formatting markups. 67 # 68 # @deprecated: Use CONTENT_XML instead. 69 CONTENT_UIDL = 2 70 71 #: Content mode, where the label contains XHTML. Contents is then enclosed 72 # in DIV elements having namespace of 73 # "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd". 74 CONTENT_XHTML = 3 75 76 #: Content mode, where the label contains well-formed or well-balanced XML. 77 # Each of the root elements must have their default namespace specified. 78 CONTENT_XML = 4 79 80 #: Content mode, where the label contains RAW output. Output is not 81 # required to comply to with XML. In Web Adapter output is inserted inside 82 # the resulting HTML document as-is. This is useful for some specific 83 # purposes where possibly broken HTML content needs to be shown, but in 84 # most cases XHTML mode should be preferred. 85 CONTENT_RAW = 5 86 87 #: The default content mode is plain text. 88 CONTENT_DEFAULT = CONTENT_TEXT 89 90 #: Array of content mode names that are rendered in UIDL as mode attribute. 91 _CONTENT_MODE_NAME = ['text', 'pre', 'uidl', 'xhtml', 'xml', 'raw'] 92 93 _DATASOURCE_MUST_BE_SET = 'Datasource must be set' 94 95
96 - def __init__(self, contentSource="", contentMode=None):
97 """Creates a new instance of Label with text-contents read from given 98 datasource. 99 """ 100 super(Label, self).__init__() 101 102 self._dataSource = None 103 self._contentMode = self.CONTENT_DEFAULT 104 105 if isinstance(contentSource, basestring): 106 contentSource = ObjectProperty(contentSource, str) 107 108 if contentMode is None: 109 contentMode = self.CONTENT_DEFAULT 110 111 self.setPropertyDataSource(contentSource) 112 113 if contentMode != self.CONTENT_DEFAULT: 114 self.setContentMode(contentMode) 115 116 self.setWidth(100, self.UNITS_PERCENTAGE)
117 118
119 - def setReadOnly(self, readOnly):
120 """Set the component to read-only. Readonly is not used in label. 121 122 @param readOnly: 123 True to enable read-only mode, False to disable it. 124 """ 125 if self._dataSource is None: 126 raise ValueError, self._DATASOURCE_MUST_BE_SET 127 self._dataSource.setReadOnly(readOnly)
128 129
130 - def isReadOnly(self):
131 """Is the component read-only ? Readonly is not used in label - this 132 returns always false. 133 134 @return: C{True} if the component is in read only mode. 135 """ 136 if self._dataSource is None: 137 raise ValueError, self._DATASOURCE_MUST_BE_SET 138 return self._dataSource.isReadOnly()
139 140
141 - def paintContent(self, target):
142 """Paints the content of this component. 143 144 @param target: 145 the Paint Event. 146 @raise PaintException: 147 if the Paint Operation fails. 148 """ 149 if self._contentMode != self.CONTENT_TEXT: 150 target.addAttribute('mode', 151 self._CONTENT_MODE_NAME[self._contentMode]) 152 153 if self._contentMode == self.CONTENT_TEXT: 154 target.addText(str(self)) 155 156 elif self._contentMode == self.CONTENT_UIDL: 157 target.addUIDL(str(self)) 158 159 elif self._contentMode == self.CONTENT_XHTML: 160 target.startTag('data') 161 target.addXMLSection('div', str(self), 162 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd') 163 target.endTag('data') 164 165 elif self._contentMode == self.CONTENT_PREFORMATTED: 166 target.startTag('pre') 167 target.addText(str(self)) 168 target.endTag('pre') 169 170 elif self._contentMode == self.CONTENT_XML: 171 target.addXMLSection('data', str(self), None) 172 173 elif self._contentMode == self.CONTENT_RAW: 174 target.startTag('data') 175 target.addAttribute('escape', False) 176 target.addText(str(self)) 177 target.endTag('data')
178 179
180 - def getValue(self):
181 """Gets the value of the label. Value of the label is the XML 182 contents of the label. 183 184 @return: the Value of the label. 185 """ 186 if self._dataSource is None: 187 raise ValueError, self._DATASOURCE_MUST_BE_SET 188 return self._dataSource.getValue()
189 190
191 - def setValue(self, newValue):
192 """Set the value of the label. Value of the label is the XML 193 contents of the label. 194 195 @param newValue: 196 the New value of the label. 197 """ 198 if self._dataSource is None: 199 raise ValueError, self._DATASOURCE_MUST_BE_SET 200 self._dataSource.setValue(newValue)
201 202
203 - def __str__(self):
204 if self._dataSource is None: 205 raise ValueError, self._DATASOURCE_MUST_BE_SET 206 return str(self._dataSource)
207 208
209 - def getType(self):
210 """Gets the type of the IProperty. 211 212 @see: L{IProperty.getType} 213 """ 214 if self._dataSource is None: 215 raise ValueError, self._DATASOURCE_MUST_BE_SET 216 return self._dataSource.getType()
217 218
219 - def getPropertyDataSource(self):
220 """Gets the viewing data-source property. 221 222 @return: the data source property. 223 @see: L{IViewer.getPropertyDataSource} 224 """ 225 return self._dataSource
226 227
228 - def setPropertyDataSource(self, newDataSource):
229 """Sets the property as data-source for viewing. 230 231 @param newDataSource: 232 the new data source IProperty 233 @see: L{IViewer.setPropertyDataSource} 234 """ 235 # Stops listening the old data source changes 236 if (self._dataSource is not None 237 and issubclass(self._dataSource.__class__, 238 prop.IValueChangeNotifier)): 239 self._dataSource.removeListener(self, prop.IValueChangeListener) 240 241 # Sets the new data source 242 self._dataSource = newDataSource 243 244 # Listens the new data source if possible 245 if (self._dataSource is not None 246 and issubclass(self._dataSource.__class__, 247 prop.IValueChangeNotifier)): 248 self._dataSource.addListener(self, prop.IValueChangeListener) 249 250 self.requestRepaint()
251 252
253 - def getContentMode(self):
254 """Gets the content mode of the Label. 255 256 Possible content modes include: 257 258 - B{CONTENT_TEXT} Content mode, where the label contains only plain 259 text. The getValue() result is coded to XML when painting. 260 - B{CONTENT_PREFORMATTED} Content mode, where the label contains 261 preformatted text. 262 - B{CONTENT_UIDL} Formatted content mode, where the contents is XML 263 restricted to the UIDL 1.0 formatting markups. 264 - B{CONTENT_XHTML} Content mode, where the label contains XHTML. 265 Contents is then enclosed in DIV elements having namespace of 266 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd". 267 - B{CONTENT_XML} Content mode, where the label contains well-formed 268 or well-balanced XML. Each of the root elements must have their 269 default namespace specified. 270 - B{CONTENT_RAW} Content mode, where the label contains RAW output. 271 Output is not required to comply to with XML. In Web Adapter output 272 is inserted inside the resulting HTML document as-is. This is 273 useful for some specific purposes where possibly broken HTML 274 content needs to be shown, but in most cases XHTML mode should be 275 preferred. 276 277 @return: the Content mode of the label. 278 """ 279 return self._contentMode
280 281
282 - def setContentMode(self, contentMode):
283 """Sets the content mode of the Label. 284 285 Possible content modes include: 286 287 - B{CONTENT_TEXT} Content mode, where the label contains only plain 288 text. The getValue() result is coded to XML when painting. 289 - B{CONTENT_PREFORMATTED} Content mode, where the label contains 290 preformatted text. 291 - B{CONTENT_UIDL} Formatted content mode, where the contents is XML 292 restricted to the UIDL 1.0 formatting markups. 293 - B{CONTENT_XHTML} Content mode, where the label contains XHTML. 294 Contents is then enclosed in DIV elements having namespace of 295 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd". 296 - B{CONTENT_XML} Content mode, where the label contains well-formed 297 or well-balanced XML. Each of the root elements must have their 298 default namespace specified. 299 - B{CONTENT_RAW} Content mode, where the label contains RAW output. 300 Output is not required to comply to with XML. In Web Adapter output 301 is inserted inside the resulting HTML document as-is. This is 302 useful for some specific purposes where possibly broken HTML 303 content needs to be shown, but in most cases XHTML mode should be 304 preferred. 305 306 @param contentMode: 307 the New content mode of the label. 308 """ 309 # Value change events 310 if (contentMode != self._contentMode 311 and contentMode >= self.CONTENT_TEXT 312 and contentMode <= self.CONTENT_RAW): 313 self._contentMode = contentMode 314 self.requestRepaint()
315 316
317 - def addListener(self, listener, iface=None):
318 """Adds the value change listener.""" 319 if (isinstance(listener, prop.IValueChangeListener) and 320 (iface is None or 321 issubclass(iface, prop.IValueChangeListener))): 322 self.registerListener(ValueChangeEvent, listener, 323 _VALUE_CHANGE_METHOD) 324 325 super(Label, self).addListener(listener, iface)
326 327
328 - def addCallback(self, callback, eventType=None, *args):
329 if eventType is None: 330 eventType = callback._eventType 331 332 if issubclass(eventType, prop.ValueChangeEvent): 333 self.registerCallback(prop.ValueChangeEvent, callback, None, *args) 334 else: 335 super(Label, self).addCallback(callback, eventType, *args)
336 337
338 - def removeListener(self, listener, iface=None):
339 """Removes the value change listener.""" 340 if (isinstance(listener, prop.IValueChangeListener) and 341 (iface is None or 342 issubclass(iface, prop.IValueChangeListener))): 343 self.withdrawListener(ValueChangeEvent, listener, 344 _VALUE_CHANGE_METHOD) 345 346 super(Label, self).removeListener(listener, iface)
347 348
349 - def removeCallback(self, callback, eventType=None):
350 if eventType is None: 351 eventType = callback._eventType 352 353 if issubclass(eventType, prop.ValueChangeEvent): 354 self.withdrawCallback(prop.ValueChangeEvent, callback) 355 else: 356 super(Label, self).removeCallback(callback, eventType)
357 358
359 - def fireValueChange(self):
360 """Emits the options change event.""" 361 event = ValueChangeEvent(self) 362 self.fireEvent(event) 363 self.requestRepaint()
364 365
366 - def valueChange(self, event):
367 """Listens the value change events from data source.""" 368 self.fireValueChange()
369 370
371 - def compareTo(self, other):
372 """Compares the Label to other objects. 373 374 Labels can be compared to other labels for sorting label contents. 375 This is especially handy for sorting table columns. 376 377 In RAW, PREFORMATTED and TEXT modes, the label contents are compared 378 as is. In XML, UIDL and XHTML modes, only CDATA is compared and tags 379 ignored. If the other object is not a Label, its toString() return 380 value is used in comparison. 381 382 @param other: 383 the Other object to compare to. 384 @return: a negative integer, zero, or a positive integer as this object 385 is less than, equal to, or greater than the specified object. 386 """ 387 if (self._contentMode == self.CONTENT_XML 388 or self._contentMode == self.CONTENT_UIDL 389 or self._contentMode == self.CONTENT_XHTML): 390 thisValue = self.stripTags(str(self)) 391 else: 392 thisValue = str(self) 393 394 if (isinstance(other, Label) 395 and (other.getContentMode() == self.CONTENT_XML 396 or other.getContentMode() == self.CONTENT_UIDL 397 or other.getContentMode() == self.CONTENT_XHTML)): 398 otherValue = self.stripTags(str(other)) 399 else: 400 otherValue = str(other) 401 402 return cmp(thisValue, otherValue)
403 404
405 - def stripTags(self, xml):
406 """Strips the tags from the XML. 407 408 @param xml: the string containing a XML snippet. 409 @return: the original XML without tags. 410 """ 411 res = StringIO() 412 processed = 0 413 xmlLen = len(xml) 414 while processed < xmlLen: 415 nxt = xml.find('<', processed) 416 if nxt < 0: 417 nxt = xmlLen 418 res.write(xml[processed:nxt]) 419 if processed < xmlLen: 420 nxt = xml.find('>', processed) 421 if nxt < 0: 422 nxt = xmlLen 423 processed = nxt + 1 424 result = res.getvalue() 425 res.close() 426 return result
427 428
429 -class ValueChangeEvent(ComponentEvent, prop.ValueChangeEvent):
430 """Value change event.""" 431
432 - def __init__(self, source):
433 """New instance of text change event.""" 434 super(ValueChangeEvent, self).__init__(source)
435 436
437 - def getProperty(self):
438 """Gets the IProperty that has been modified.""" 439 return self.getSource()
440