예제 #1
0
파일: Tree.py 프로젝트: anandology/pyjamas
class Tree(Widget):
    def __init__(self, **ka):
        ka['StyleName'] = ka.get('StyleName', "gwt-Tree")

        self.root = None
        self.childWidgets = Set()
        self.curSelection = None
        self.focusable = None
        self.focusListeners = []
        self.mouseListeners = []
        self.imageBase = pygwt.getModuleBaseURL()
        self.keyboardListeners = []
        self.listeners = []
        self.lastEventType = ""

        element = ka.pop('Element', None) or DOM.createDiv()
        self.setElement(element)
        DOM.setStyleAttribute(self.getElement(), "position", "relative")
        self.focusable = Focus.createFocusable()
        # Hide focus outline in Mozilla/Webkit/Opera
        DOM.setStyleAttribute(self.focusable, "outline", "0px")
        # Hide focus outline in IE 6/7
        DOM.setElemAttribute(self.focusable, "hideFocus", "true");

        DOM.setStyleAttribute(self.focusable, "fontSize", "0")
        DOM.setStyleAttribute(self.focusable, "position", "absolute")
        DOM.setIntStyleAttribute(self.focusable, "zIndex", -1)
        DOM.appendChild(self.getElement(), self.focusable)

        self.root = RootTreeItem()
        self.root.setTree(self)

        Widget.__init__(self, **ka)

        self.sinkEvents(Event.ONMOUSEDOWN | Event.ONCLICK | Event.KEYEVENTS)
        DOM.sinkEvents(self.focusable, Event.FOCUSEVENTS)

    def add(self, widget):
        self.addItem(widget)

    def addFocusListener(self, listener):
        self.focusListeners.append(listener)

    def addItem(self, item):
        return self.insertItem(item)

    def insertItem(self, item, index=None):
        if isinstance(item, basestring):
            item = TreeItem(item)

        ret = self.root.addItem(item)
        if index is None:
            DOM.appendChild(self.getElement(), item.getElement())
        else:
            DOM.insertChild(self.getElement(), item.getElement(), index)

        return ret

    def addKeyboardListener(self, listener):
        self.keyboardListeners.append(listener)

    def addMouseListener(self, listener):
        self.mouseListeners.append(listener)

    def addTreeListener(self, listener):
        self.listeners.append(listener)

    def clear(self):
        size = self.root.getChildCount()
        for i in range(size, 0, -1):
            self.root.getChild(i-1).remove()

    def ensureSelectedItemVisible(self):
        if self.curSelection is None:
            return

        parent = self.curSelection.getParentItem()
        while parent is not None:
            parent.setState(True)
            parent = parent.getParentItem()

    def getImageBase(self):
        return self.imageBase

    def getItem(self, index):
        return self.root.getChild(index)

    def getItemCount(self):
        return self.root.getChildCount()

    def getSelectedItem(self):
        return self.curSelection

    def getTabIndex(self):
        return Focus.getTabIndex(self.focusable)

    def __iter__(self):
        return self.root.__iter__()

    def onBrowserEvent(self, event):
        etype = DOM.eventGetType(event)

        if etype == "click":
            e = DOM.eventGetTarget(event)
            if not self.shouldTreeDelegateFocusToElement(e) and \
                            self.curSelection is not None:
                self.setFocus(True)
        elif etype in MouseListener.MOUSE_EVENTS:
            if etype == "mousedown":
                self.elementClicked(self.root, DOM.eventGetTarget(event))
            MouseListener.fireMouseEvent(self.mouseListeners, self, event)
        elif etype == "blur" or etype == "focus":
            FocusListener.fireFocusEvent(self.focusListeners, self, event)
        elif etype == "keydown":
            if self.curSelection is None:
                if self.root.getChildCount() > 0:
                    self.onSelection(self.root.getChild(0), True)
                Widget.onBrowserEvent(self, event)
                return

            if self.lastEventType == "keydown":
                return

            keycode = DOM.eventGetKeyCode(event)
            if keycode == KeyboardListener.KEY_UP:
                self.moveSelectionUp(self.curSelection, True)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_DOWN:
                self.moveSelectionDown(self.curSelection, True)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_LEFT:
                if self.curSelection.getState():
                    self.curSelection.setState(False)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_RIGHT:
                if not self.curSelection.getState():
                    self.curSelection.setState(True)
                DOM.eventPreventDefault(event)
        elif etype == "keyup":
            if DOM.eventGetKeyCode(event) == KeyboardListener.KEY_TAB:
                chain = []
                self.collectElementChain(chain, self.getElement(),
                                         DOM.eventGetTarget(event))
                item = self.findItemByChain(chain, 0, self.root)
                if item != self.getSelectedItem():
                    self.setSelectedItem(item, True)
        elif etype == "keypress":
            KeyboardListener.fireKeyboardEvent(self.keyboardListeners,
                                               self, event)

        Widget.onBrowserEvent(self, event)
        self.lastEventType = etype

    def remove(self, widget):
        raise Exception("Widgets should never be directly removed from a tree")

    def removeFocusListener(self, listener):
        self.focusListeners.remove(listener)

    def removeItem(self, item):
        self.root.removeItem(item)
        DOM.removeChild(self.getElement(), item.getElement())

    def removeItems(self):
        while self.getItemCount() > 0:
            self.removeItem(self.getItem(0))

    def removeKeyboardListener(self, listener):
        self.keyboardListeners.remove(listener)

    def removeTreeListener(self, listener):
        self.listeners.remove(listener)

    def setAccessKey(self, key):
        Focus.setAccessKey(self.focusable, key)

    def setFocus(self, focus):
        if focus:
            Focus.focus(self.focusable)
        else:
            Focus.blur(self.focusable)

    def setImageBase(self, baseUrl):
        self.imageBase = baseUrl
        self.root.updateStateRecursive()

    def setSelectedItem(self, item, fireEvents=True):
        if item is None:
            if self.curSelection is None:
                return
            self.curSelection.setSelected(False)
            self.curSelection = None
            return

        self.onSelection(item, fireEvents)

    def setTabIndex(self, index):
        Focus.setTabIndex(self.focusable, index)

    def treeItemIterator(self):
        accum = []
        self.root.addTreeItems(accum)
        return accum.__iter__()

    def collectElementChain(self, chain, hRoot, hElem):
        if (hElem is None) or DOM.compare(hElem, hRoot):
            return

        self.collectElementChain(chain, hRoot, DOM.getParent(hElem))
        chain.append(hElem)

    def elementClicked(self, root, hElem):
        chain = []
        self.collectElementChain(chain, self.getElement(), hElem)

        item = self.findItemByChain(chain, 0, root)
        if item is not None:
            if DOM.compare(item.getImageElement(), hElem):
                item.setState(not item.getState(), True)
                return True
            elif DOM.isOrHasChild(item.getElement(), hElem):
                self.onSelection(item, True)
                return True

        return False

    def findDeepestOpenChild(self, item):
        if not item.getState():
            return item
        return self.findDeepestOpenChild(item.getChild(item.getChildCount()-1))

    def findItemByChain(self, chain, idx, root):
        if idx == len(chain):
            return root

        hCurElem = chain[idx]
        for i in range(root.getChildCount()):
            child = root.getChild(i)
            if DOM.compare(child.getElement(), hCurElem):
                retItem = self.findItemByChain(chain, idx + 1, root.getChild(i))
                if retItem is None:
                    return child
                return retItem

        return self.findItemByChain(chain, idx + 1, root)

    def moveFocus(self, selection):
        focusableWidget = selection.getFocusableWidget()
        if focusableWidget is not None:
            focusableWidget.setFocus(True)
            DOM.scrollIntoView(focusableWidget.getElement())
        else:
            selectedElem = selection.getContentElem()
            containerLeft = self.getAbsoluteLeft()
            containerTop = self.getAbsoluteTop()

            left = DOM.getAbsoluteLeft(selectedElem) - containerLeft
            top = DOM.getAbsoluteTop(selectedElem) - containerTop
            width = DOM.getIntAttribute(selectedElem, "offsetWidth")
            height = DOM.getIntAttribute(selectedElem, "offsetHeight")

            DOM.setIntStyleAttribute(self.focusable, "left", left)
            DOM.setIntStyleAttribute(self.focusable, "top", top)
            DOM.setIntStyleAttribute(self.focusable, "width", width)
            DOM.setIntStyleAttribute(self.focusable, "height", height)

            DOM.scrollIntoView(self.focusable)
            Focus.focus(self.focusable)

    def moveSelectionDown(self, sel, dig):
        if sel == self.root:
            return

        parent = sel.getParentItem()
        if parent is None:
            parent = self.root
        idx = parent.getChildIndex(sel)

        if not dig or not sel.getState():
            if idx < parent.getChildCount() - 1:
                self.onSelection(parent.getChild(idx + 1), True)
            else:
                self.moveSelectionDown(parent, False)
        elif sel.getChildCount() > 0:
            self.onSelection(sel.getChild(0), True)

    def moveSelectionUp(self, sel, climb):
        parent = sel.getParentItem()
        if parent is None:
            parent = self.root
        idx = parent.getChildIndex(sel)

        if idx > 0:
            sibling = parent.getChild(idx - 1)
            self.onSelection(self.findDeepestOpenChild(sibling), True)
        else:
            self.onSelection(parent, True)

    def onSelection(self, item, fireEvents):
        if item == self.root:
            return

        if fireEvents and len(self.listeners):
            for listener in self.listeners:
                onBefore = getattr(listener, "onBeforeTreeItemSelected", None)
                if onBefore is not None:
                    if not onBefore(item):
                        return

        if self.curSelection is not None:
            self.curSelection.setSelected(False)

        self.curSelection = item

        if self.curSelection is not None:
            self.moveFocus(self.curSelection)
            self.curSelection.setSelected(True)
            if fireEvents and len(self.listeners):
                for listener in self.listeners:
                    listener.onTreeItemSelected(item)

    def doAttachChildren(self):
        for child in self:
            child.onAttach()
        DOM.setEventListener(self.focusable, self);

    def doDetachChildren(self):
        for child in self:
            child.onDetach()
        DOM.setEventListener(self.focusable, None);

    def onLoad(self):
        self.root.updateStateRecursive()

    def adopt(self, content):
        self.childWidgets.add(content)
        content.treeSetParent(self)

    def disown(self, item):
        self.childWidgets.remove(item)
        item.treeSetParent(None)

    def fireStateChanged(self, item):
        for listener in self.listeners:
            if hasattr(listener, "onTreeItemStateChanged"):
                listener.onTreeItemStateChanged(item)

    def getChildWidgets(self):
        return self.childWidgets

    def shouldTreeDelegateFocusToElement(self, elem):
        name = str(elem.nodeName)
        name = name.lower()
        return name == 'select' or \
               name == 'input' or \
               name == 'checkbox'
