Package pyjamas :: Package ui :: Module HTMLTable
[hide private]
[frames] | no frames]

Source Code for Module pyjamas.ui.HTMLTable

  1  # Copyright 2006 James Tauber and contributors 
  2  # Copyright (C) 2009 Luke Kenneth Casson Leighton <lkcl@lkcl.net> 
  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  # setWidget recoded to call _mapWidget - makes support for mshtml simpler 
 17  # added by Phil Charlesworth 2010-09-16 
 18  # 
 19  # removeWidget recoded to call _unmapWidget - makes support for mshtml simpler 
 20  # added by Phil Charlesworth 2010-09-16 
 21  # 
 22   
 23  from pyjamas import DOM 
 24  from pyjamas import Factory 
 25   
 26  from pyjamas.ui.Panel import Panel 
 27  from pyjamas.ui import Event 
 28  from pyjamas.ui.CellFormatter import CellFormatter 
 29  from pyjamas.ui.RowFormatter import RowFormatter 
 30   
 31  widgethash = {} 
32 33 -class HTMLTable(Panel):
34 35 _props = [ ("border", "Border width", "BorderWidth", int), 36 ("spacing", "Spacing", "CellSpacing", None), 37 ("padding", "Padding", "CellPadding", None) 38 ] 39
40 - def __init__(self, **kwargs):
41 if not kwargs.has_key('CellFormatter'): 42 kwargs['CellFormatter'] = CellFormatter(self) 43 if not kwargs.has_key('RowFormatter'): 44 kwargs['RowFormatter'] = RowFormatter(self) 45 46 self.tableListeners = [] 47 self.dbltableListeners = [] 48 self.widgetMap = {} 49 50 if kwargs.has_key('Element'): 51 self.tableElem = kwargs.pop('Element') 52 fc = DOM.getFirstChild(self.tableElem) 53 if fc: 54 self.bodyElem = fc 55 else: 56 self.bodyElem = DOM.createTBody() 57 DOM.appendChild(self.tableElem, self.bodyElem) 58 else: 59 self.tableElem = DOM.createTable() 60 self.bodyElem = DOM.createTBody() 61 DOM.appendChild(self.tableElem, self.bodyElem) 62 self.setElement(self.tableElem) 63 64 self.sinkEvents(Event.ONCLICK | Event.ONDBLCLICK) 65 66 Panel.__init__(self, **kwargs)
67 68 @classmethod
69 - def _getProps(self):
70 return Panel._getProps() + self._props
71
72 - def addDblTableListener(self, listener):
73 self.dbltableListeners.append(listener)
74
75 - def addTableListener(self, listener):
76 self.tableListeners.append(listener)
77
78 - def clear(self):
79 for row in range(self.getRowCount()): 80 for col in range(self.getCellCount(row)): 81 child = self.getWidget(row, col) 82 if child is not None: 83 self.removeWidget(child) 84 else: 85 self.clearCell(row, col)
86 # assert len(self.widgetMap) == 0 87
88 - def clearCell(self, row, column):
89 td = self.cellFormatter.getElement(row, column) 90 return self.internalClearCell(td)
91
92 - def getCellCount(self, row):
93 return 0
94
95 - def getCellFormatter(self):
96 return self.cellFormatter
97
98 - def getCellPadding(self):
99 return DOM.getIntAttribute(self.tableElem, "cellPadding")
100
101 - def getCellSpacing(self):
102 return DOM.getIntAttribute(self.tableElem, "cellSpacing")
103
104 - def getHTML(self, row, column):
105 element = self.cellFormatter.getElement(row, column) 106 return DOM.getInnerHTML(element)
107
108 - def getRowCount(self):
109 return 0
110
111 - def getRowFormatter(self):
112 return self.rowFormatter
113
114 - def getText(self, row, column):
115 self.checkCellBounds(row, column) 116 element = self.cellFormatter.getElement(row, column) 117 return DOM.getInnerText(element)
118 119 # also callable as getWidget(widgetElement)
120 - def getWidget(self, row, column=None):
121 if column is None: 122 key = self.computeKeyForElement(row) 123 else: 124 self.checkCellBounds(row, column) 125 key = self.computeKey(row, column) 126 127 if key is None: 128 return None 129 return self.widgetMap[key]
130 131 # next three functions are part of the standard Builder API for panels
132 - def getIndex(self, widget):
133 """ given a widget, return its index. 134 """ 135 for row in xrange(self.getDOMRowCount()): 136 for col in xrange(self.getDOMCellCount(row)): 137 if self.getWidget(row, col) is widget: 138 return (row, col) 139 return None
140
141 - def getIndexedChild(self, index):
142 return self.getWidget(index[0], index[1])
143
144 - def addIndexedItem(self, index, item):
145 row, col = index 146 while row >= self.getDOMRowCount(): 147 self.insertRow(self.getDOMRowCount()) 148 while col >= self.getDOMCellCount(row): 149 self.insertCells(row, self.getDOMCellCount(row), 1) 150 self.setWidget(row, col, item)
151
152 - def add(self, item, row, col):
153 self.addIndexedItem((row, col), item)
154
155 - def isCellPresent(self, row, column):
156 # GWT uses "and", possibly a bug 157 if row >= self.getRowCount() or row < 0: 158 return False 159 160 if column < 0 or column >= self.getCellCount(row): 161 return False 162 163 return True
164
165 - def __iter__(self):
166 """ only gets widgets: does not obtain HTML or Text cells! 167 """ 168 return self.widgetMap.itervalues()
169
170 - def _onBrowserEvent(self, event, event_type):
171 172 td = self.getEventTargetCell(event) 173 if td is None: 174 return 175 tr = DOM.getParent(td) 176 body = DOM.getParent(tr) 177 row = DOM.getChildIndex(body, tr) 178 column = DOM.getChildIndex(tr, td) 179 180 if event_type == 'dblclick': 181 lists = self.dbltableListeners 182 else: 183 lists = self.tableListeners 184 185 for listener in lists: 186 if event_type == 'click' and \ 187 hasattr(listener, 'onCellClicked'): 188 listener.onCellClicked(self, row, column) 189 elif event_type == 'dblclick' and \ 190 hasattr(listener, 'onCellDoubleClicked'): 191 listener.onCellDoubleClicked(self, row, column) 192 else: 193 listener(self)
194
195 - def onBrowserEvent(self, event):
196 event_type = DOM.eventGetType(event) 197 if event_type != "dblclick" and event_type != "click": 198 return 199 200 self._onBrowserEvent(event, event_type)
201
202 - def remove(self, widget):
203 if widget.getParent() != self: 204 return False 205 206 self.removeWidget(widget) 207 return True
208
209 - def removeDblClickTableListener(self, listener):
210 self.dbltableListeners.remove(listener)
211
212 - def removeTableListener(self, listener):
213 self.tableListeners.remove(listener)
214
215 - def setBorderWidth(self, width):
216 if width is None: 217 DOM.removeAttribute(self.tableElem, "border") 218 else: 219 DOM.setAttribute(self.tableElem, "border", str(width))
220
221 - def setCellPadding(self, padding):
222 DOM.setAttribute(self.tableElem, "cellPadding", str(padding))
223
224 - def setCellSpacing(self, spacing):
225 DOM.setAttribute(self.tableElem, "cellSpacing", str(spacing))
226
227 - def setHTML(self, row, column, html):
228 self.prepareCell(row, column) 229 td = self.cleanCell(row, column) 230 if html is not None: 231 DOM.setInnerHTML(td, html)
232
233 - def setText(self, row, column, text):
234 self.prepareCell(row, column) 235 td = self.cleanCell(row, column) 236 if text is not None: 237 DOM.setInnerText(td, text)
238
239 - def setWidget(self, row, column, widget):
240 self.prepareCell(row, column) 241 if widget is None: 242 return 243 244 widget.removeFromParent() 245 td = self.cleanCell(row, column) 246 self._mapWidget(widget) 247 self.adopt(widget, td)
248
249 - def _mapWidget(self, widget):
250 widget_hash = widget 251 element = widget.getElement() 252 widgethash[element] = widget_hash 253 self.widgetMap[widget_hash] = widget
254
255 - def cleanCell(self, row, column):
256 td = self.cellFormatter.getRawElement(row, column) 257 self.internalClearCell(td) 258 return td
259
260 - def computeKey(self, row, column):
261 element = self.cellFormatter.getRawElement(row, column) 262 child = DOM.getFirstChild(element) 263 if child is None: 264 return None 265 266 return self.computeKeyForElement(child)
267
268 - def computeKeyForElement(self, widgetElement):
269 return widgethash.get(widgetElement)
270
271 - def removeWidget(self, widget):
272 self.disown(widget) 273 self._unmapWidget(widget) 274 return True
275
276 - def _unmapWidget(self, widget):
277 element = widget.getElement() 278 del self.widgetMap[self.computeKeyForElement(element)] 279 del widgethash[element]
280
281 - def checkCellBounds(self, row, column):
282 self.checkRowBounds(row) 283 #if column<0: raise IndexError, "Column " + column + " must be non-negative: " + column 284 285 cellSize = self.getCellCount(row)
286 #if cellSize<column: raise IndexError, "Column " + column + " does not exist, col at row " + row + " size is " + self.getCellCount(row) + "cell(s)" 287
288 - def checkRowBounds(self, row):
289 rowSize = self.getRowCount()
290 #if row >= rowSize or row < 0: raise IndexError, "Row " + row + " does not exist, row size is " + self.getRowCount() 291
292 - def createCell(self):
293 return DOM.createTD()
294
295 - def getBodyElement(self):
296 return self.bodyElem
297 298 # also callable as getDOMCellCount(row)
299 - def getDOMCellCount(self, element, row=None):
300 if row is None: 301 return self.getDOMCellCountImpl(self.bodyElem, element) 302 return self.getDOMCellCountImpl(element, row)
303
304 - def getDOMCellCountImpl(self, element, row):
305 return element.rows.item(row).cells.length
306 307 # also callable as getDOMRowCount(element)
308 - def getDOMRowCount(self, element=None):
309 if element is None: 310 element = self.bodyElem 311 return self.getDOMRowCountImpl(element)
312
313 - def getDOMRowCountImpl(self, element):
314 return element.rows.length
315
316 - def getEventTargetCell(self, event):
317 td = DOM.eventGetTarget(event) 318 while td is not None: 319 tagName = DOM.getAttribute(td, "tagName") 320 if tagName is not None and tagName.lower() == "td": 321 tr = DOM.getParent(td) 322 body = DOM.getParent(tr) 323 if DOM.compare(body, self.bodyElem): 324 return td 325 if DOM.compare(td, self.bodyElem): 326 return None 327 td = DOM.getParent(td) 328 329 return None
330
331 - def insertCell(self, row, column):
332 tr = self.rowFormatter.getRow(self.bodyElem, row) 333 td = self.createCell() 334 DOM.insertChild(tr, td, column)
335
336 - def insertCells(self, row, column, count):
337 tr = self.rowFormatter.getRow(self.bodyElem, row) 338 for i in range(column, column + count): 339 td = self.createCell() 340 DOM.insertChild(tr, td, i)
341
342 - def insertRow(self, beforeRow):
343 if beforeRow != self.getRowCount(): 344 self.checkRowBounds(beforeRow) 345 346 tr = DOM.createTR() 347 DOM.insertChild(self.bodyElem, tr, beforeRow) 348 return beforeRow
349
350 - def internalClearCell(self, td):
351 maybeChild = DOM.getFirstChild(td) 352 widget = None 353 if maybeChild is not None: 354 widget = self.getWidget(maybeChild) 355 356 if widget is not None: 357 self.removeWidget(widget) 358 return True 359 360 DOM.setInnerHTML(td, "") 361 return False
362
363 - def prepareCell(self, row, column):
364 pass
365
366 - def prepareRow(self, row):
367 pass
368
369 - def removeCell(self, row, column):
370 self.checkCellBounds(row, column) 371 td = self.cleanCell(row, column) 372 tr = self.rowFormatter.getRow(self.bodyElem, row) 373 DOM.removeChild(tr, td)
374
375 - def removeRow(self, row):
376 for column in range(self.getCellCount(row)): 377 self.cleanCell(row, column) 378 DOM.removeChild(self.bodyElem, self.rowFormatter.getRow(self.bodyElem, row))
379
380 - def setCellFormatter(self, cellFormatter):
381 self.cellFormatter = cellFormatter
382
383 - def setRowFormatter(self, rowFormatter):
384 self.rowFormatter = rowFormatter
385 386 Factory.registerClass('pyjamas.ui.HTMLTable', 'HTMLTable', HTMLTable) 387