![JAR search and dependency download from the Maven repository](/logo.png)
rwt.widgets.base.Parent.js Maven / Gradle / Ivy
/******************************************************************************* * Copyright (c) 2004, 2022 1&1 Internet AG, Germany, http://www.1und1.de, * EclipseSource and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * 1&1 Internet AG and others - original API and implementation * EclipseSource - adaptation for the Eclipse Remote Application Platform ******************************************************************************/ /** * Abstract base class for all widget which have child widgets (e.g. layout manager) * * Don't instantiate this class directly. */ rwt.qx.Class.define("rwt.widgets.base.Parent", { extend : rwt.widgets.base.Widget, /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ construct : function() { this.base(arguments); // Contains all children this._children = []; // Create instanceof layout implementation this._layoutImpl = this._createLayoutImpl(); }, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { /** Individual focus handler for all child elements. */ focusHandler : { check : "rwt.widgets.util.FocusHandler", apply : "_applyFocusHandler", nullable : true }, /** The current active child. */ activeChild : { check : "rwt.widgets.base.Widget", event : "changeActiveChild", nullable : true }, /** The current focused child. */ focusedChild : { check : "rwt.widgets.base.Widget", apply : "_applyFocusedChild", event : "changeFocusedChild", nullable : true }, /** all visible child widgets */ visibleChildren : { _cached : true, defaultValue : null } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /* --------------------------------------------------------------------------- FOCUS HANDLING --------------------------------------------------------------------------- */ /** * Wether the widget has its own focus handler or uses one of its parent's * focus handler. * * @type member * @return {Boolean} whether the widget has its own focus handler */ isFocusRoot : function() { return this.getFocusHandler() != null; }, /** * Return the responsible focus handler * * @type member * @return {rwt.widgets.util.FocusHandler} TODOC */ getFocusRoot : function() { if (this.isFocusRoot()) { return this; } if (this._hasParent) { return this.getParent().getFocusRoot(); } return null; }, /** * Let the widget use its own focus handler * * @type member * @return {void} */ activateFocusRoot : function() { if (this._focusHandler) { return; } this._focusHandler = new rwt.widgets.util.FocusHandler(this); this.setFocusHandler(this._focusHandler); }, /** * Delegate keyevent to the focus handler * * @type member * @param e {Event} TODOC * @return {void} */ _onfocuskeyevent : function(e) { this.getFocusHandler()._onkeyevent(this, e); }, /** * TODOC * * @type member * @param value {var} Current value * @param old {var} Previous value */ _applyFocusHandler : function(value) { if (value) { // Add Key Handler this.addEventListener("keypress", this._onfocuskeyevent); // Activate focus handling (but keep already configured tabIndex) if (this.getTabIndex() < 1) { this.setTabIndex(1); } // But hide the focus outline this.setHideFocus(true); // Make myself the default this.setActiveChild(this); } else { // Remove Key Handler this.removeEventListener("keydown", this._onfocuskeyevent); this.removeEventListener("keypress", this._onfocuskeyevent); // Deactivate focus handling this.setTabIndex(null); // Don't hide focus outline this.setHideFocus(false); } }, /** * TODOC * * @type member * @param value {var} Current value * @param old {var} Previous value */ _applyFocusedChild : function(value, old) { var vFocusValid = value != null; var vBlurValid = old != null; if (rwt.qx.Class.isDefined("rwt.widgets.util.PopupManager") && vFocusValid) { var vMgr = rwt.widgets.util.PopupManager.getInstance(); if (vMgr) { vMgr.update(value); } } if (vBlurValid) { // Dispatch FocusOut if (old.hasEventListeners("focusout")) { var vEventObject = new rwt.event.FocusEvent("focusout", old); if (vFocusValid) { vEventObject.setRelatedTarget(value); } old.dispatchEvent(vEventObject); vEventObject.dispose(); } } if (vFocusValid) { if (value.hasEventListeners("focusin")) { // Dispatch FocusIn var vEventObject = new rwt.event.FocusEvent("focusin", value); if (vBlurValid) { vEventObject.setRelatedTarget(old); } value.dispatchEvent(vEventObject); vEventObject.dispose(); } } if (vBlurValid) { if (this.getActiveChild() == old && !vFocusValid) { this.setActiveChild(null); } old.setFocused(false); // Dispatch Blur var vEventObject = new rwt.event.FocusEvent("blur", old); if (vFocusValid) { vEventObject.setRelatedTarget(value); } old.dispatchEvent(vEventObject); var vMgr = rwt.widgets.util.ToolTipManager.getInstance(); if (vMgr) { vMgr.handleBlur(vEventObject); } vEventObject.dispose(); } if (vFocusValid) { this.setActiveChild(value); value.setFocused(true); rwt.event.EventHandler.setFocusRoot(this); // Dispatch Focus var vEventObject = new rwt.event.FocusEvent("focus", value); if (vBlurValid) { vEventObject.setRelatedTarget(old); } value.dispatchEvent(vEventObject); var vMgr = rwt.widgets.util.ToolTipManager.getInstance(); if (vMgr) { vMgr.handleFocus(vEventObject); } vEventObject.dispose(); } }, _applyWidth : function( newValue, oldValue ) { this.base( arguments, newValue, oldValue ); this._layoutX(); }, _applyHeight : function( newValue, oldValue ) { this.base( arguments, newValue, oldValue ); this._layoutY(); }, _applyBorder : function( newValue, oldValue ) { this.base( arguments, newValue, oldValue ); this._layoutX(); this._layoutY(); }, _applyDirection : function( value ) { this.base( arguments, value ); this._layoutX(); }, _layoutX : function() {}, _layoutY : function() {}, /* --------------------------------------------------------------------------- LAYOUT IMPLEMENTATION --------------------------------------------------------------------------- */ _layoutImpl : null, /** * abstract method. Create layout implementation. * * This method must be overwritten by all subclasses * * return * * @type member * @return {rwt.widgets.base.BoxLayout} TODOC */ _createLayoutImpl : function() { return new rwt.widgets.util.CanvasLayoutImpl( this); }, /** * Return the layout implementation. * * return {rwt.widgets.util.LayoutImpl} * * @type member * @return {var} TODOC */ getLayoutImpl : function() { return this._layoutImpl; }, /* --------------------------------------------------------------------------- CHILDREN MANAGMENT: MANAGE ALL --------------------------------------------------------------------------- */ /** * Return the array of all children * * @type member * @return {rwt.widgets.base.Widget[]} all children */ getChildren : function() { return this._children; }, /** * Get number of children * * @type member * @return {Integer} number of children */ getChildrenLength : function() { return this.getChildren().length; }, /** * Check if the widget has children * * @type member * @return {Boolean} whether the widget has children */ hasChildren : function() { return this.getChildrenLength() > 0; }, /** * Check if there are any children inside * * @type member * @return {Boolean} whether the number of children is 0 */ isEmpty : function() { return this.getChildrenLength() === 0; }, /** * Get the index of a child widget. * * @type member * @param vChild {rwt.widgets.base.Widget} Child widget to get the index for * @return {Integer} index of the child widget */ indexOf : function(vChild) { return this.getChildren().indexOf(vChild); }, /** * Check if the given widget is a child * * @type member * @param vWidget {rwt.widgets.base.Widget} The widget which should be checked. * @return {Boolean | var} TODOC */ contains : function(vWidget) { switch(vWidget) { case null: return false; case this: return true; default: // try the next parent of the widget (recursive until found) return this.contains(vWidget.getParent()); } }, /* --------------------------------------------------------------------------- CHILDREN MANAGMENT: MANAGE VISIBLE ONES uses a cached private property --------------------------------------------------------------------------- */ /** * Return the array of all visible children * (which are configured as visible=true) * * @type member * @return {rwt.widgets.base.Widget[]} all visible children */ _computeVisibleChildren : function() { var vVisible = []; var vChildren = this.getChildren(); if (! vChildren) { return 0; } var vLength = vChildren.length; for (var i=0; i
. The first parameter is the child widget * and the second the index of the child widget in its parent. * * @type member * @param vFunc {Function} callback function. Signature:0; }, /** * Check whether there are any visible children inside * * @type member * @return {Boolean} whether there are any visible children inside */ isVisibleEmpty : function() { return this.getVisibleChildrenLength() === 0; }, /* --------------------------------------------------------------------------- CHILDREN MANAGMENT: ADD --------------------------------------------------------------------------- */ /** * Add/Append another widget. Allows to add multiple at * one, a parameter could be a widget. * * @type member * @param varargs {rwt.widgets.base.Widget} variable number of widgets to add * @return {Parent} This widget. * @throws TODOC */ add : function() { var vWidget; for (var i=0, l=arguments.length; i vTargetIndex) { vTargetIndex++; } return this.addAt(vChild, Math.max(0, vTargetIndex - 1)); }, /** * Add a widget after another already inserted widget * * @type member * @param vChild {var} widget to add * @param vAfter {var} widgert, after which the new widget will be inserted */ addAfter : function(vChild, vAfter) { var vChildren = this.getChildren(); var vTargetIndex = vChildren.indexOf(vAfter); if (vTargetIndex == -1) { throw new Error("Child to add after: " + vAfter + " is not inside this parent."); } var vSourceIndex = vChildren.indexOf(vChild); if (vSourceIndex != -1 && vSourceIndex < vTargetIndex) { vTargetIndex--; } return this.addAt(vChild, Math.min(vChildren.length, vTargetIndex + 1)); }, /* --------------------------------------------------------------------------- CHILDREN MANAGMENT: REMOVE --------------------------------------------------------------------------- */ /** * Remove one or multiple childrens. * * @type member * @param varargs {rwt.widgets.base.Widget} variable number of widgets to remove */ remove : function( /*children*/ ) { var vWidget; for (var i=0, l=arguments.length; i function(childWidget, widgetIndex) function(childWidget, widgetIndex)
*/ forEachChild : function(vFunc) { var ch = this.getChildren(), chc, i = -1; if (! ch) { return; } chc = ch[++i]; while( chc ) { vFunc.call(chc, i); chc = ch[++i]; } }, /** * Call a callbach function for each visible child widget. The callback has the following signature: *function(childWidget, widgetIndex)
. The first parameter is the child widget * and the second the index of the child widget in its parent. * * @type member * @param vFunc {Function} callback function. Signature:function(childWidget, widgetIndex)
*/ forEachVisibleChild : function(vFunc) { var ch = this.getVisibleChildren(), chc, i = -1; if (! ch) { return; } chc = ch[++i]; while( chc ) { vFunc.call(chc, i); chc = ch[++i]; } }, _markInDispose : function() { this._isInGlobalDisposeQueue = true; if( this.forEachChild ) { this.forEachChild( arguments.callee ); } }, // overridden _fireBeforeDispose : function() { this.base( arguments ); if( this.forEachChild ) { this.forEachChild( arguments.callee ); } }, /* --------------------------------------------------------------------------- APPEAR/DISAPPEAR MESSAGES FOR CHILDREN --------------------------------------------------------------------------- */ // overridden _beforeAppear : function() { this.base(arguments); this.forEachVisibleChild(function() { if (this.isAppearRelevant()) { this._beforeAppear(); } }); }, // overridden _afterAppear : function() { this.base(arguments); this.forEachVisibleChild(function() { if (this.isAppearRelevant()) { this._afterAppear(); } }); }, // overridden _beforeDisappear : function() { this.base(arguments); this.forEachVisibleChild(function() { if (this.isAppearRelevant()) { this._beforeDisappear(); } }); }, // overridden _afterDisappear : function() { this.base(arguments); this.forEachVisibleChild(function() { if (this.isAppearRelevant()) { this._afterDisappear(); } }); }, // overridden _afterInsertDom : function() { this.base( arguments ); // NOTE: a "visible" Child is actually every "displayable" child here this.forEachVisibleChild( function() { // Check if the nodes are actually connected - See Bug 359665 if( this.getElement() && this.getElement().parentNode === this.getParent()._getTargetNode() ) { this._afterInsertDom(); } } ); }, // overridden _afterRemoveDom : function() { this.base( arguments ); this.forEachVisibleChild( function() { if( this.isInDom() ) { this._afterRemoveDom(); } } ); }, /* --------------------------------------------------------------------------- DISPLAYBLE HANDLING --------------------------------------------------------------------------- */ /** * TODOC * * @type member * @param vDisplayable {var} TODOC * @param vParent {var} TODOC * @param vHint {var} TODOC * @return {void} */ _handleDisplayableCustom : function() { this.forEachChild(function() { this._handleDisplayable(); }); }, /* --------------------------------------------------------------------------- STATE QUEUE --------------------------------------------------------------------------- */ /** * TODOC * * @type member * @return {void} */ _addChildrenToStateQueue : function() { this.forEachVisibleChild(function() { this.addToStateQueue(); }); }, // overridden recursiveAddToStateQueue : function() { this.addToStateQueue(); this.forEachVisibleChild(function() { this.recursiveAddToStateQueue(); }); }, // overridden _recursiveAppearanceThemeUpdate : function(vNewAppearanceTheme, vOldAppearanceTheme) { this.base(arguments, vNewAppearanceTheme, vOldAppearanceTheme); this.forEachVisibleChild(function() { this._recursiveAppearanceThemeUpdate(vNewAppearanceTheme, vOldAppearanceTheme); }); }, /* --------------------------------------------------------------------------- CHILDREN QUEUE --------------------------------------------------------------------------- */ /** * TODOC * * @type member * @param vChild {var} TODOC * @return {void} */ _addChildToChildrenQueue : function(vChild) { if (!vChild._isInParentChildrenQueue && vChild._isDisplayable) { rwt.widgets.base.Widget.addToGlobalLayoutQueue(this); if (!this._childrenQueue) { this._childrenQueue = {}; } this._childrenQueue[vChild.toHashCode()] = vChild; } }, /** * TODOC * * @type member * @param vChild {var} TODOC * @return {void} */ _removeChildFromChildrenQueue : function(vChild) { if (this._childrenQueue && vChild._isInParentChildrenQueue) { delete this._childrenQueue[vChild.toHashCode()]; if (rwt.util.Objects.isEmpty(this._childrenQueue)) { this._childrenQueue = {}; rwt.widgets.base.Widget.removeFromGlobalLayoutQueue(this); } } }, /** * TODOC * * @type member * @return {void} */ _flushChildrenQueue : function() { if (!rwt.util.Objects.isEmpty(this._childrenQueue)) { this.getLayoutImpl().flushChildrenQueue(this._childrenQueue); delete this._childrenQueue; } }, /* --------------------------------------------------------------------------- LAYOUT QUEUE --------------------------------------------------------------------------- */ /** * TODOC * * @type member * @param p {var} TODOC * @return {void} */ _addChildrenToLayoutQueue : function(p) { this.forEachChild(function() { this.addToLayoutChanges(p); }); }, /** * TODOC * * @type member * @param vChild {var} TODOC * @return {void} */ _layoutChild : function(vChild) { if (!vChild._isDisplayable) { // this.warn("Want to render an invisible child: " + vChild + " -> omitting!"); return; } // APPLY LAYOUT var vChanges = vChild._layoutChanges; if (vChild.renderBorder && vChanges.border ) { vChild.renderBorder( vChanges ); } if (vChild.renderPadding) { if (vChanges.paddingLeft || vChanges.paddingRight || vChanges.paddingTop || vChanges.paddingBottom) { vChild.renderPadding(vChanges); } } // WRAP TO LAYOUT ENGINE this.getLayoutImpl().layoutChild(vChild, vChanges); // POST LAYOUT vChild._layoutPost(vChanges); // DISPLAY DOM NODE // insert dom node (if initial flag enabled) if (vChanges.initial) { vChild._initialLayoutDone = true; rwt.widgets.base.Widget.addToGlobalDisplayQueue(vChild); } // CLEANUP vChild._layoutChanges = {}; delete vChild._isInParentLayoutQueue; delete this._childrenQueue[vChild.toHashCode()]; }, _layoutPost : function( changes ) { this.createDispatchDataEvent( "flush", changes ); }, /* --------------------------------------------------------------------------- DIMENSION CACHE --------------------------------------------------------------------------- */ /** * TODOC * * @type member * @return {var} TODOC */ _computePreferredInnerWidth : function() { return this.getLayoutImpl().computeChildrenNeededWidth(); }, /** * TODOC * * @type member * @return {var} TODOC */ _computePreferredInnerHeight : function() { return this.getLayoutImpl().computeChildrenNeededHeight(); }, /** * TODOC * * @type member * @param vNew {var} TODOC * @param vOld {var} TODOC * @return {void} */ _changeInnerWidth : function() { var vLayout = this.getLayoutImpl(); if (vLayout.invalidateChildrenFlexWidth) { vLayout.invalidateChildrenFlexWidth(); } this.forEachVisibleChild(function() { if (vLayout.updateChildOnInnerWidthChange(this) && this._recomputeBoxWidth()) { this._recomputeOuterWidth(); this._recomputeInnerWidth(); } }); }, /** * TODOC * * @type member * @param vNew {var} TODOC * @param vOld {var} TODOC * @return {void} */ _changeInnerHeight : function() { var vLayout = this.getLayoutImpl(); if (vLayout.invalidateChildrenFlexHeight) { vLayout.invalidateChildrenFlexHeight(); } this.forEachVisibleChild(function() { if (vLayout.updateChildOnInnerHeightChange(this) && this._recomputeBoxHeight()) { this._recomputeOuterHeight(); this._recomputeInnerHeight(); } }); }, /** * TODOC * * @type member * @param vChild {var} TODOC * @return {var} TODOC */ getInnerWidthForChild : function() { return this.getInnerWidth(); }, /** * TODOC * * @type member * @param vChild {var} TODOC * @return {var} TODOC */ getInnerHeightForChild : function() { return this.getInnerHeight(); }, /* --------------------------------------------------------------------------- REMAPPING --------------------------------------------------------------------------- */ _remappingChildTable : [ "add", "remove", "addAt", "addAtBegin", "addAtEnd", "removeAt", "addBefore", "addAfter", "removeAll" ], remapChildrenHandlingTo : function( vTarget ) { this._remappingChildTarget = vTarget; this._remappingChildTable.forEach( function( remappingChild ) { this[ remappingChild ] = function() { return this._remappingChildTarget[ remappingChild ].apply( this._remappingChildTarget, arguments ); }; }, this ); } }, /* ***************************************************************************** DESTRUCTOR ***************************************************************************** */ destruct : function() { this._disposeObjectDeep("_children", 1); this._disposeObjects("_layoutImpl", "_focusHandler"); this._disposeFields("_childrenQueue", "_childrenQueue", "_remappingChildTable", "_remappingChildTarget", "_cachedVisibleChildren"); } });
© 2015 - 2025 Weber Informatics LLC | Privacy Policy