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

Source Code for Module pyjamas.ui.Tree

  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  from pyjamas import DOM 
 16  from pyjamas import Factory 
 17  from __pyjamas__ import console 
 18  from sets import Set 
 19  import pygwt 
 20   
 21  from Widget import Widget 
 22  from pyjamas.ui import Event 
 23  from pyjamas.ui import Focus 
 24  from TreeItem import RootTreeItem, TreeItem 
 25  from pyjamas.ui import MouseListener 
 26  from pyjamas.ui import KeyboardListener 
 27  from pyjamas.ui import FocusListener 
 28   
29 -class Tree(Widget):
30 - def __init__(self, **kwargs):
31 if not kwargs.has_key('StyleName'): kwargs['StyleName']="gwt-Tree" 32 33 self.root = None 34 self.childWidgets = Set() 35 self.curSelection = None 36 self.focusable = None 37 self.focusListeners = [] 38 self.mouseListeners = [] 39 self.imageBase = pygwt.getModuleBaseURL() 40 self.keyboardListeners = [] 41 self.listeners = [] 42 self.lastEventType = "" 43 44 if kwargs.has_key('Element'): 45 element = kwargs.pop('Element') 46 else: 47 element = DOM.createDiv() 48 self.setElement(element) 49 DOM.setStyleAttribute(self.getElement(), "position", "relative") 50 self.focusable = Focus.createFocusable() 51 # Hide focus outline in Mozilla/Webkit/Opera 52 DOM.setStyleAttribute(self.focusable, "outline", "0px") 53 # Hide focus outline in IE 6/7 54 DOM.setElemAttribute(self.focusable, "hideFocus", "true"); 55 56 DOM.setStyleAttribute(self.focusable, "fontSize", "0") 57 DOM.setStyleAttribute(self.focusable, "position", "absolute") 58 DOM.setIntStyleAttribute(self.focusable, "zIndex", -1) 59 DOM.appendChild(self.getElement(), self.focusable) 60 61 self.root = RootTreeItem() 62 self.root.setTree(self) 63 64 Widget.__init__(self, **kwargs) 65 66 self.sinkEvents(Event.ONMOUSEDOWN | Event.ONCLICK | Event.KEYEVENTS) 67 #DOM.sinkEvents(self.focusable, Event.FOCUSEVENTS | Event.KEYEVENTS | DOM.getEventsSunk(self.focusable)) 68 DOM.sinkEvents(self.focusable, Event.FOCUSEVENTS)
69
70 - def add(self, widget):
71 self.addItem(widget)
72
73 - def addFocusListener(self, listener):
74 self.focusListeners.append(listener)
75
76 - def addItem(self, item):
77 return self.insertItem(item)
78
79 - def insertItem(self, item, index=None):
80 if isinstance(item, str): 81 item = TreeItem(item) 82 83 ret = self.root.addItem(item) 84 if index is None: 85 DOM.appendChild(self.getElement(), item.getElement()) 86 else: 87 DOM.insertChild(self.getElement(), item.getElement(), index) 88 89 return ret
90
91 - def addKeyboardListener(self, listener):
92 self.keyboardListeners.append(listener)
93
94 - def addMouseListener(self, listener):
95 self.mouseListeners.append(listener)
96
97 - def addTreeListener(self, listener):
98 self.listeners.append(listener)
99
100 - def clear(self):
101 size = self.root.getChildCount() 102 for i in range(size, 0, -1): 103 self.root.getChild(i-1).remove()
104
106 if self.curSelection is None: 107 return 108 109 parent = self.curSelection.getParentItem() 110 while parent is not None: 111 parent.setState(True) 112 parent = parent.getParentItem()
113
114 - def getImageBase(self):
115 return self.imageBase
116
117 - def getItem(self, index):
118 return self.root.getChild(index)
119
120 - def getItemCount(self):
121 return self.root.getChildCount()
122
123 - def getSelectedItem(self):
124 return self.curSelection
125
126 - def getTabIndex(self):
127 return Focus.getTabIndex(self.focusable)
128
129 - def __iter__(self):
130 return self.childWidgets.__iter__()
131
132 - def onBrowserEvent(self, event):
133 type = DOM.eventGetType(event) 134 135 if type == "click": 136 e = DOM.eventGetTarget(event) 137 if not self.shouldTreeDelegateFocusToElement(e) and \ 138 self.curSelection is not None: 139 self.setFocus(True) 140 elif type == "mousedown": 141 MouseListener.fireMouseEvent(self.mouseListeners, self, event) 142 self.elementClicked(self.root, DOM.eventGetTarget(event)) 143 elif type == "mouseup" or type == "mousemove" or type == "mouseover" or type == "mouseout": 144 MouseListener.fireMouseEvent(self.mouseListeners, self, event) 145 elif type == "blur" or type == "focus": 146 FocusListener.fireFocusEvent(self.focusListeners, self, event) 147 elif type == "keydown": 148 if self.curSelection is None: 149 if self.root.getChildCount() > 0: 150 self.onSelection(self.root.getChild(0), True) 151 Widget.onBrowserEvent(self, event) 152 return 153 154 if self.lastEventType == "keydown": 155 return 156 157 keycode = DOM.eventGetKeyCode(event) 158 if keycode == KeyboardListener.KEY_UP: 159 self.moveSelectionUp(self.curSelection, True) 160 DOM.eventPreventDefault(event) 161 elif keycode == KeyboardListener.KEY_DOWN: 162 self.moveSelectionDown(self.curSelection, True) 163 DOM.eventPreventDefault(event) 164 elif keycode == KeyboardListener.KEY_LEFT: 165 if self.curSelection.getState(): 166 self.curSelection.setState(False) 167 DOM.eventPreventDefault(event) 168 elif keycode == KeyboardListener.KEY_RIGHT: 169 if not self.curSelection.getState(): 170 self.curSelection.setState(True) 171 DOM.eventPreventDefault(event) 172 elif type == "keyup": 173 if DOM.eventGetKeyCode(event) == KeyboardListener.KEY_TAB: 174 chain = [] 175 self.collectElementChain(chain, self.getElement(), DOM.eventGetTarget(event)) 176 item = self.findItemByChain(chain, 0, self.root) 177 if item != self.getSelectedItem(): 178 self.setSelectedItem(item, True) 179 elif type == "keypress": 180 KeyboardListener.fireKeyboardEvent(self.keyboardListeners, self, event) 181 182 Widget.onBrowserEvent(self, event) 183 self.lastEventType = type
184
185 - def remove(self, widget):
186 #throw new UnsupportedOperationException("Widgets should never be directly removed from a tree") 187 console.error("Widgets should never be directly removed from a tree")
188
189 - def removeFocusListener(self, listener):
190 self.focusListeners.remove(listener)
191
192 - def removeItem(self, item):
193 self.root.removeItem(item) 194 DOM.removeChild(self.getElement(), item.getElement())
195
196 - def removeItems(self):
197 while self.getItemCount() > 0: 198 self.removeItem(self.getItem(0))
199
200 - def removeKeyboardListener(self, listener):
201 self.keyboardListeners.remove(listener)
202
203 - def removeTreeListener(self, listener):
204 self.listeners.remove(listener)
205
206 - def setAccessKey(self, key):
207 Focus.setAccessKey(self.focusable, key)
208
209 - def setFocus(self, focus):
210 if focus: 211 Focus.focus(self.focusable) 212 else: 213 Focus.blur(self.focusable)
214
215 - def setImageBase(self, baseUrl):
216 self.imageBase = baseUrl 217 self.root.updateStateRecursive()
218
219 - def setSelectedItem(self, item, fireEvents=True):
220 if item is None: 221 if self.curSelection is None: 222 return 223 self.curSelection.setSelected(False) 224 self.curSelection = None 225 return 226 227 self.onSelection(item, fireEvents)
228
229 - def setTabIndex(self, index):
230 Focus.setTabIndex(self.focusable, index)
231
232 - def treeItemIterator(self):
233 accum = [] 234 self.root.addTreeItems(accum) 235 return accum.__iter__()
236
237 - def collectElementChain(self, chain, hRoot, hElem):
238 if (hElem is None) or DOM.compare(hElem, hRoot): 239 return 240 241 self.collectElementChain(chain, hRoot, DOM.getParent(hElem)) 242 chain.append(hElem)
243
244 - def elementClicked(self, root, hElem):
245 chain = [] 246 self.collectElementChain(chain, self.getElement(), hElem) 247 248 item = self.findItemByChain(chain, 0, root) 249 if item is not None: 250 if DOM.compare(item.getImageElement(), hElem): 251 item.setState(not item.getState(), True) 252 return True 253 elif DOM.isOrHasChild(item.getElement(), hElem): 254 self.onSelection(item, True) 255 return True 256 257 return False
258
259 - def findDeepestOpenChild(self, item):
260 if not item.getState(): 261 return item 262 return self.findDeepestOpenChild(item.getChild(item.getChildCount() - 1))
263
264 - def findItemByChain(self, chain, idx, root):
265 if idx == len(chain): 266 return root 267 268 hCurElem = chain[idx] 269 for i in range(root.getChildCount()): 270 child = root.getChild(i) 271 if DOM.compare(child.getElement(), hCurElem): 272 retItem = self.findItemByChain(chain, idx + 1, root.getChild(i)) 273 if retItem is None: 274 return child 275 return retItem 276 277 return self.findItemByChain(chain, idx + 1, root)
278
279 - def moveFocus(self, selection):
280 focusableWidget = selection.getFocusableWidget() 281 if focusableWidget is not None: 282 focusableWidget.setFocus(True) 283 DOM.scrollIntoView(focusableWidget.getElement()) 284 else: 285 selectedElem = selection.getContentElem() 286 containerLeft = self.getAbsoluteLeft() 287 containerTop = self.getAbsoluteTop() 288 289 left = DOM.getAbsoluteLeft(selectedElem) - containerLeft 290 top = DOM.getAbsoluteTop(selectedElem) - containerTop 291 width = DOM.getIntAttribute(selectedElem, "offsetWidth") 292 height = DOM.getIntAttribute(selectedElem, "offsetHeight") 293 294 DOM.setIntStyleAttribute(self.focusable, "left", left) 295 DOM.setIntStyleAttribute(self.focusable, "top", top) 296 DOM.setIntStyleAttribute(self.focusable, "width", width) 297 DOM.setIntStyleAttribute(self.focusable, "height", height) 298 299 DOM.scrollIntoView(self.focusable) 300 Focus.focus(self.focusable)
301
302 - def moveSelectionDown(self, sel, dig):
303 if sel == self.root: 304 return 305 306 parent = sel.getParentItem() 307 if parent is None: 308 parent = self.root 309 idx = parent.getChildIndex(sel) 310 311 if not dig or not sel.getState(): 312 if idx < parent.getChildCount() - 1: 313 self.onSelection(parent.getChild(idx + 1), True) 314 else: 315 self.moveSelectionDown(parent, False) 316 elif sel.getChildCount() > 0: 317 self.onSelection(sel.getChild(0), True)
318
319 - def moveSelectionUp(self, sel, climb):
320 parent = sel.getParentItem() 321 if parent is None: 322 parent = self.root 323 idx = parent.getChildIndex(sel) 324 325 if idx > 0: 326 sibling = parent.getChild(idx - 1) 327 self.onSelection(self.findDeepestOpenChild(sibling), True) 328 else: 329 self.onSelection(parent, True)
330
331 - def onSelection(self, item, fireEvents):
332 if item == self.root: 333 return 334 335 if self.curSelection is not None: 336 self.curSelection.setSelected(False) 337 338 self.curSelection = item 339 340 if self.curSelection is not None: 341 self.moveFocus(self.curSelection) 342 self.curSelection.setSelected(True) 343 if fireEvents and len(self.listeners): 344 for listener in self.listeners: 345 listener.onTreeItemSelected(item)
346
347 - def doAttachChildren(self):
348 for child in self: 349 child.onAttach() 350 DOM.setEventListener(self.focusable, self);
351
352 - def doDetachChildren(self):
353 for child in self: 354 child.onDetach() 355 DOM.setEventListener(self.focusable, None);
356
357 - def onLoad(self):
358 self.root.updateStateRecursive()
359
360 - def adopt(self, content):
361 self.childWidgets.add(content) 362 content.treeSetParent(self)
363
364 - def disown(self, item):
365 self.childWidgets.remove(item) 366 item.treeSetParent(None)
367
368 - def fireStateChanged(self, item):
369 for listener in self.listeners: 370 if hasattr(listener, "onTreeItemStateChanged"): 371 listener.onTreeItemStateChanged(item)
372
373 - def getChildWidgets(self):
374 return self.childWidgets
375
376 - def shouldTreeDelegateFocusToElement(self, elem):
377 name = str(elem.nodeName) 378 name = name.lower() 379 return name == 'select' or\ 380 name == 'input' or\ 381 name == 'checkbox'
382 383 Factory.registerClass('pyjamas.ui.Tree', Tree) 384