UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

513 lines (414 loc) 11.7 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Fabian Jakobs (fjakobs) * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) * Derrell Lipman (derrell) * Christian Hagendorn (chris_schmidt) ************************************************************************ */ /** * The AbstractItem serves as a common superclass for the {@link * qx.ui.tree.core.AbstractTreeItem} and {@link qx.ui.tree.VirtualTreeItem} classes. * * @childControl label {qx.ui.basic.Label} label of the tree item * @childControl icon {qx.ui.basic.Image} icon of the tree item * @childControl open {qx.ui.tree.core.FolderOpenButton} button to open/close a subtree */ qx.Class.define("qx.ui.tree.core.AbstractItem", { extend : qx.ui.core.Widget, type : "abstract", include : [qx.ui.form.MModelProperty], implement : [qx.ui.form.IModel], /** * @param label {String?null} The tree item's caption text */ construct : function(label) { this.base(arguments); if (label != null) { this.setLabel(label); } this._setLayout(new qx.ui.layout.HBox()); this._addWidgets(); this.initOpen(); }, properties : { /** * Whether the tree item is opened. */ open : { check : "Boolean", init : false, event : "changeOpen", apply : "_applyOpen" }, /** * Controls, when to show the open symbol. If the mode is "auto" , the open * symbol is shown only if the item has child items. */ openSymbolMode : { check : ["always", "never", "auto"], init : "auto", event : "changeOpenSymbolMode", apply : "_applyOpenSymbolMode" }, /** * The number of pixel to indent the tree item for each level. */ indent : { check : "Integer", init : 19, apply : "_applyIndent", event : "changeIndent", themeable : true }, /** * URI of "closed" icon. Can be any URI String supported by qx.ui.basic.Image. **/ icon : { check : "String", apply : "_applyIcon", event : "changeIcon", nullable : true, themeable : true }, /** * URI of "opened" icon. Can be any URI String supported by qx.ui.basic.Image. **/ iconOpened : { check : "String", apply : "_applyIconOpened", event : "changeIconOpened", nullable : true, themeable : true }, /** * The label/caption/text */ label : { check : "String", apply : "_applyLabel", event : "changeLabel", init : "" } }, members : { __labelAdded : null, __iconAdded : null, __spacer : null, /** * This method configures the tree item by adding its sub widgets like * label, icon, open symbol, ... * * This method must be overridden by sub classes. */ _addWidgets : function() { throw new Error("Abstract method call."); }, // overridden _createChildControlImpl : function(id, hash) { var control; switch(id) { case "label": control = new qx.ui.basic.Label().set({ alignY: "middle", anonymous: true, value: this.getLabel() }); break; case "icon": control = new qx.ui.basic.Image().set({ alignY: "middle", anonymous: true, source: this.getIcon() }); break; case "open": control = new qx.ui.tree.core.FolderOpenButton().set({ alignY: "middle" }); control.addListener("changeOpen", this._onChangeOpen, this); control.addListener("resize", this._updateIndent, this); break; } return control || this.base(arguments, id); }, /* --------------------------------------------------------------------------- TREE ITEM CONFIGURATION --------------------------------------------------------------------------- */ /** * Adds a sub widget to the tree item's horizontal box layout. * * @param widget {qx.ui.core.Widget} The widget to add * @param options {Map?null} The (optional) layout options to use for the widget */ addWidget : function(widget, options) { this._add(widget, options); }, /** * Adds the spacer used to render the indentation to the item's horizontal * box layout. If the spacer has been added before, it is removed from its * old position and added to the end of the layout. */ addSpacer : function() { if (!this.__spacer) { this.__spacer = new qx.ui.core.Spacer(); } else { this._remove(this.__spacer); } this._add(this.__spacer); }, /** * Adds the open button to the item's horizontal box layout. If the open * button has been added before, it is removed from its old position and * added to the end of the layout. */ addOpenButton : function() { this._add(this.getChildControl("open")); }, /** * Event handler, which listens to open state changes of the open button * * @param e {qx.event.type.Data} The event object */ _onChangeOpen : function(e) { if (this.isOpenable()) { this.setOpen(e.getData()); } }, /** * Adds the icon widget to the item's horizontal box layout. If the icon * widget has been added before, it is removed from its old position and * added to the end of the layout. */ addIcon : function() { var icon = this.getChildControl("icon"); if (this.__iconAdded) { this._remove(icon); } this._add(icon); this.__iconAdded = true; }, /** * Adds the label to the item's horizontal box layout. If the label * has been added before, it is removed from its old position and * added to the end of the layout. * * @param text {String?0} The label's contents */ addLabel : function(text) { var label = this.getChildControl("label"); if (this.__labelAdded) { this._remove(label); } if (text) { this.setLabel(text); } else { label.setValue(this.getLabel()); } this._add(label); this.__labelAdded = true; }, /* --------------------------------------------------------------------------- PROPERTY APPLY --------------------------------------------------------------------------- */ // property apply _applyIcon : function(value, old) { // Set "closed" icon - even when "opened" - if no "opened" icon was // user-defined if (!this.__getUserValueIconOpened()) { this.__setIconSource(value); } else if (!this.isOpen()) { this.__setIconSource(value); } }, // property apply _applyIconOpened : function(value, old) { if (this.isOpen()) { // ... both "closed" and "opened" icon were user-defined if (this.__getUserValueIcon() && this.__getUserValueIconOpened()) { this.__setIconSource(value); } // .. only "opened" icon was user-defined else if (!this.__getUserValueIcon() && this.__getUserValueIconOpened()) { this.__setIconSource(value); } } }, // property apply _applyLabel : function(value, old) { var label = this.getChildControl("label", true); if (label) { label.setValue(value); } }, // property apply _applyOpen : function(value, old) { var open = this.getChildControl("open", true); if (open) { open.setOpen(value); } // // Determine source of icon for "opened" or "closed" state // var source; // Opened if (value) { // Never overwrite user-defined icon with themed "opened" icon source = this.__getUserValueIconOpened() ? this.getIconOpened() : null; } // Closed else { source = this.getIcon(); } if (source) { this.__setIconSource(source); } value ? this.addState("opened") : this.removeState("opened"); }, /** * Get user-defined value of "icon" property * * @return {var} The user value of the property "icon" */ __getUserValueIcon : function() { return qx.util.PropertyUtil.getUserValue(this, "icon"); }, /** * Get user-defined value of "iconOpened" property * * @return {var} The user value of the property "iconOpened" */ __getUserValueIconOpened : function() { return qx.util.PropertyUtil.getUserValue(this, "iconOpened"); }, /** * Set source of icon child control * * @param url {String} The URL of the icon */ __setIconSource : function(url) { var icon = this.getChildControl("icon", true); if (icon) { icon.setSource(url); } }, /* --------------------------------------------------------------------------- INDENT HANDLING --------------------------------------------------------------------------- */ /** * Whether the tree item can be opened. * * @return {Boolean} Whether the tree item can be opened. */ isOpenable : function() { var openMode = this.getOpenSymbolMode(); return ( openMode === "always" || openMode === "auto" && this.hasChildren() ); }, /** * Whether the open symbol should be shown * * @return {Boolean} Whether the open symbol should be shown. */ _shouldShowOpenSymbol : function() { throw new Error("Abstract method call."); }, // property apply _applyOpenSymbolMode : function(value, old) { this._updateIndent(); }, /** * Update the indentation of the tree item. */ _updateIndent : function() { var openWidth = 0; var open = this.getChildControl("open", true); if (open) { if (this._shouldShowOpenSymbol()) { open.show(); var openBounds = open.getBounds(); if (openBounds) { openWidth = openBounds.width; } else { return; } } else { open.exclude(); } } if (this.__spacer) { this.__spacer.setWidth((this.getLevel() + 1) * this.getIndent() - openWidth); } }, // property apply _applyIndent : function(value, old) { this._updateIndent(); }, /** * Computes the item's nesting level. If the item is not part of a tree * this function will return <code>null</code>. * * @return {Integer|null} The item's nesting level or <code>null</code>. */ getLevel : function() { throw new Error("Abstract method call."); }, // overridden syncWidget : function(jobs) { this._updateIndent(); }, /** * Whether the item has any children * * @return {Boolean} Whether the item has any children. */ hasChildren : function() { throw new Error("Abstract method call."); } }, destruct : function() { this._disposeObjects("__spacer"); } });