예제 #2
0
class Tree(Widget):
    def __init__(self, **ka):
        ka['StyleName'] = ka.get('StyleName', "gwt-Tree")

        self.root = None
        self.childWidgets = Set()
        self.curSelection = None
        self.focusable = None
        self.focusListeners = []
        self.mouseListeners = []
        self.images = ka.pop('Images', False)
        self.imageBase = pygwt.getImageBaseURL(self.images)
        self.keyboardListeners = []
        self.listeners = []
        self.lastEventType = ""

        element = ka.pop('Element', None) or DOM.createDiv()
        self.setElement(element)
        DOM.setStyleAttribute(self.getElement(), "position", "relative")
        self.focusable = Focus.createFocusable()
        # Hide focus outline in Mozilla/Webkit/Opera
        DOM.setStyleAttribute(self.focusable, "outline", "0px")
        # Hide focus outline in IE 6/7
        DOM.setElemAttribute(self.focusable, "hideFocus", "true")

        DOM.setStyleAttribute(self.focusable, "fontSize", "0")
        DOM.setStyleAttribute(self.focusable, "position", "absolute")
        DOM.setIntStyleAttribute(self.focusable, "zIndex", -1)
        DOM.appendChild(self.getElement(), self.focusable)

        self.root = RootTreeItem()
        self.root.setTree(self)

        Widget.__init__(self, **ka)

        self.sinkEvents(Event.ONMOUSEDOWN | Event.ONCLICK | Event.KEYEVENTS)
        DOM.sinkEvents(self.focusable, Event.FOCUSEVENTS)

    def add(self, widget):
        self.addItem(widget)

    def addFocusListener(self, listener):
        self.focusListeners.append(listener)

    def addItem(self, item):
        return self.insertItem(item)

    def insertItem(self, item, index=None):
        if isinstance(item, basestring):
            item = TreeItem(item)

        ret = self.root.addItem(item)
        if index is None:
            DOM.appendChild(self.getElement(), item.getElement())
        else:
            DOM.insertChild(self.getElement(), item.getElement(), index)

        return ret

    def addKeyboardListener(self, listener):
        self.keyboardListeners.append(listener)

    def addMouseListener(self, listener):
        self.mouseListeners.append(listener)

    def addTreeListener(self, listener):
        self.listeners.append(listener)

    def clear(self):
        size = self.root.getChildCount()
        for i in range(size, 0, -1):
            self.root.getChild(i - 1).remove()

    def ensureSelectedItemVisible(self):
        if self.curSelection is None:
            return

        parent = self.curSelection.getParentItem()
        while parent is not None:
            parent.setState(True)
            parent = parent.getParentItem()

    def getImageBase(self):
        return self.imageBase

    def getImages(self):
        return self.images

    def getItem(self, index):
        return self.root.getChild(index)

    def getItemCount(self):
        return self.root.getChildCount()

    def getSelectedItem(self):
        return self.curSelection

    def getTabIndex(self):
        return Focus.getTabIndex(self.focusable)

    def __iter__(self):
        return self.root.__iter__()

    def onBrowserEvent(self, event):
        etype = DOM.eventGetType(event)

        if etype == "click":
            e = DOM.eventGetTarget(event)
            if not self.shouldTreeDelegateFocusToElement(e) and \
                            self.curSelection is not None:
                self.setFocus(True)
        elif etype in MouseListener.MOUSE_EVENTS:
            if etype == "mousedown":
                self.elementClicked(self.root, DOM.eventGetTarget(event))
            MouseListener.fireMouseEvent(self.mouseListeners, self, event)
        elif etype == "blur" or etype == "focus":
            FocusListener.fireFocusEvent(self.focusListeners, self, event)
        elif etype == "keydown":
            if self.curSelection is None:
                if self.root.getChildCount() > 0:
                    self.onSelection(self.root.getChild(0), True)
                Widget.onBrowserEvent(self, event)
                return

            if self.lastEventType == "keydown":
                return

            keycode = DOM.eventGetKeyCode(event)
            if keycode == KeyboardListener.KEY_UP:
                self.moveSelectionUp(self.curSelection, True)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_DOWN:
                self.moveSelectionDown(self.curSelection, True)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_LEFT:
                if self.curSelection.getState():
                    self.curSelection.setState(False)
                DOM.eventPreventDefault(event)
            elif keycode == KeyboardListener.KEY_RIGHT:
                if not self.curSelection.getState():
                    self.curSelection.setState(True)
                DOM.eventPreventDefault(event)
        elif etype == "keyup":
            if DOM.eventGetKeyCode(event) == KeyboardListener.KEY_TAB:
                chain = []
                self.collectElementChain(chain, self.getElement(),
                                         DOM.eventGetTarget(event))
                item = self.findItemByChain(chain, 0, self.root)
                if item != self.getSelectedItem():
                    self.setSelectedItem(item, True)
        elif etype == "keypress":
            KeyboardListener.fireKeyboardEvent(self.keyboardListeners, self,
                                               event)

        Widget.onBrowserEvent(self, event)
        self.lastEventType = etype

    def remove(self, widget):
        raise Exception("Widgets should never be directly removed from a tree")

    def removeFocusListener(self, listener):
        self.focusListeners.remove(listener)

    def removeItem(self, item):
        self.root.removeItem(item)
        DOM.removeChild(self.getElement(), item.getElement())

    def removeItems(self):
        while self.getItemCount() > 0:
            self.removeItem(self.getItem(0))

    def removeKeyboardListener(self, listener):
        self.keyboardListeners.remove(listener)

    def removeTreeListener(self, listener):
        self.listeners.remove(listener)

    def setAccessKey(self, key):
        Focus.setAccessKey(self.focusable, key)

    def setFocus(self, focus):
        if focus:
            Focus.focus(self.focusable)
        else:
            Focus.blur(self.focusable)

    def setImageBase(self, baseUrl):
        self.imageBase = baseUrl
        self.root.updateStateRecursive()

    def setImages(self, images):
        if self.images == images:
            return
        self.images = images
        self.setImageBase(pygwt.getImageBaseURL(self.images))

    def setSelectedItem(self, item, fireEvents=True):
        if item is None:
            if self.curSelection is None:
                return
            self.curSelection.setSelected(False)
            self.curSelection = None
            return

        self.onSelection(item, fireEvents)

    def setTabIndex(self, index):
        Focus.setTabIndex(self.focusable, index)

    def treeItemIterator(self):
        accum = []
        self.root.addTreeItems(accum)
        return accum.__iter__()

    def collectElementChain(self, chain, hRoot, hElem):
        if (hElem is None) or DOM.compare(hElem, hRoot):
            return

        self.collectElementChain(chain, hRoot, DOM.getParent(hElem))
        chain.append(hElem)

    def elementClicked(self, root, hElem):
        chain = []
        self.collectElementChain(chain, self.getElement(), hElem)

        item = self.findItemByChain(chain, 0, root)
        if item is not None:
            if DOM.compare(item.getImageElement(), hElem):
                item.setState(not item.getState(), True)
                return True
            elif DOM.isOrHasChild(item.getElement(), hElem):
                self.onSelection(item, True)
                return True

        return False

    def findDeepestOpenChild(self, item):
        if not item.getState():
            return item
        return self.findDeepestOpenChild(
            item.getChild(item.getChildCount() - 1))

    def findItemByChain(self, chain, idx, root):
        if idx == len(chain):
            return root

        hCurElem = chain[idx]
        for i in range(root.getChildCount()):
            child = root.getChild(i)
            if DOM.compare(child.getElement(), hCurElem):
                retItem = self.findItemByChain(chain, idx + 1,
                                               root.getChild(i))
                if retItem is None:
                    return child
                return retItem

        return self.findItemByChain(chain, idx + 1, root)

    def moveFocus(self, selection):
        focusableWidget = selection.getFocusableWidget()
        if focusableWidget is not None:
            focusableWidget.setFocus(True)
            DOM.scrollIntoView(focusableWidget.getElement())
        else:
            selectedElem = selection.getContentElem()
            containerLeft = self.getAbsoluteLeft()
            containerTop = self.getAbsoluteTop()

            left = DOM.getAbsoluteLeft(selectedElem) - containerLeft
            top = DOM.getAbsoluteTop(selectedElem) - containerTop
            width = DOM.getIntAttribute(selectedElem, "offsetWidth")
            height = DOM.getIntAttribute(selectedElem, "offsetHeight")

            DOM.setIntStyleAttribute(self.focusable, "left", "%spx" % left)
            DOM.setIntStyleAttribute(self.focusable, "top", "%spx" % top)
            DOM.setIntStyleAttribute(self.focusable, "width", "%spx" % width)
            DOM.setIntStyleAttribute(self.focusable, "height", "%spx" % height)

            DOM.scrollIntoView(self.focusable)
            Focus.focus(self.focusable)

    def moveSelectionDown(self, sel, dig):
        if sel == self.root:
            return

        parent = sel.getParentItem()
        if parent is None:
            parent = self.root
        idx = parent.getChildIndex(sel)

        if not dig or not sel.getState():
            if idx < parent.getChildCount() - 1:
                self.onSelection(parent.getChild(idx + 1), True)
            else:
                self.moveSelectionDown(parent, False)
        elif sel.getChildCount() > 0:
            self.onSelection(sel.getChild(0), True)

    def moveSelectionUp(self, sel, climb):
        parent = sel.getParentItem()
        if parent is None:
            parent = self.root
        idx = parent.getChildIndex(sel)

        if idx > 0:
            sibling = parent.getChild(idx - 1)
            self.onSelection(self.findDeepestOpenChild(sibling), True)
        else:
            self.onSelection(parent, True)

    def onSelection(self, item, fireEvents):
        if item == self.root:
            return

        if fireEvents and len(self.listeners):
            for listener in self.listeners:
                onBefore = getattr(listener, "onBeforeTreeItemSelected", None)
                if onBefore is not None:
                    if not onBefore(item):
                        return

        if self.curSelection is not None:
            self.curSelection.setSelected(False)

        self.curSelection = item

        if self.curSelection is not None:
            self.moveFocus(self.curSelection)
            self.curSelection.setSelected(True)
            if fireEvents and len(self.listeners):
                for listener in self.listeners:
                    listener.onTreeItemSelected(item)

    def doAttachChildren(self):
        for child in self:
            child.onAttach()
        DOM.setEventListener(self.focusable, self)

    def doDetachChildren(self):
        for child in self:
            child.onDetach()
        DOM.setEventListener(self.focusable, None)

    def onLoad(self):
        self.root.updateStateRecursive()

    def adopt(self, content):
        self.childWidgets.add(content)
        content.treeSetParent(self)

    def disown(self, item):
        self.childWidgets.remove(item)
        item.treeSetParent(None)

    def fireStateChanged(self, item):
        for listener in self.listeners:
            if hasattr(listener, "onTreeItemStateChanged"):
                listener.onTreeItemStateChanged(item)

    def getChildWidgets(self):
        return self.childWidgets

    def shouldTreeDelegateFocusToElement(self, elem):
        name = str(elem.nodeName)
        name = name.lower()
        return name == 'select' or \
               name == 'input' or \
               name == 'checkbox'