/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org 2006 by Derrell Lipman License: LGPL 2.1: http://www.gnu.org/licenses/lgpl.html Authors: * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) * Derrell Lipman (derrell) ************************************************************************ */ /* ************************************************************************ #module(ui_treefullcontrol) ************************************************************************ */ /** * qx.ui.treefullcontrol.Tree objects are tree root nodes but act like * TreeFolder. * * @param treeRowStructure An instance of qx.ui.treefullcontrol.TreeRowStructure, * defining the structure of this tree row. */ qx.OO.defineClass("qx.ui.treefullcontrol.Tree", qx.ui.treefullcontrol.TreeFolder, function(treeRowStructure) { qx.ui.treefullcontrol.TreeFolder.call(this, treeRowStructure); // ************************************************************************ // INITILISIZE MANAGER // ************************************************************************ this._manager = new qx.manager.selection.TreeFullControlSelectionManager(this); this._iconObject.setAppearance("tree-icon"); this._labelObject.setAppearance("tree-label"); // ************************************************************************ // DEFAULT STATE // ************************************************************************ // The tree should be open by default this.setOpen(true); // Fix vertical alignment of empty tree this.addToFolder(); // ************************************************************************ // KEY EVENT LISTENER // ************************************************************************ this.addEventListener("keydown", this._onkeydown); this.addEventListener("keypress", this._onkeypress); this.addEventListener("keyup", this._onkeyup); }); /* --------------------------------------------------------------------------- PROPERTIES --------------------------------------------------------------------------- */ qx.OO.addProperty({ name : "useDoubleClick", type : "boolean", defaultValue : false, getAlias : "useDoubleClick" }); qx.OO.addProperty({ name : "useTreeLines", type : "boolean", defaultValue : true, getAlias : "useTreeLines" }); /*! In specific applications, it is desirable to omit tree lines for only certain indentation levels. This property provides an array wherein the index of the array corresponds to the indentation level, counted from left to right; and the value of that element, if it contains, specifically, the boolean value true, indicates that tree lines at that indentation level are to be omitted. Any value of that element other than true, or if an indentation level's index does not exist in the array, means that tree lines should be displayed for that indentation level. (There are some minor code efficiencies that are realized if this array is empty, so after having set an element to true and desiring to reset the default behavior, you should 'delete' the element rather than setting it to some value other than true.) If useTreeLines is false, then all tree lines are excluded and this property is ignored. */ qx.OO.addProperty({ name : "excludeSpecificTreeLines", type : "object", defaultValue : [] }); /*! Hide the root (Tree) node. This differs from the visibility property in that this property hides *only* the current node, not the node's children. */ qx.OO.addProperty({ name : "hideNode", type : "boolean", defaultValue : false, getAlias : "hideNode" }); /*! Whether the Root should have an open/close button. This may also be used in conjunction with the hideNode property to provide for virtual root nodes. In the latter case, be very sure that the virtual root nodes are expanded programatically, since there will be no open/close button for the user to open them. */ qx.OO.addProperty({ name : "rootOpenClose", type : "boolean", defaultValue : true }); /* --------------------------------------------------------------------------- MANAGER BINDING --------------------------------------------------------------------------- */ qx.Proto.getManager = function() { return this._manager; } qx.Proto.getSelectedElement = function() { return this.getManager().getSelectedItems()[0]; } /* --------------------------------------------------------------------------- QUEUE HANDLING --------------------------------------------------------------------------- */ qx.Proto.addChildToTreeQueue = function(vChild) { if (!vChild._isInTreeQueue && !vChild._isDisplayable) { this.debug("Ignoring invisible child: " + vChild); } if (!vChild._isInTreeQueue && vChild._isDisplayable) { qx.ui.core.Widget.addToGlobalWidgetQueue(this); if (!this._treeQueue) { this._treeQueue = {}; } this._treeQueue[vChild.toHashCode()] = vChild; vChild._isInTreeQueue = true; } } qx.Proto.removeChildFromTreeQueue = function(vChild) { if (vChild._isInTreeQueue) { if (this._treeQueue) { delete this._treeQueue[vChild.toHashCode()]; } delete vChild._isInTreeQueue; } } qx.Proto.flushWidgetQueue = function() { this.flushTreeQueue(); } qx.Proto.flushTreeQueue = function() { if (!qx.lang.Object.isEmpty(this._treeQueue)) { for (var vHashCode in this._treeQueue) { // this.debug("Flushing Tree Child: " + this._treeQueue[vHashCode]); this._treeQueue[vHashCode].flushTree(); delete this._treeQueue[vHashCode]._isInTreeQueue; } delete this._treeQueue; } } /* --------------------------------------------------------------------------- MODIFIER --------------------------------------------------------------------------- */ qx.Proto._modifyUseTreeLines = function(propValue, propOldValue, propData) { if (this._initialLayoutDone) { this._updateIndent(); } return true; } qx.Proto._modifyHideNode = function(propValue, propOldValue, propData) { if (! propValue) { this._horizontalLayout.setHeight(this._horizontalLayout.originalHeight); this._horizontalLayout.show(); } else { this._horizontalLayout.originalHeight = this._horizontalLayout.getHeight(); this._horizontalLayout.setHeight(0); this._horizontalLayout.hide(); } if (this._initialLayoutDone) { this._updateIndent(); } return true; } qx.Proto._modifyRootOpenClose = function(propValue, propOldValue, propData) { if (this._initialLayoutDone) { this._updateIndent(); } return true; } // Override getter so we can return a clone of the array. Otherwise, the // setter finds the identical array (after user modifications) and the modify // function doesn't get called. qx.Proto.getExcludeSpecificTreeLines = function() { var vName = "excludeSpecificTreeLines"; var vUpName = qx.lang.String.toFirstUp(vName); var vStorageField = "_value" + vUpName; return this[vStorageField].slice(0); } qx.Proto._modifyExcludeSpecificTreeLines = function(propValue, propOldValue, propData) { if (this._initialLayoutDone) { this._updateIndent(); } return true; } /* --------------------------------------------------------------------------- UTILITIES --------------------------------------------------------------------------- */ qx.Proto.getTree = function() { return this; } qx.Proto.getParentFolder = function() { return null; } qx.Proto.getLevel = function() { return 0; } /* --------------------------------------------------------------------------- COMMON CHECKERS --------------------------------------------------------------------------- */ qx.ui.treefullcontrol.Tree.isTreeFolder = function(vObject) { return (vObject && vObject instanceof qx.ui.treefullcontrol.TreeFolder && !(vObject instanceof qx.ui.treefullcontrol.Tree)); } qx.ui.treefullcontrol.Tree.isOpenTreeFolder = function(vObject) { return (vObject instanceof qx.ui.treefullcontrol.TreeFolder && vObject.getOpen() && vObject.hasContent()); } /* --------------------------------------------------------------------------- EVENT HANDLER --------------------------------------------------------------------------- */ qx.Proto._onkeydown = function(e) { var vManager = this.getManager(); var vSelectedItem = vManager.getSelectedItem(); if (e.getKeyIdentifier() == "Enter") { e.preventDefault(); if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) { return vSelectedItem.toggle(); } } } qx.Proto._onkeypress = function(e) { var vManager = this.getManager(); var vSelectedItem = vManager.getSelectedItem(); switch(e.getKeyIdentifier()) { case "Left": e.preventDefault(); if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) { if (!vSelectedItem.getOpen()) { var vParent = vSelectedItem.getParentFolder(); if (vParent instanceof qx.ui.treefullcontrol.TreeFolder) { if (!(vParent instanceof qx.ui.treefullcontrol.Tree)) { vParent.close(); } this.setSelectedElement(vParent); } } else { return vSelectedItem.close(); } } else if (vSelectedItem instanceof qx.ui.treefullcontrol.TreeFile) { var vParent = vSelectedItem.getParentFolder(); if (vParent instanceof qx.ui.treefullcontrol.TreeFolder) { if (!(vParent instanceof qx.ui.treefullcontrol.Tree)) { vParent.close(); } this.setSelectedElement(vParent); } } break; case "Right": e.preventDefault(); if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) { if (!vSelectedItem.getOpen()) { return vSelectedItem.open(); } else if (vSelectedItem.hasContent()) { var vFirst = vSelectedItem.getFirstVisibleChildOfFolder(); this.setSelectedElement(vFirst); if (vFirst instanceof qx.ui.tree.TreeFolder) { vFirst.open(); } return; } } break; default: if (!this._fastUpdate) { this._fastUpdate = true; this._oldItem = vSelectedItem; } vManager.handleKeyPress(e); } }; qx.Proto._onkeyup = function(e) { if (this._fastUpdate) { var vNewItem = this.getManager().getSelectedItem(); if (! vNewItem) { return; } vNewItem.getIconObject().addState("selected"); delete this._fastUpdate; delete this._oldItem; } } qx.Proto.getLastTreeChild = function() { var vLast = this; while (vLast instanceof qx.ui.treefullcontrol.AbstractTreeElement) { if (!(vLast instanceof qx.ui.treefullcontrol.TreeFolder) || !vLast.getOpen()) { return vLast; } vLast = vLast.getLastVisibleChildOfFolder(); } return null; } qx.Proto.getFirstTreeChild = function() { return this; } qx.Proto.setSelectedElement = function(vElement) { var vManager = this.getManager(); vManager.setSelectedItem(vElement); vManager.setLeadItem(vElement); } /* Override getHierarchy: do not add label if root node is hidden */ qx.Proto.getHierarchy = function(vArr) { if (! this.hideNode() && this._labelObject) { vArr.unshift(this._labelObject.getHtml()); } return vArr; } qx.Proto.getIndentSymbol = function(vUseTreeLines, vColumn, vLastColumn) { if (vColumn == vLastColumn && (this.hasContent() || this.getAlwaysShowPlusMinusSymbol())) { if (! vUseTreeLines) { return this.getOpen() ? "minus" : "plus"; } else { return this.getOpen() ? "only_minus" : "only_plus"; } } else { return null; } } /* --------------------------------------------------------------------------- DISPOSER --------------------------------------------------------------------------- */ qx.Proto.dispose = function() { if (this.getDisposed()) { return; } this.removeEventListener("keydown", this._onkeydown); this.removeEventListener("keypress", this._onkeypress); this.removeEventListener("keyup", this._onkeyup); if (this._manager) { this._manager.dispose(); this._manager = null; } delete this._oldItem; return qx.ui.treefullcontrol.TreeFolder.prototype.dispose.call(this); }