diff options
author | Derrell Lipman <derrell@samba.org> | 2007-02-06 03:23:52 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:44:34 -0500 |
commit | ef256c958066c19bb10cbe9745bdf96b6514762d (patch) | |
tree | dbe379cb3021c5af2d1b8f74528e4fff968fc712 /webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class | |
parent | a8d0f5df6266aeacdb20326094c0401618ab62e8 (diff) | |
download | samba-ef256c958066c19bb10cbe9745bdf96b6514762d.tar.gz samba-ef256c958066c19bb10cbe9745bdf96b6514762d.tar.bz2 samba-ef256c958066c19bb10cbe9745bdf96b6514762d.zip |
r21167: - Upgrade to latest released qooxdoo. This is step 1 of the upgrade process,
which involves adding the latest SDK. This new version has not 2, but 4
icon themes. In order to quiet Andrew B. who thinks that 9000+ files in a
gui api is too many (come on, disk space is free these days :-), I have
removed 3 of the 4 icon themes, leaving only the default, Nuvola. That
lowers the file count by 1/3. I'm sure Andrew still isn't happy, but I hope
he's a bit happier... Step 2 will make him happier yet.
(This used to be commit d161c1382c36238105b85d0499d5a1011f580f52)
Diffstat (limited to 'webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class')
301 files changed, 84693 insertions, 0 deletions
diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Locale.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Locale.js new file mode 100644 index 0000000000..02921da4d8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Locale.js @@ -0,0 +1,99 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +qx.OO.defineClass("qx.Locale", +{ + /** {var} TODOC */ + _registry : {}, + + /** + * Locale definition + * + * Example: + * <pre><code> + * qx.Locale.define("fullname", + * { + * "msgId": "msgText", + * ... + * }); + * </code></pre> + * + * @type static + * @name define + * @access public + * @param fullname {String} name of the mixin + * @param definition {Map} definition structure + * @return {void} + */ + define : function(fullname, definition) + { + var vSplitName = fullname.split("."); + var vLength = vSplitName.length; + var vParentPackage = window; + var vPartName = vSplitName[0]; + + for (var i=0, l=vSplitName.length - 1; i<l; i++) + { + if (!vParentPackage[vPartName]) { + vParentPackage[vPartName] = {}; + } + + vParentPackage = vParentPackage[vPartName]; + vPartName = vSplitName[i + 1]; + } + + vParentPackage[vPartName] = definition; + qx.locale.Manager.getInstance().addTranslation(vPartName, definition); + + qx.Locale._registry[fullname] = definition; + }, + + /** + * Returns a locale by name + * + * @type static + * @name byName + * @access public + * @param fullname {String} locale name to check + * @return {Object ? void} locale object + */ + byName : function(fullname) { + return qx.Locale._registry[fullname]; + }, + + /** + * Determine if locale exists + * + * @type static + * @name isDefined + * @access public + * @param fullname {String} locale name to check + * @return {Boolean} true if locale exists + */ + isDefined : function(fullname) { + return qx.Locale.byName(fullname) !== undefined; + } +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/OO.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/OO.js new file mode 100644 index 0000000000..47eb74783e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/OO.js @@ -0,0 +1,746 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#id(qx.OO) +#module(core) +#after(qx.Settings) +#load(qx.lang.Core) +#load(qx.lang.Function) +#optional(qx.event.type.DataEvent) + +************************************************************************ */ + +// Usage of this hacky construct to make qx.OO available inside the API viewer +qx.OO = {}; +qx.OO.defineClass = function() {}; +qx.Class = qx.OO; +qx.OO.defineClass("qx.OO"); + +qx.Class.classes = {}; +qx.Class.setter = {}; +qx.Class.getter = {}; +qx.Class.resetter = {}; +qx.Class.values = {}; +qx.Class.propertyNumber = 0; + + + + +/* +--------------------------------------------------------------------------- + DEFINE CLASS IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +/** + * define a new qooxdoo class + * All classes should be defined in this way. + * + * @param vClassName {String} fully qualified class name (e.g. "qx.ui.form.Button") + * @param vSuper {Object} super class + * @param vConstructor {Function} the constructor of the new class + */ +qx.Class.defineClass = function(vClassName, vSuper, vConstructor) +{ + var vSplitName = vClassName.split("."); + var vNameLength = vSplitName.length-1; + var vTempObject = window; + + // Setting up namespace + for (var i=0; i<vNameLength; i++) + { + if (typeof vTempObject[vSplitName[i]] === "undefined") { + vTempObject[vSplitName[i]] = {}; + } + + vTempObject = vTempObject[vSplitName[i]]; + } + + // Instantiate objects/inheritance + if (typeof vSuper === "undefined") + { + if (typeof vConstructor !== "undefined") { + throw new Error("SuperClass is undefined, but constructor was given for class: " + vClassName); + } + + qx.Class = vTempObject[vSplitName[i]] = {}; + qx.Proto = null; + qx.Super = null; + } + else if (typeof vConstructor === "undefined") + { + qx.Class = vTempObject[vSplitName[i]] = vSuper; + qx.Proto = null; + qx.Super = vSuper; + } + else + { + qx.Class = vTempObject[vSplitName[i]] = vConstructor; + + // build helper function + // this omits the initial constructor call while inherit properties + var vHelperConstructor = function() {}; + vHelperConstructor.prototype = vSuper.prototype; + qx.Proto = vConstructor.prototype = new vHelperConstructor; + + qx.Super = vConstructor.superclass = vSuper; + + qx.Proto.classname = vConstructor.classname = vClassName; + qx.Proto.constructor = vConstructor; + } + + // Store reference to global classname registry + qx.OO.classes[vClassName] = qx.Class; +} + + + + + + +/* +--------------------------------------------------------------------------- + OBJECT PROPERTY EXTENSION +--------------------------------------------------------------------------- +*/ + +qx.Class.addFastProperty = function(vConfig) +{ + var vName = vConfig.name; + var vUpName = qx.lang.String.toFirstUp(vName); + + var vStorageField = "_value" + vUpName; + var vGetterName = "get" + vUpName; + var vSetterName = "set" + vUpName; + var vComputerName = "_compute" + vUpName; + + qx.Proto[vStorageField] = typeof vConfig.defaultValue !== "undefined" ? vConfig.defaultValue : null; + + if (vConfig.noCompute) + { + qx.Proto[vGetterName] = function() { + return this[vStorageField]; + } + } + else + { + qx.Proto[vGetterName] = function() { + return this[vStorageField] == null ? this[vStorageField] = this[vComputerName]() : this[vStorageField]; + } + } + + if (vConfig.setOnlyOnce) + { + qx.Proto[vSetterName] = function(vValue) + { + this[vStorageField] = vValue; + this[vSetterName] = null; + + return vValue; + } + } + else + { + qx.Proto[vSetterName] = function(vValue) { + return this[vStorageField] = vValue; + } + } + + if (!vConfig.noCompute) + { + qx.Proto[vComputerName] = function() { + return null; + } + } +} + +qx.OO.addCachedProperty = function(p) +{ + var vName = p.name; + var vUpName = qx.lang.String.toFirstUp(vName); + + var vStorageField = "_cached" + vUpName; + var vComputerName = "_compute" + vUpName; + var vChangeName = "_change" + vUpName; + + if (typeof p.defaultValue !== "undefined") { + qx.Proto[vStorageField] = p.defaultValue; + } + + qx.Proto["get" + vUpName] = function() + { + if (this[vStorageField] == null) { + this[vStorageField] = this[vComputerName](); + } + + return this[vStorageField]; + } + + qx.Proto["_invalidate" + vUpName] = function() + { + if (this[vStorageField] != null) + { + this[vStorageField] = null; + + if (p.addToQueueRuntime) { + this.addToQueueRuntime(p.name); + } + } + } + + qx.Proto["_recompute" + vUpName] = function() + { + var vOld = this[vStorageField]; + var vNew = this[vComputerName](); + + if (vNew != vOld) + { + this[vStorageField] = vNew; + this[vChangeName](vNew, vOld); + + return true; + } + + return false; + } + + qx.Proto[vChangeName] = function(vNew, vOld) {}; + qx.Proto[vComputerName] = function() { return null; }; +} + +qx.Class.addPropertyGroup = function(p) +{ + /* -------------------------------------------------------------------------------- + PRE-CHECKS + -------------------------------------------------------------------------------- */ + if(typeof p !== "object") { + throw new Error("Param should be an object!"); + } + + if (typeof p.name != "string") { + throw new Error("Malformed input parameters: name needed!"); + } + + if (typeof p.members != "object") { + throw new Error("Malformed input parameters: members needed!"); + } + + p.method = qx.lang.String.toFirstUp(p.name); + + + /* -------------------------------------------------------------------------------- + CACHING + -------------------------------------------------------------------------------- */ + p.getter = []; + p.setter = []; + + for (var i=0, l=p.members.length; i<l; i++) { + p.setter.push("set" + qx.lang.String.toFirstUp(p.members[i])); + } + + for (var i=0, l=p.members.length; i<l; i++) { + p.getter.push("get" + qx.lang.String.toFirstUp(p.members[i])); + } + + + /* -------------------------------------------------------------------------------- + GETTER + -------------------------------------------------------------------------------- */ + qx.Proto["get" + p.method] = function() + { + var a = []; + var g = p.getter; + + for (var i=0, l=g.length; i<l; i++) { + a.push(this[g[i]]()); + } + + return a; + }; + + + /* -------------------------------------------------------------------------------- + SETTER + -------------------------------------------------------------------------------- */ + switch(p.mode) + { + case "shorthand": + qx.Proto["set" + p.method] = function() + { + if (arguments.length > 4 || arguments.length == 0) { + throw new Error("Invalid number of arguments for property " + p.name + ": " + arguments); + } + + try + { + var ret = qx.lang.Array.fromShortHand(qx.lang.Array.fromArguments(arguments)); + } + catch(ex) + { + throw new Error("Invalid shorthand values for property " + p.name + ": " + arguments + ": " + ex); + } + + var s = p.setter; + var l = s.length; + + for (var i=0; i<l; i++) { + this[s[i]](ret[i]); + } + }; + break; + + default: + qx.Proto["set" + p.method] = function() + { + var s = p.setter; + var l = s.length; + + if (arguments.length != l) { + throw new Error("Invalid number of arguments (needs: " + l + ", is: " + arguments.length + ") for property " + p.name + ": " + qx.lang.Array.fromArguments(arguments).toString()); + } + + for (var i=0; i<l; i++) { + this[s[i]](arguments[i]); + } + }; + } +} + +qx.Class.removeProperty = function(p) +{ + if (typeof qx.Proto._properties !== "string") { + throw new Error("Has no properties!"); + } + + if(typeof p !== "object") { + throw new Error("Param should be an object!"); + } + + if (typeof p.name !== "string") { + throw new Error("Malformed input parameters: name needed!"); + } + + // building shorter prototype access + var pp = qx.Proto; + + p.method = qx.lang.String.toFirstUp(p.name); + p.implMethod = p.impl ? qx.lang.String.toFirstUp(p.impl) : p.method; + + var valueKey = "_value" + p.method; + + // Remove property from list + pp._properties = qx.lang.String.removeListItem(pp._properties, p.name); + + // Reset default value to null + pp[valueKey] = null; + + // Reset methods + pp["get" + p.method] = null; + pp["set" + p.method] = null; + pp["reset" + p.method] = null; + pp["apply" + p.method] = null; + pp["force" + p.method] = null; + pp["getDefault" + p.method] = null; + pp["setDefault" + p.method] = null; +} + +qx.Class._createProperty = function(p) +{ + if(typeof p !== "object") { + throw new Error("AddProperty: Param should be an object!"); + } + + if (typeof p.name !== "string") { + throw new Error("AddProperty: Malformed input parameters: name needed!"); + } + + // building shorter prototype access + var pp = qx.Proto; + + p.method = qx.lang.String.toFirstUp(p.name); + p.implMethod = p.impl ? qx.lang.String.toFirstUp(p.impl) : p.method; + + if (p.defaultValue == undefined) { + p.defaultValue = null; + } + + p.allowNull = p.allowNull !== false; + p.allowMultipleArguments = p.allowMultipleArguments === true; + + + + + + + if (typeof p.type === "string") { + p.hasType = true; + } + else if (typeof p.type !== "undefined") { + throw new Error("AddProperty: Invalid type definition for property " + p.name + ": " + p.type); + } + else { + p.hasType = false; + } + + if (typeof p.instance === "string") { + p.hasInstance = true; + } + else if (typeof p.instance !== "undefined") { + throw new Error("AddProperty: Invalid instance definition for property " + p.name + ": " + p.instance); + } + else { + p.hasInstance = false; + } + + if (typeof p.classname === "string") { + p.hasClassName = true; + } + else if (typeof p.classname !== "undefined") { + throw new Error("AddProperty: Invalid classname definition for property " + p.name + ": " + p.classname); + } + else { + p.hasClassName = false; + } + + + + + + + p.hasConvert = p.convert != null; + p.hasPossibleValues = p.possibleValues != null; + p.hasUnitDetection = p.unitDetection != null; + + p.addToQueue = p.addToQueue || false; + p.addToQueueRuntime = p.addToQueueRuntime || false; + + // upper-case name + p.up = p.name.toUpperCase(); + + // register global uppercase name + qx.OO["PROPERTY_" + p.up] = p.name; + + var valueKey = "_value" + p.method; + var evalKey = "_eval" + p.method; + var changeKey = "change" + p.method; + var modifyKey = "_modify" + p.implMethod; + var checkKey = "_check" + p.implMethod; + + if (!qx.OO.setter[p.name]) + { + qx.OO.setter[p.name] = "set" + p.method; + qx.OO.getter[p.name] = "get" + p.method; + qx.OO.resetter[p.name] = "reset" + p.method; + qx.OO.values[p.name] = valueKey; + } + + // unit detection support + if (p.hasUnitDetection) + { + // computed unit + var cu = "_computed" + p.method; + pp[cu + "Value"] = null; + pp[cu + "Parsed"] = null; + pp[cu + "Type"] = null; + pp[cu + "TypeNull"] = true; + pp[cu + "TypePixel"] = false; + pp[cu + "TypePercent"] = false; + pp[cu + "TypeAuto"] = false; + pp[cu + "TypeFlex"] = false; + + var unitDetectionKey = "_unitDetection" + qx.lang.String.toFirstUp(p.unitDetection); + } + + // apply default value + pp[valueKey] = p.defaultValue; + + // building getFoo(): Returns current stored value + pp["get" + p.method] = function() { + return this[valueKey]; + }; + + // building forceFoo(): Set (override) without do anything else + pp["force" + p.method] = function(newValue) { + return this[valueKey] = newValue; + }; + + // building resetFoo(): Reset value to default value + pp["reset" + p.method] = function() { + return this["set" + p.method](p.defaultValue); + }; + + // building toggleFoo(): Switching between two boolean values + if (p.type === "boolean") + { + pp["toggle" + p.method] = function(newValue) { + return this["set" + p.method](!this[valueKey]); + }; + } + + if (p.allowMultipleArguments || p.hasConvert || p.hasInstance || p.hasClassName || p.hasPossibleValues || p.hasUnitDetection || p.addToQueue || p.addToQueueRuntime || p.addToStateQueue) + { + // building setFoo(): Setup new value, do type and change detection, converting types, call unit detection, ... + pp["set" + p.method] = function(newValue) + { + // convert multiple arguments to array + if (p.allowMultipleArguments && arguments.length > 1) { + newValue = qx.lang.Array.fromArguments(arguments); + } + + // support converter methods + if (p.hasConvert) + { + try + { + newValue = p.convert.call(this, newValue, p); + } + catch(ex) + { + throw new Error("Attention! Could not convert new value for " + p.name + ": " + newValue + ": " + ex); + } + } + + var oldValue = this[valueKey]; + + if (newValue === oldValue) { + return newValue; + } + + if (!(p.allowNull && newValue == null)) + { + if (p.hasType && typeof newValue !== p.type) { + return this.error("Attention! The value \"" + newValue + "\" is an invalid value for the property \"" + p.name + "\" which must be typeof \"" + p.type + "\" but is typeof \"" + typeof newValue + "\"!", new Error()); + } + + if (p.hasInstance && !(newValue instanceof qx.OO.classes[p.instance])) { + return this.error("Attention! The value \"" + newValue + "\" is an invalid value for the property \"" + p.name + "\" which must be an instance of \"" + p.instance + "\"!", new Error()); + } + + if (p.hasClassName && newValue.classname != p.classname) { + return this.error("Attention! The value \"" + newValue + "\" is an invalid value for the property \"" + p.name + "\" which must be an object with the classname \"" + p.classname + "\"!", new Error()); + } + + if (p.hasPossibleValues && newValue != null && !qx.lang.Array.contains(p.possibleValues, newValue)) { + return this.error("Failed to save value for " + p.name + ". '" + newValue + "' is not a possible value!", new Error()); + } + } + + // Allow to check and transform the new value before storage + if (this[checkKey]) + { + try + { + newValue = this[checkKey](newValue, p); + + // Don't do anything if new value is indentical to old value + if (newValue === oldValue) { + return newValue; + } + } + catch(ex) + { + return this.error("Failed to check property " + p.name, ex); + } + } + + // Store new value + this[valueKey] = newValue; + + // Check if there is a modifier implementation + if (this[modifyKey]) + { + try + { + var r = this[modifyKey](newValue, oldValue, p); + if (!r) { + return this.error("Modification of property \"" + p.name + "\" failed without exception (" + r + ")", new Error()); + } + } + catch(ex) + { + return this.error("Modification of property \"" + p.name + "\" failed with exception", ex); + } + } + + // Unit detection support + if (p.hasUnitDetection) { + this[unitDetectionKey](p, newValue); + } + + // Auto queue addition support + if (p.addToQueue) { + this.addToQueue(p.name); + } + else if (p.addToQueueRuntime) { + this.addToQueueRuntime(p.name); + } + + // Auto state queue addition support + if (p.addToStateQueue) { + this.addToStateQueue(); + } + + // Create Event + if (this.hasEventListeners && this.hasEventListeners(changeKey)) + { + try + { + this.createDispatchDataEvent(changeKey, newValue); + } + catch(ex) + { + throw new Error("Property " + p.name + " modified: Failed to dispatch change event: " + ex); + } + } + + return newValue; + }; + } + else + { + // building setFoo(): Setup new value, do type and change detection, converting types, call unit detection, ... + pp["set" + p.method] = function(newValue) + { + // this.debug("Fast Setter: " + p.name); + + var oldValue = this[valueKey]; + + if (newValue === oldValue) { + return newValue; + } + + if (!(p.allowNull && newValue == null)) + { + if (p.hasType && typeof newValue !== p.type) { + return this.error("Attention! The value \"" + newValue + "\" is an invalid value for the property \"" + p.name + "\" which must be typeof \"" + p.type + "\" but is typeof \"" + typeof newValue + "\"!", new Error()); + } + } + + // Allow to check and transform the new value before storage + if (this[checkKey]) + { + try + { + newValue = this[checkKey](newValue, p); + + // Don't do anything if new value is indentical to old value + if (newValue === oldValue) { + return newValue; + } + } + catch(ex) + { + return this.error("Failed to check property " + p.name, ex); + } + } + + // Store new value + this[valueKey] = newValue; + + // Check if there is a modifier implementation + if (this[modifyKey]) + { + try + { + var r = this[modifyKey](newValue, oldValue, p); + if (!r) { + var valueStr = new String(newValue).substring(0, 50); + return this.error("Setting property \"" + p.name + "\" to \"" + valueStr + "\" failed without exception (" + r + ")", new Error()); + } + } + catch(ex) + { + var valueStr = new String(newValue).substring(0, 50); + return this.error("Setting property \"" + p.name + "\" to \"" + valueStr + "\" failed with exception", ex); + } + } + + // Create Event + if (this.hasEventListeners && this.hasEventListeners(changeKey)) + { + var vEvent = new qx.event.type.DataEvent(changeKey, newValue, oldValue, false); + + vEvent.setTarget(this); + + try + { + this.dispatchEvent(vEvent, true); + } + catch(ex) + { + throw new Error("Property " + p.name + " modified: Failed to dispatch change event: " + ex); + } + } + + return newValue; + }; + } + + // building user configured get alias for property + if (typeof p.getAlias === "string") { + pp[p.getAlias] = pp["get" + p.method]; + } + + // building user configured set alias for property + if (typeof p.setAlias === "string") { + pp[p.setAlias] = pp["set" + p.method]; + } +} + +qx.Class.changeProperty = qx.OO._createProperty; + +qx.Class.addProperty = function(p) +{ + qx.OO.propertyNumber++; + + qx.OO._createProperty(p); + + // add property to (all) property list + if (typeof qx.Proto._properties !== "string") { + qx.Proto._properties = p.name; + } else { + qx.Proto._properties += "," + p.name; + } + + // add property to object property list + switch(p.type) + { + case undefined: + case "object": + case "function": + if (typeof qx.Proto._objectproperties !== "string") { + qx.Proto._objectproperties = p.name; + } else { + qx.Proto._objectproperties += "," + p.name; + } + } +} + +qx.Class.inheritField = function(vField, vData) +{ + qx.lang.Object.carefullyMergeWith(vData, qx.Super.prototype[vField]); + qx.Proto[vField] = vData; +} + +qx.Class.isAvailable = function(vClassName) { + return qx.OO.classes[vClassName] != null; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Settings.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Settings.js new file mode 100644 index 0000000000..ca4c6a56e0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/Settings.js @@ -0,0 +1,169 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#id(qx.Settings) +#module(core) + +************************************************************************ */ + + + +/* +--------------------------------------------------------------------------- + CREATE NAMESPACE HIERARCHY +--------------------------------------------------------------------------- +*/ + +if (!window.qx) { + qx = {}; +} + +if (!qx.Settings) { + qx.Settings = {}; +} + +if (!qx.Settings._customSettings) { + qx.Settings._customSettings = {}; +} + +/** the default settings */ +qx.Settings._defaultSettings = {}; + + + + +/* +--------------------------------------------------------------------------- + ATTACH GLOBAL DATA +--------------------------------------------------------------------------- +*/ + +qx._LOADSTART = (new Date).valueOf(); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITES METHODS +--------------------------------------------------------------------------- +*/ + +qx.Settings.substitute = function(vTemplate) +{ + if (typeof vTemplate !== "string") { + return vTemplate; + } + + return vTemplate.replace(/\%\{(.+)\}/g, function(vMatch, vKey) { + return eval(vKey); + }); +}; + + + + + + +/* +--------------------------------------------------------------------------- + ACCESS METHODS +--------------------------------------------------------------------------- +*/ + +qx.Settings.getValue = function(vKey) { + return qx.Settings.getValueOfClass(qx.Class.classname, vKey); +} + +qx.Settings.getValueOfClass = function(vClassName, vKey) +{ + var vCustomObject = qx.Settings._customSettings[vClassName]; + if (vCustomObject && vCustomObject[vKey] != null) { + return vCustomObject[vKey]; + } + + var vDefaultObject = qx.Settings._defaultSettings[vClassName]; + if (vDefaultObject && vDefaultObject[vKey] != null) { + return vDefaultObject[vKey]; + } + + return null; +} + +qx.Settings.setDefault = function(vKey, vValue) { + return qx.Settings.setDefaultOfClass(qx.Class.classname, vKey, vValue); +} + +qx.Settings.setDefaultOfClass = function(vClassName, vKey, vValue) +{ + var vDefaultObject = qx.Settings._defaultSettings[vClassName]; + + if (!vDefaultObject) { + vDefaultObject = qx.Settings._defaultSettings[vClassName] = {}; + } + + // default values doesn't support substitution + vDefaultObject[vKey] = vValue; +} + +qx.Settings.setCustom = function(vKey, vValue) { + return qx.Settings.setCustomOfClass(qx.Class.classname, vKey, vValue); +} + +qx.Settings.setCustomOfClass = function(vClassName, vKey, vValue) +{ + var vCustomObject = qx.Settings._customSettings[vClassName]; + + if (!vCustomObject) { + vCustomObject = qx.Settings._customSettings[vClassName] = {}; + } + + vCustomObject[vKey] = qx.Settings.substitute(vValue); +} + + + + + + + +/* +--------------------------------------------------------------------------- + IMPORT VARIABLES OF CUSTOM SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.init = function() +{ + for (var vClass in qx.Settings._customSettings) + { + var vSettings = qx.Settings._customSettings[vClass]; + + for (var vKey in vSettings) { + qx.Settings.setCustomOfClass(vClass, vKey, vSettings[vKey]); + } + } +} + +qx.Settings.init(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Command.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Command.js new file mode 100644 index 0000000000..d7026203f9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Command.js @@ -0,0 +1,349 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.locale.Key) + +************************************************************************ */ + +/** + * This contains a command with shortcut. + * + * Each command could be assigned to multiple widgets. + * + * @event execute {qx.event.type.DataEvent} when the command is executed. Sets the + * "data" property of the event to the object that issued the command. + * + * @param vShortcut {String} shortcuts can be composed of optional modifier + * keys Control, Alt, Shift, Meta and a non modifier key. + * If no non modifier key is specified, the second paramater is evaluated. + * The key must be seperated by a <code>+</code> or <code>-</code> character. + * Examples: Alt+F1, Control+C, Control+Alt+Enf + * + * @param vKeyCode {Integer} Additional key of the command interpreted as a keyCode. + */ +qx.OO.defineClass("qx.client.Command", qx.core.Target, +function(vShortcut, vKeyCode) +{ + qx.core.Target.call(this); + + this._modifier = {}; + this._key = null; + + if (vShortcut != null) { + this.setShortcut(vShortcut); + } + + if (vKeyCode != null) + { + this.warn("The use of keyCode in command is deprecated. Use keyIdentifier instead."); + this.setKeyCode(vKeyCode); + } + + // OSX warning for Alt key combinations + if (this._modifier.Alt && this._key && this._key.length == 1) { + if ( + (this._key >= "A" && this._key <= "Z") || + (this._key >= "0" && this._key <= "9") + ) { + this.warn("A shortcut containing Alt and a letter or number will not work under OS X!"); + } + } + qx.event.handler.EventHandler.getInstance().addCommand(this); +}); + + +/** the command shortcut */ +qx.OO.addProperty({ name : "shortcut", type : "string" }); + +/** + * keyCode + * @deprecated + * + * Still there for compatibility with the old key handler/commands + */ +qx.OO.addProperty({ name : "keyCode", type : "number" }); + +/** KeyIdentifier */ +qx.OO.addProperty({ name : "keyIdentifier", type : "string" }); + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Fire the "execute" event on this command. + * + * @param vTarget {Object} Object which issued the execute event + */ +qx.Proto.execute = function(vTarget) +{ + if (this.hasEventListeners("execute")) { + var event = new qx.event.type.DataEvent("execute", vTarget); + this.dispatchEvent(event, true); + } + + return false; +}; + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyShortcut = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._modifier = {}; + this._key = null; + + // split string to get each key which must be pressed + // build a hash with active keys + var a = propValue.split(/[-+\s]+/); + var al = a.length; + + for (var i=0; i<al; i++) + { + var identifier = this._oldKeyNameToKeyIdentifier(a[i]); + + switch (identifier) + { + case "Control": + case "Shift": + case "Meta": + case "Alt": + this._modifier[identifier] = true; + break; + + case "Unidentified": + var msg = "Not a valid key name for a command: " + a[i]; + this.error(msg); + throw msg; + + default: + if (this._key) { + var msg = "You can only specify one non modifier key!"; + this.error(msg); + throw msg; + } + this._key = identifier; + } + } + } + return true; +}; + + + +/* +-------------------------------------------------------------------------- + INTERNAL MATCHING LOGIC +--------------------------------------------------------------------------- +*/ + +/** + * Checks wether the given key event matches the command's shortcut + * + * @param e {qx.event.type.KeyEvent} the key event object + * @return {Boolean} wether the commands shortcut matches the key event + */ +qx.Proto._matchesKeyEvent = function(e) +{ + var key = this._key || this.getKeyIdentifier(); + if (!key && !this.getKeyCode()) { + // no shortcut defined. + return; + } + + // pre-check for check special keys + // we handle this here to omit to check this later again. + if ( + (this._modifier.Shift && !e.isShiftPressed()) || + (this._modifier.Control && !e.isCtrlPressed()) || +// (this._modifier.Meta && !e.getMetaKey()) || + (this._modifier.Alt && !e.isAltPressed()) + ) { + return false; + } + + if (key) + { + if (key == e.getKeyIdentifier()) { + return true; + } + } + else + { + if (this.getKeyCode() == e.getKeyCode()) { + return true; + } + } + + return false; +}; + + +/* +--------------------------------------------------------------------------- + COMPATIBILITY TO COMMAND +--------------------------------------------------------------------------- +*/ + +qx.Proto._oldKeyNameToKeyIdentifierMap = +{ + // all other keys are converted by converting the first letter to uppercase + + esc : "Escape", + ctrl : "Control", + print : "PrintScreen", + del : "Delete", + pageup : "PageUp", + pagedown : "PageDown", + numlock : "NumLock", + numpad_0 : "0", + numpad_1 : "1", + numpad_2 : "2", + numpad_3 : "3", + numpad_4 : "4", + numpad_5 : "5", + numpad_6 : "6", + numpad_7 : "7", + numpad_8 : "8", + numpad_9 : "9", + numpad_divide : "/", + numpad_multiply : "*", + numpad_minus : "-", + numpad_plus : "+" +}; + + +/** + * converts an old key name as found in {@link qx.event.type.KeyEvent.keys} to + * the new keyIdentifier. + * + * @param keyName {String} old name of the key. + * @return {String} corresponding keyIdentifier or "Unidentified" if a conversion was not possible + */ +qx.Proto._oldKeyNameToKeyIdentifier = function(keyName) +{ + var keyHandler = qx.event.handler.KeyEventHandler.getInstance(); + var keyIdentifier = "Unidentified"; + + if (keyHandler.isValidKeyIdentifier(keyName)) { + return keyName; + } + + if (keyName.length == 1 && keyName >= "a" && keyName <= "z") { + return keyName.toUpperCase(); + } + + keyName = keyName.toLowerCase(); + + // check wether its a valid old key name + if (!qx.event.type.KeyEvent.keys[keyName]) { + return "Unidentified"; + } + + var keyIdentifier = this._oldKeyNameToKeyIdentifierMap[keyName]; + if (keyIdentifier) { + return keyIdentifier; + } else { + return qx.lang.String.toFirstUp(keyName); + } +}; + + +/* +--------------------------------------------------------------------------- + STRING CONVERTION +--------------------------------------------------------------------------- +*/ + +/** + * Returns the shortcut as string + * + * @return {String} shortcut + */ +qx.Proto.toString = function() +{ + //var vShortcut = this.getShortcut(); + var vKeyCode = this.getKeyCode(); + var key = this._key || this.getKeyIdentifier(); + + var vString = []; + + for (var modifier in this._modifier) { + vString.push(qx.locale.Key.getKeyName("short", modifier)); + } + + if (key) { + vString.push(qx.locale.Key.getKeyName("short", key)); + } + /* + if (vShortcut != null) { + vString.push(vShortcut); + } + */ + if (vKeyCode != null) + { + var vTemp = qx.event.type.KeyEvent.codes[vKeyCode]; + vString.push(vTemp ? qx.lang.String.toFirstUp(vTemp) : String(vKeyCode)); + } + + return vString.join("-"); +}; + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Destructor + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._shortcutParts = null; + + var vMgr = qx.event.handler.EventHandler.getInstance(); + if (vMgr) { + vMgr.removeCommand(this); + } + + return qx.core.Target.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/History.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/History.js new file mode 100644 index 0000000000..3cc8004d46 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/History.js @@ -0,0 +1,139 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.manager.object.AliasManager) +#embed(qx.static/history/historyHelper.html) + +************************************************************************ */ + +/** + * A helper for using the browser history in JavaScript Applications without + * reloading the main page. + * <p> + * Adds entries to the browser history and fires a "request" event when one of + * the entries was requested by the user (e.g. by clicking on the back button). + * </p> + * + * @event request {qx.event.type.DataEvent} Fired when the user moved in the + * history. The data property of the event holds the command, which was + * passed to {@link #addToHistory}. + */ +qx.OO.defineClass("qx.client.History", qx.core.Target, +function() { + qx.core.Target.call(this); + + this._pageFlag = true; +}); + + +/** + * Initializes the History. This method has to called by applications using this + * class once during initialization. Subsequent calls have no (negative) effect. + */ +qx.Proto.init = function() { + if (this._iframe == null) { + this._iframe = document.createElement("iframe"); + this._iframe.style.visibility = "hidden"; + document.body.appendChild(this._iframe); + } +} + + +/** + * Adds an entry to the browser history. + * + * @param command {String} a string representing the old state of the + * application. This command will be delivered in the data property of + * the "request" event. + * @param newTitle {String ? null} the page title to set after the history entry + * is done. This title should represent the new state of the application. + */ +qx.Proto.addToHistory = function(command, newTitle) { + if (command == this._currentCommand) { + document.title = newTitle; + } else { + if (this._iframe == null) { + throw new Error("You have to call init first!"); + } + + this._pageFlag = !this._pageFlag; + this._currentCommand = command; + this._newTitle = newTitle; + + // NOTE: We need the command attribute to enforce a loading of the page + // (Otherwise we don't get an onload event). + // The browser will still cache commands loaded once. + // Without the onload-problem anchors would work, too. + // (Anchors would have the advantage that the helper is only loaded once) + this._iframe.src = this.getSetting("helperFile") + "?c=" + command; + } +} + + +/** + * Event handler. Called when the history helper page was loaded. + * + * @param location {Map} the location property of the window object of the + * helper page. + */ +qx.Proto._onHistoryLoad = function(location) +{ + try { + var equalsPos = location.search.indexOf("="); + var command = location.search.substring(equalsPos + 1); + + if (this._newTitle) { + document.title = this._newTitle; + this._newTitle = null; + } + + if (command != this._currentCommand) { + this._currentCommand = command; + + this.createDispatchDataEvent("request", command); + } + } catch (exc) { + this.error("Handling history load failed", exc); + } + + qx.ui.core.Widget.flushGlobalQueues(); +} + + +/** The URL to the helper page. */ +qx.Settings.setDefault("helperFile", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "staticUri") + "/history/historyHelper.html"); + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/NativeWindow.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/NativeWindow.js new file mode 100644 index 0000000000..e63ac4f12e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/NativeWindow.js @@ -0,0 +1,641 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.html.Window) + +************************************************************************ */ + +qx.OO.defineClass("qx.client.NativeWindow", qx.core.Target, +function(vUrl, vName) +{ + qx.core.Target.call(this); + + + // ************************************************************************ + // TIMER + // ************************************************************************ + + this._timer = new qx.client.Timer(100); + this._timer.addEventListener("interval", this._oninterval, this); + + + // ************************************************************************ + // INITIAL PROPERTIES + // ************************************************************************ + + if (vUrl != null) { + this.setUrl(vUrl); + } + + if (vName != null) { + this.setName(vName); + } +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + If the window is open or closed +*/ +qx.OO.addProperty({ name : "open", type : "boolean", defaultValue : false }); + +/*! + The outer width of the window. +*/ +qx.OO.addProperty({ name : "width", type : "number", defaultValue : 400, impl : "dimension" }); + +/*! + The outer height of the window. +*/ +qx.OO.addProperty({ name : "height", type : "number", defaultValue : 250, impl : "dimension" }); + +/*! + The left screen coordinate of the window. +*/ +qx.OO.addProperty({ name : "left", type : "number", defaultValue : 100, impl : "position" }); + +/*! + The top screen coordinate of the window. +*/ +qx.OO.addProperty({ name : "top", type : "number", defaultValue : 200, impl : "position" }); + +/*! + Should be window be modal +*/ +qx.OO.addProperty({ name : "modal", type : "boolean", defaultValue : false }); + +/*! + Should be window be dependent on this application window +*/ +qx.OO.addProperty({ name : "dependent", type : "boolean", defaultValue : true }); + +/*! + The url +*/ +qx.OO.addProperty({ name : "url", type : "string" }); + +/*! + The window name +*/ +qx.OO.addProperty({ name : "name", type : "string" }); + +/*! + The text of the statusbar +*/ +qx.OO.addProperty({ name : "status", type : "string", defaultValue : "Ready" }); + +/*! + Should the statusbar be shown +*/ +qx.OO.addProperty({ name : "showStatusbar", type : "boolean", defaultValue : false }); + +/*! + Should the menubar be shown +*/ +qx.OO.addProperty({ name : "showMenubar", type : "boolean", defaultValue : false }); + +/*! + Should the location(bar) be shown +*/ +qx.OO.addProperty({ name : "showLocation", type : "boolean", defaultValue : false }); + +/*! + Should the toolbar be shown +*/ +qx.OO.addProperty({ name : "showToolbar", type : "boolean", defaultValue : false }); + +/*! + If the window is resizeable +*/ +qx.OO.addProperty({ name : "resizeable", type : "boolean", defaultValue : true }); + +/*! + If the window is able to scroll and has visible scrollbars if needed +*/ +qx.OO.addProperty({ name : "allowScrollbars", type : "boolean", defaultValue : true }); + + + +/* +--------------------------------------------------------------------------- + STATE +--------------------------------------------------------------------------- +*/ + +qx.Proto._loaded = false; + + + + +/* +--------------------------------------------------------------------------- + PROPERTY GROUPS +--------------------------------------------------------------------------- +*/ + +qx.OO.addPropertyGroup({ name : "location", members : [ "left", "top" ]}); +qx.OO.addPropertyGroup({ name : "dimension", members : [ "width", "height" ]}); + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyPosition = function(propValue, propOldValue, propName) +{ + /* + http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/sp2brows.mspx + Changes to Functionality in Microsoft Windows XP Service Pack 2 + Part 5: Enhanced Browsing Security + URLACTION_FEATURE_WINDOW_RESTRICTIONS + Allow script-initiated windows without size or position constraints + Code: 2102 + */ + + if (!this.isClosed()) + { + try + { + this._window.moveTo(this.getLeft(), this.getTop()); + } + catch(ex) + { + this.error("Cross-Domain Scripting problem: Could not move window!", ex); + } + } + + return true; +} + +qx.Proto._modifyDimension = function(propValue, propOldValue, propName) +{ + /* + http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/sp2brows.mspx + Changes to Functionality in Microsoft Windows XP Service Pack 2 + Part 5: Enhanced Browsing Security + URLACTION_FEATURE_WINDOW_RESTRICTIONS + Allow script-initiated windows without size or position constraints + Code: 2102 + */ + + if (!this.isClosed()) + { + try + { + this._window.resizeTo(this.getWidth(), this.getHeight()); + } + catch(ex) + { + this.error("Cross-Domain Scripting problem: Could not resize window!", ex); + } + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propName) +{ + if (!this.isClosed()) { + this._window.name = propValue; + } + + return true; +} + +qx.Proto._modifyUrl = function(propValue, propOldValue, propName) +{ + // String hack needed for old compressor (compile.py) + if(!this.isClosed()) { + this._window.location.replace(propValue != null ? propValue : ("javascript:/" + "/")); + } + + return true; +} + +qx.Proto._modifyOpen = function(propValue, propOldValue, propData) +{ + propValue ? this._open() : this._close(); + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + NAME +--------------------------------------------------------------------------- +*/ + +qx.Proto.getName = function() +{ + if (!this.isClosed()) + { + try + { + var vName = this._window.name; + } + catch(ex) + { + return this._valueName; + } + + if (vName == this._valueName) + { + return vName; + } + else + { + throw new Error("window name and name property are not identical"); + } + } + else + { + return this._valueName; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.isClosed = function() +{ + var vClosed = true; + + if (this._window) + { + try { + vClosed = this._window.closed; + } catch(ex) {} + } + + return vClosed; +} + +qx.Proto.open = function() { + this.setOpen(true); +} + +qx.Proto.close = function() { + this.setOpen(false); +} + +qx.Proto.isLoaded = function() { + return this._loaded; +} + + + + + + + +/* +--------------------------------------------------------------------------- + OPEN METHOD +--------------------------------------------------------------------------- +*/ + +qx.Proto._open = function() +{ + var vConf = []; + + + /* + ------------------------------------------------------------------------------ + PRE CONFIGURE WINDOW + ------------------------------------------------------------------------------ + */ + + if (this.getWidth() != null) + { + vConf.push("width"); + vConf.push("="); + vConf.push(this.getWidth()); + vConf.push(","); + } + + if (this.getHeight() != null) + { + vConf.push("height"); + vConf.push("="); + vConf.push(this.getHeight()); + vConf.push(","); + } + + if (this.getLeft() != null) + { + vConf.push("left"); + vConf.push("="); + vConf.push(this.getLeft()); + vConf.push(","); + } + + if (this.getTop() != null) + { + vConf.push("top"); + vConf.push("="); + vConf.push(this.getTop()); + vConf.push(","); + } + + + + vConf.push("dependent"); + vConf.push("="); + vConf.push(this.getDependent() ? "yes" : "no"); + vConf.push(","); + + vConf.push("resizable"); + vConf.push("="); + vConf.push(this.getResizeable() ? "yes" : "no"); + vConf.push(","); + + vConf.push("status"); + vConf.push("="); + vConf.push(this.getShowStatusbar() ? "yes" : "no"); + vConf.push(","); + + vConf.push("location"); + vConf.push("="); + vConf.push(this.getShowLocation() ? "yes" : "no"); + vConf.push(","); + + vConf.push("menubar"); + vConf.push("="); + vConf.push(this.getShowMenubar() ? "yes" : "no"); + vConf.push(","); + + vConf.push("toolbar"); + vConf.push("="); + vConf.push(this.getShowToolbar() ? "yes" : "no"); + vConf.push(","); + + vConf.push("scrollbars"); + vConf.push("="); + vConf.push(this.getAllowScrollbars() ? "yes" : "no"); + vConf.push(","); + + vConf.push("modal"); + vConf.push("="); + vConf.push(this.getModal() ? "yes" : "no"); + vConf.push(","); + + + + + + + /* + ------------------------------------------------------------------------------ + OPEN WINDOW + ------------------------------------------------------------------------------ + */ + + if (this.getName() != null) { + this.setName("qx_NativeWindow" + this.toHashCode()); + } + + this._window = window.open(this.getUrl(), this.getName(), vConf.join("")); + + if (this.isClosed()) + { + this.error("Window could not be opened. It seems, there is a popup blocker active!"); + } + else + { + // This try-catch is needed because of cross domain issues (access rights) + try + { + this._window._native = this; + this._window.onload = this._onload; + } + catch(ex) {} + + // start timer for close detection + this._timer.start(); + + // block original document + if (this.getModal()) { + qx.ui.core.ClientDocument.getInstance().block(this); + } + } +} + +qx.Proto._close = function() +{ + if (!this._window) { + return; + } + + // stop timer for close detection + this._timer.stop(); + + // release window again + if (this.getModal()){ + qx.ui.core.ClientDocument.getInstance().release(this); + } + + // finally close window + if (!this.isClosed()) { + this._window.close(); + } + + try + { + this._window._native = null; + this._window.onload = null; + } + catch(ex) {}; + + this._window = null; + this._loaded = false; + + this.createDispatchEvent("close"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CENTER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.centerToScreen = function() { + return this._centerHelper((screen.width - this.getWidth()) / 2, (screen.height - this.getHeight()) / 2); +} + +qx.Proto.centerToScreenArea = function() { + return this._centerHelper((screen.availWidth - this.getWidth()) / 2, (screen.availHeight - this.getHeight()) / 2); +} + +qx.Proto.centerToOpener = function() { + return this._centerHelper(((qx.html.Window.getInnerWidth(window) - this.getWidth()) / 2) + qx.html.Location.getScreenBoxLeft(window.document.body), ((qx.html.Window.getInnerHeight(window) - this.getHeight()) / 2) + qx.html.Location.getScreenBoxTop(window.document.body)); +} + +qx.Proto._centerHelper = function(l, t) +{ + // set new values + this.setLeft(l); + this.setTop(t); + + // focus window if opened + if (!this.isClosed()) { + this.focus(); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.focus = function() +{ + if (!this.isClosed()) { + this._window.focus(); + } +} + +qx.Proto.blur = function() +{ + if (!this.isClosed()) { + this._window.blur(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._oninterval = function(e) +{ + if (this.isClosed()) { + this.setOpen(false); + } + else if (!this._loaded) + { + // This try-catch is needed because of cross domain issues (access rights) + try + { + if (this._window.document && this._window.document.readyState == "complete") + { + this._loaded = true; + this.createDispatchEvent("load"); + } + } + catch(ex) {}; + } +} + +qx.Proto._onload = function(e) +{ + var obj = this._native; + + if (!obj._loaded) + { + obj._loaded = true; + obj.createDispatchEvent("load"); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this.getDependent()) { + this.close(); + } + + if (this._timer) + { + this._timer.stop(); + this._timer = null; + } + + if (this._window) + { + try + { + this._window._native = null; + this._window.onload = null; + } + catch(ex) {}; + + this._window = null; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Timer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Timer.js new file mode 100644 index 0000000000..36fb11dc08 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/client/Timer.js @@ -0,0 +1,185 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Global timer support. Simplifies javascript intervals for objects. + * + * @event interval {qx.event.type.Event} + */ +qx.OO.defineClass("qx.client.Timer", qx.core.Target, +function(vInterval) +{ + qx.core.Target.call(this); + + this.setEnabled(false); + + if (vInterval != null) { + this.setInterval(vInterval); + } + + // Object wrapper to timer event + var o = this; + this.__oninterval = function() { o._oninterval(); } +}); + +qx.OO.addProperty({ name : "interval", type : "number", defaultValue : 1000 }); + +qx.Proto._intervalHandle = null; + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + window.clearInterval(this._intervalHandle); + this._intervalHandle = null; + } + else if (propValue) + { + this._intervalHandle = window.setInterval(this.__oninterval, this.getInterval()); + } + + return true; +} + + + + +/* +--------------------------------------------------------------------------- + USER-ACCESS +--------------------------------------------------------------------------- +*/ + +qx.Proto.start = function() { + this.setEnabled(true); +} + +qx.Proto.startWith = function(vInterval) +{ + this.setInterval(vInterval); + this.start(); +} + +qx.Proto.stop = function() { + this.setEnabled(false); +} + +qx.Proto.restart = function() +{ + this.stop(); + this.start(); +} + +qx.Proto.restartWith = function(vInterval) +{ + this.stop(); + this.startWith(vInterval); +} + + + + +/* +--------------------------------------------------------------------------- + EVENT-MAPPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._oninterval = function() +{ + if (this.getEnabled()) { + this.createDispatchEvent("interval"); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + // Stop interval + this.stop(); + + // Clear handle + if (this._intervalHandler) + { + window.clearInterval(this._intervalHandle); + this._intervalHandler = null; + } + + // Clear object wrapper function + this.__oninterval = null; + + // Call qx.core.Target to do the other dispose work + return qx.core.Target.prototype.dispose.call(this); +} + + + + + +/* +--------------------------------------------------------------------------- + HELPER +--------------------------------------------------------------------------- +*/ + +qx.client.Timer.once = function(vFunction, vObject, vTimeout) +{ + // Create time instance + var vTimer = new qx.client.Timer(vTimeout); + + // Add event listener to interval + vTimer.addEventListener("interval", function(e) + { + vFunction.call(vObject, e); + vTimer.dispose(); + + vObject = null; + }, vObject); + + // Directly start timer + vTimer.start(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractApplication.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractApplication.js new file mode 100644 index 0000000000..0d0877f5aa --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractApplication.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +qx.OO.defineClass("qx.component.AbstractApplication", qx.component.AbstractComponent, +function() { + qx.component.AbstractComponent.call(this); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractComponent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractComponent.js new file mode 100644 index 0000000000..3bb95a1309 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/AbstractComponent.js @@ -0,0 +1,68 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +qx.OO.defineClass("qx.component.AbstractComponent", qx.core.Target, +function() +{ + qx.core.Target.call(this); + +}); + + +/*! + Run initialisation part of component creation. +*/ +qx.Proto.initialize = function() {}; + +/*! + Run main part of component creation. +*/ +qx.Proto.main = function() {}; + +/*! + Run finalization part of component creation. +*/ +qx.Proto.finalize = function() {}; + +/*! + Terminate this component. +*/ +qx.Proto.close = function() {}; + +/*! + Terminate this component. +*/ +qx.Proto.terminate = function() {}; + + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/DummyApplication.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/DummyApplication.js new file mode 100644 index 0000000000..68f76172ba --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/DummyApplication.js @@ -0,0 +1,43 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +qx.OO.defineClass("qx.component.DummyApplication", qx.component.AbstractApplication, +function() { + qx.component.AbstractApplication.call(this); +}); + + + +/* +--------------------------------------------------------------------------- + DIRECT SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/AbstractInitComponent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/AbstractInitComponent.js new file mode 100644 index 0000000000..7e7ebee012 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/AbstractInitComponent.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Abstract application initializer + */ +qx.OO.defineClass("qx.component.init.AbstractInitComponent", qx.component.AbstractComponent, +function() { + qx.component.AbstractComponent.call(this); +}); + + + +/** + * Run initialisation part of component creation. + * + * @param e {Event} event object + */ +qx.Proto.initialize = function(e) { + return qx.core.Init.getInstance().getApplicationInstance().initialize(e); +}; + + +/** + * Run main part of component creation. + * + * @param e {Event} event object + */ +qx.Proto.main = function(e) { + return qx.core.Init.getInstance().getApplicationInstance().main(e); +}; + + +/** + * Run finalization part of component creation. + * + * @param e {Event} event object + */ +qx.Proto.finalize = function(e) { + return qx.core.Init.getInstance().getApplicationInstance().finalize(e); +}; + + +/** + * Terminate this component. + * + * @param e {Event} event object + */ +qx.Proto.close = function(e) { + return qx.core.Init.getInstance().getApplicationInstance().close(e); +}; + + +/** + * Terminate this component. + * + * @param e {Event} event object + */ +qx.Proto.terminate = function(e) { + return qx.core.Init.getInstance().getApplicationInstance().terminate(e); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/BasicInitComponent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/BasicInitComponent.js new file mode 100644 index 0000000000..f87d768241 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/BasicInitComponent.js @@ -0,0 +1,55 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +qx.OO.defineClass("qx.component.init.BasicInitComponent", qx.component.init.AbstractInitComponent, +function() { + qx.component.init.AbstractInitComponent.call(this); +}); + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onload = function(e) +{ + this.initialize(e); + this.main(e); + this.finalize(e); +} + +qx.Proto._onbeforeunload = function(e) { + this.close(e); +} + +qx.Proto._onunload = function(e) { + this.terminate(e); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/InterfaceInitComponent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/InterfaceInitComponent.js new file mode 100644 index 0000000000..211a4ff53d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/component/init/InterfaceInitComponent.js @@ -0,0 +1,183 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.component.init.InterfaceInitComponent", qx.component.init.BasicInitComponent, +function() { + qx.component.init.BasicInitComponent.call(this); +}); + + + + + +/* +--------------------------------------------------------------------------- + READY STATE +--------------------------------------------------------------------------- +*/ + +qx.Proto._uiReady = false; + +qx.Proto.isUiReady = function() { + return this._uiReady; +} + + + + + + +/* +--------------------------------------------------------------------------- + STATE MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto.initialize = function() +{ + // Force creation of event handler + qx.event.handler.EventHandler.getInstance(); + + // Force creation of client document + qx.ui.core.ClientDocument.getInstance(); + + // Start real initialisation + var start = (new Date).valueOf(); + qx.component.init.BasicInitComponent.prototype.initialize.call(this); + this.info("initialize runtime: " + ((new Date).valueOf() - start) + "ms"); +}; + +qx.Proto.main = function() +{ + // Start real main process + var start = (new Date).valueOf(); + qx.component.init.BasicInitComponent.prototype.main.call(this); + this.info("main runtime: " + ((new Date).valueOf() - start) + "ms"); + + this.debug("preloading visible images..."); + new qx.io.image.PreloaderSystem(qx.manager.object.ImageManager.getInstance().getPreloadImageList(), this.finalize, this); +}; + + +qx.Proto.finalize = function() +{ + var start = (new Date).valueOf(); + + this._printPreloadComplete(); + this._uiReady = true; + + // Show initial widgets + qx.ui.core.Widget.flushGlobalQueues(); + + // Finally attach event to make the GUI ready for the user + qx.event.handler.EventHandler.getInstance().attachEvents(); + + qx.component.init.BasicInitComponent.prototype.finalize.call(this); + + this.info("finalize runtime: " + ((new Date).valueOf() - start) + "ms"); +}; + +qx.Proto.close = function() +{ + var start = (new Date).valueOf(); + qx.component.init.BasicInitComponent.prototype.close.call(this); + + this.info("close runtime: " + ((new Date).valueOf() - start) + "ms"); +}; + +qx.Proto.terminate = function() +{ + var start = (new Date).valueOf(); + qx.component.init.BasicInitComponent.prototype.terminate.call(this); + + this.info("terminate runtime: " + ((new Date).valueOf() - start) + "ms"); +}; + + + + + +/* +--------------------------------------------------------------------------- + PRELOAD UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.preload = function() +{ + if (!this._preloadDone) + { + this.debug("preloading hidden images..."); + new qx.io.image.PreloaderSystem(qx.manager.object.ImageManager.getInstance().getPostPreloadImageList(), this._printPreloadComplete, this); + this._preloadDone = true; + } +} + +qx.Proto._printPreloadComplete = function() { + this.debug("preloading complete"); +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onload = function(e) +{ + this.initialize(); + this.main(); + + // Note: finalize will be called through image preloader +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._preloadDone = null; + this._uiReady = null; + + return qx.component.init.BasicInitComponent.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Client.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Client.js new file mode 100644 index 0000000000..7f62a620cb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Client.js @@ -0,0 +1,406 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/*! + Basic client detection implementation + + Version shemes following wikipedia: major.minor[.revision[.build]] + http://en.wikipedia.org/wiki/Software_version +*/ +qx.OO.defineClass("qx.core.Client", Object, +function() +{ + var vRunsLocally = window.location.protocol === "file:"; + + var vBrowserUserAgent = navigator.userAgent; + var vBrowserVendor = navigator.vendor; + var vBrowserProduct = navigator.product; + var vBrowserPlatform = navigator.platform; + var vBrowserModeHta = false; + var vBrowser; + + var vEngine = null; + var vEngineVersion = null; + var vEngineVersionMajor = 0; + var vEngineVersionMinor = 0; + var vEngineVersionRevision = 0; + var vEngineVersionBuild = 0; + + var vEngineEmulation = null; + var vVersionHelper; + + if (window.opera && /Opera[\s\/]([0-9\.]*)/.test(vBrowserUserAgent)) + { + vEngine = "opera"; + vEngineVersion = RegExp.$1; + + // Fix Opera version to match wikipedia style + vEngineVersion = vEngineVersion.substring(0, 3) + "." + vEngineVersion.substring(3); + + vEngineEmulation = vBrowserUserAgent.indexOf("MSIE") !== -1 ? "mshtml" : vBrowserUserAgent.indexOf("Mozilla") !== -1 ? "gecko" : null; + } + else if (typeof vBrowserVendor==="string" && vBrowserVendor==="KDE" && /KHTML\/([0-9-\.]*)/.test(vBrowserUserAgent)) + { + vEngine = "khtml"; + vBrowser = "konqueror"; + vEngineVersion = RegExp.$1; + } + else if (vBrowserUserAgent.indexOf("AppleWebKit") != -1 && /AppleWebKit\/([0-9-\.]*)/.test(vBrowserUserAgent)) + { + vEngine = "webkit"; + vEngineVersion = RegExp.$1; + + if(vBrowserUserAgent.indexOf("Safari") != -1) { + vBrowser = "safari"; + } else if(vBrowserUserAgent.indexOf("Omni") != -1) { + vBrowser = "omniweb"; + } else { + vBrowser = "other webkit"; + } + } + else if (window.controllers && typeof vBrowserProduct==="string" && vBrowserProduct==="Gecko" && /rv\:([^\);]+)(\)|;)/.test(vBrowserUserAgent)) + { + // http://www.mozilla.org/docs/dom/domref/dom_window_ref13.html + vEngine = "gecko"; + vEngineVersion = RegExp.$1; + + if(vBrowserUserAgent.indexOf("Firefox") != -1) { + vBrowser = "firefox"; + } else if(vBrowserUserAgent.indexOf("Camino") != -1) { + vBrowser = "camino"; + } else if(vBrowserUserAgent.indexOf("Galeon") != -1) { + vBrowser = "galeon"; + } else { + vBrowser = "other gecko"; + } + } + else if (/MSIE\s+([^\);]+)(\)|;)/.test(vBrowserUserAgent)) + { + vEngine = "mshtml"; + vEngineVersion = RegExp.$1; + + vBrowserModeHta = !window.external; + } + + if (vEngineVersion) + { + vVersionHelper = vEngineVersion.split("."); + + vEngineVersionMajor = vVersionHelper[0] || 0; + vEngineVersionMinor = vVersionHelper[1] || 0; + vEngineVersionRevision = vVersionHelper[2] || 0; + vEngineVersionBuild = vVersionHelper[3] || 0; + } + + var vEngineBoxSizingAttr = vEngine == "gecko" ? "-moz-box-sizing" : vEngine == "mshtml" ? null : "box-sizing"; + var vEngineQuirksMode = document.compatMode !== "CSS1Compat"; + + var vDefaultLocale = "en"; + var vBrowserLocale = (vEngine == "mshtml" ? navigator.userLanguage : navigator.language).toLowerCase(); + var vBrowserLocaleVariant = null; + + var vBrowserLocaleVariantIndex = vBrowserLocale.indexOf("-"); + if (vBrowserLocaleVariantIndex != -1) + { + vBrowserLocaleVariant = vBrowserLocale.substr(vBrowserLocaleVariantIndex+1); + vBrowserLocale = vBrowserLocale.substr(0, vBrowserLocaleVariantIndex); + } + + var vPlatform = "none"; + var vPlatformWindows = false; + var vPlatformMacintosh = false; + var vPlatformUnix = false; + var vPlatformOther = false; + + if (vBrowserPlatform.indexOf("Windows") != -1 || vBrowserPlatform.indexOf("Win32") != -1 || vBrowserPlatform.indexOf("Win64") != -1) + { + vPlatformWindows = true; + vPlatform = "win"; + } + else if (vBrowserPlatform.indexOf("Macintosh") != -1 || vBrowserPlatform.indexOf("MacIntel") != -1) + { + vPlatformMacintosh = true; + vPlatform = "mac"; + } + else if (vBrowserPlatform.indexOf("X11") != -1 || vBrowserPlatform.indexOf("Linux") != -1 || vBrowserPlatform.indexOf("BSD") != -1) + { + vPlatformUnix = true; + vPlatform = "unix"; + } + else + { + vPlatformOther = true; + vPlatform = "other"; + } + + var vGfxVml = false; + var vGfxSvg = false; + var vGfxSvgBuiltin = false; + var vGfxSvgPlugin = false; + + if (vEngine == "mshtml") + { + vGfxVml = true; + + // TODO: Namespace for VML: + // document.write('<style>v\:*{ behavior:url(#default#VML); }</style>'); + // document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>'); + } + + if (document.implementation && document.implementation.hasFeature) + { + if (document.implementation.hasFeature("org.w3c.dom.svg", "1.0")) + { + vGfxSvg = vGfxSvgBuiltin = true; + } + } + + this._runsLocally = vRunsLocally; + + this._engineName = vEngine; + this._engineNameMshtml = vEngine === "mshtml"; + this._engineNameGecko = vEngine === "gecko"; + this._engineNameOpera = vEngine === "opera"; + this._engineNameKhtml = vEngine === "khtml"; + this._engineNameWebkit = vEngine === "webkit"; + + this._engineVersion = parseFloat(vEngineVersion); + this._engineVersionMajor = parseInt(vEngineVersionMajor); + this._engineVersionMinor = parseInt(vEngineVersionMinor); + this._engineVersionRevision = parseInt(vEngineVersionRevision); + this._engineVersionBuild = parseInt(vEngineVersionBuild); + + this._engineQuirksMode = vEngineQuirksMode; + this._engineBoxSizingAttribute = vEngineBoxSizingAttr; + this._engineEmulation = vEngineEmulation; + + this._defaultLocale = vDefaultLocale; + + this._browserPlatform = vPlatform; + this._browserPlatformWindows = vPlatformWindows; + this._browserPlatformMacintosh = vPlatformMacintosh; + this._browserPlatformUnix = vPlatformUnix; + this._browserPlatformOther = vPlatformOther; + this._browserModeHta = vBrowserModeHta; + this._browserLocale = vBrowserLocale; + this._browserLocaleVariant = vBrowserLocaleVariant; + + this._gfxVml = vGfxVml; + this._gfxSvg = vGfxSvg; + this._gfxSvgBuiltin = vGfxSvgBuiltin; + this._gfxSvgPlugin = vGfxSvgPlugin; + + this._fireBugActive = (window.console && console.log && console.debug && console.assert); + + this._supportsTextContent = (document.documentElement.textContent !== undefined); + this._supportsInnerText = (document.documentElement.innerText !== undefined); +}); + + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getRunsLocally = function() { + return this._runsLocally; +} + +qx.Proto.getEngine = function() { + return this._engineName; +} + +qx.Proto.getVersion = function() { + return this._engineVersion; +} + +qx.Proto.getMajor = function() { + return this._engineVersionMajor; +} + +qx.Proto.getMinor = function() { + return this._engineVersionMinor; +} + +qx.Proto.getRevision = function() { + return this._engineVersionRevision; +} + +qx.Proto.getBuild = function() { + return this._engineVersionBuild; +} + +qx.Proto.getEmulation = function() { + return this._engineEmulation; +} + +qx.Proto.isMshtml = function() { + return this._engineNameMshtml; +} + +qx.Proto.isGecko = function() { + return this._engineNameGecko; +} + +qx.Proto.isOpera = function() { + return this._engineNameOpera; +} + +qx.Proto.isKhtml = function() { + return this._engineNameKhtml; +} + +qx.Proto.isWebkit = function() { + return this._engineNameWebkit; +} + +qx.Proto.isSafari2 = function() { + return this._engineNameWebkit && (this._engineVersion < 420); +} + +qx.Proto.isInQuirksMode = function() { + return this._engineQuirksMode; +} + +qx.Proto.getLocale = function() { + return this._browserLocale; +} + +qx.Proto.getLocaleVariant = function() { + return this._browserLocaleVariant; +} + +qx.Proto.getDefaultLocale = function() { + return this._defaultLocale; +} + +qx.Proto.usesDefaultLocale = function() { + return this._browserLocale === this._defaultLocale; +} + + + +/** + * Returns the CSS attribute name for box-sizing if supported. + * + * @return {String} the attribute name. + */ +qx.Proto.getEngineBoxSizingAttribute = function() { + return this._engineBoxSizingAttribute; +} + + +qx.Proto.getPlatform = function() { + return this._browserPlatform; +} + +/** + * Returns whether the client platform is a Windows machine. + * + * @return {Boolean} whether the client platform is a Windows. + */ +qx.Proto.runsOnWindows = function() { + return this._browserPlatformWindows; +} + +/** + * Returns whether the client platform is a Macintosh machine. + * + * @return {Boolean} whether the client platform is a Macintosh. + */ +qx.Proto.runsOnMacintosh = function() { + return this._browserPlatformMacintosh; +} + +/** + * Returns whether the client platform is a X11 powered machine. + * + * @return {Boolean} whether the client platform is a X11 powered machine. + */ +qx.Proto.runsOnUnix = function() { + return this._browserPlatformUnix; +} + +qx.Proto.supportsVml = function() { + return this._gfxVml; +} + +qx.Proto.supportsSvg = function() { + return this._gfxSvg; +} + +qx.Proto.usesSvgBuiltin = function() { + return this._gfxSvgBuiltin; +} + +qx.Proto.usesSvgPlugin = function() { + return this._gfxSvgPlugin; +} + +/** + * Retuns whether the Mozilla FireBug extension is installed and active + * http://www.getfirebug.com/ + * + * @return {Boolean} whether FireBug is active + */ + qx.Proto.isFireBugActive = function() { + return this._fireBugActive; + }; + +/** + * Returns whether the client supports the W3C property textContent of DOM element nodes. + * + * @return {Boolean} whether the client supports textContent. + */ +qx.Proto.supportsTextContent = function() { + return this._supportsTextContent; +} + +/** + * Returns whether the client supports the W3C property innerText of DOM element nodes. + * + * @return {Boolean} whether the client supports innerText. + */ +qx.Proto.supportsInnerText = function() { + return this._supportsInnerText; +} + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Init.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Init.js new file mode 100644 index 0000000000..e52a249272 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Init.js @@ -0,0 +1,329 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#require(qx.html.EventRegistration) +#optional(qx.component.init.InterfaceInitComponent) + +************************************************************************ */ + +/** + * Initialize qooxdoo. + * + * Attaches qooxdoo callbacks to the load events (onload, onunload, onbeforeunload) + * and initializes the qooxdoo application. The initializations starts automatically. + * + * Make shure you set the application to your application before the load event is fired: + * <pre>qx.core.Init.getInstance().setApplication(YourApplication)</pre> + */ +qx.OO.defineClass("qx.core.Init", qx.core.Target, +function() +{ + qx.core.Target.call(this, false); + + // Object Wrapper to Events (Needed for DOM-Events) + var o = this; + + /** + * private + * @param e {Object} event + */ + this.__onload = function(e) { return o._onload(e); } + /** + * private + * @param e {Object} event + */ + this.__onbeforeunload = function(e) { return o._onbeforeunload(e); } + /** + * private + * @param e {Object} event + */ + this.__onunload = function(e) { return o._onunload(e); } + + // Attach events + qx.html.EventRegistration.addEventListener(window, "load", this.__onload); + qx.html.EventRegistration.addEventListener(window, "beforeunload", this.__onbeforeunload); + qx.html.EventRegistration.addEventListener(window, "unload", this.__onunload); +}); + + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("component", "qx.component.init.InterfaceInitComponent"); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * Instance of the component initializer. + */ +qx.OO.addProperty({ name : "component", type : "object", instance : "qx.component.init.BasicInitComponent" }); + +/** + * Reference to the constructor of the main application. + * + * Set this before the onload event is fired. + */ +qx.OO.addProperty({ name : "application", type : "function" }); + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyApplication = function(propValue, propOldValue, propData) +{ + if (propValue) { + this._applicationInstance = new propValue; + } + + return true; +}; + + + + + + +/* +--------------------------------------------------------------------------- + INTERNAL PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * Returns an instance of the current qooxdoo Application + * + * @return {qx.component.AbstractApplication} instance of the current qooxdoo application + */ +qx.Proto.getApplicationInstance = function() +{ + if (!this.getApplication()) { + this.setApplication(qx.component.DummyApplication); + } + + return this._applicationInstance; +}; + + + + + + +/* +--------------------------------------------------------------------------- + COMPONENT BINDING +--------------------------------------------------------------------------- +*/ + +/** + * define the initialisation function + * Don't use this method directly. Use setApplication instead! + * + * @param vFunc {Function} callback function + */ +qx.Proto.defineInitialize = function(vFunc) { + this.getApplicationInstance().initialize = vFunc; +} + +/** + * define the main function + * Don't use this method directly. Use setApplication instead! + * + * @param vFunc {Function} callback function + */ +qx.Proto.defineMain = function(vFunc) { + this.getApplicationInstance().main = vFunc; +} + +/** + * define the finalize function + * Don't use this method directly. Use setApplication instead! + * + * @param vFunc {Function} callback function + */ +qx.Proto.defineFinalize = function(vFunc) { + this.getApplicationInstance().finalize = vFunc; +} + +/** + * define the close function + * Don't use this method directly. Use setApplication instead! + * + * @param vFunc {Function} callback function + */ +qx.Proto.defineClose = function(vFunc) { + this.getApplicationInstance().close = vFunc; +} + +/** + * define the terminate function + * Don't use this method directly. Use setApplication instead! + * + * @param vFunc {Function} callback function + */ +qx.Proto.defineTerminate = function(vFunc) { + this.getApplicationInstance().terminate = vFunc; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +/** + * load event handler + * + * @param e {Object} event + */ +qx.Proto._onload = function(e) +{ + this.debug("qooxdoo " + qx.core.Version.toString()); + + // Print out class information + this.debug("loaded " + qx.lang.Object.getLength(qx.OO.classes) + " classes"); + + // Print browser information + var cl = qx.core.Client.getInstance(); + this.debug("client: " + cl.getEngine() + "-" + cl.getMajor() + "." + + cl.getMinor() + "/" + cl.getPlatform() + "/" + cl.getLocale()); + + if (cl.isMshtml() && !cl.isInQuirksMode()) { + this.warn("Wrong box sizing: Please modify the document's DOCTYPE!"); + } + + // Init component from settings + this.setComponent(new qx.OO.classes[this.getSetting("component")](this)); + + // Send onload + return this.getComponent()._onload(e); +} + + +/** + * beforeunload event handler + * + * @param e {Object} event + */ +qx.Proto._onbeforeunload = function(e) +{ + // Send onbeforeunload event (can be cancelled) + return this.getComponent()._onbeforeunload(e); +} + + +/** + * unload event handler + * + * @param e {Object} event + */ +qx.Proto._onunload = function(e) +{ + // Send onunload event (last event) + this.getComponent()._onunload(e); + + // Dispose all qooxdoo objects + qx.core.Object.dispose(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Destructor + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Detach Events + qx.html.EventRegistration.removeEventListener(window, "load", this.__onload); + qx.html.EventRegistration.removeEventListener(window, "beforeunload", this.__onbeforeunload); + qx.html.EventRegistration.removeEventListener(window, "unload", this.__onunload); + + // Reset inline functions + this.__onload = this.__onbeforeunload = this.__onunload = null; + + if (this._applicationInstance) { + this._applicationInstance.dispose(); + this._applicationInstance = null; + } + + qx.core.Target.prototype.dispose.call(this); +} + + + + +/* +--------------------------------------------------------------------------- + DIRECT SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + +// Force direct creation +qx.Class.getInstance(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Object.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Object.js new file mode 100644 index 0000000000..d4bbb7ae51 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Object.js @@ -0,0 +1,597 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#load(qx.core.Init) +#resource(static:static) + +************************************************************************ */ + +/** + * The qooxdoo root class. All other classes are direct or indirect subclasses of this one. + * + * This class contains methods for: + * <ul> + * <li> object management (creation and destruction) </li> + * <li> logging & debugging </li> + * <li> generic getter/setter </li> + * <li> user data </li> + * <li> settings </li> + * <li> internationalization </li> + * </ul> + * + * @param vAutoDispose {Boolean ? true} whether the object should be automatically disposed + */ +qx.OO.defineClass("qx.core.Object", Object, +function(vAutoDispose) +{ + this._hashCode = qx.core.Object._availableHashCode++; + + if (vAutoDispose !== false) + { + this._dbKey = qx.core.Object._db.length; + qx.core.Object._db.push(this); + } +}); + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableDisposerDebug", false); + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +qx.Class._availableHashCode = 0; +qx.Class._db = []; +qx.Class._disposeAll = false; + + +/** + * Returns an unique identifier for the given object. If such an identifier + * does not yet exist, create it. + * + * @param o {Object} the Object to get the hashcode for + * @return {Integer} unique identifier for the given object + */ +qx.Class.toHashCode = function(o) +{ + if(o._hashCode != null) { + return o._hashCode; + } + + return o._hashCode = qx.core.Object._availableHashCode++; +} + + +/** + * Destructor. This method is called by qooxdoo on object destruction. + * + * Any class that holds resources like links to DOM nodes must overwrite + * this method and free these resources. + */ +qx.Class.dispose = function() +{ + // var logger = qx.log.Logger.getClassLogger(qx.core.Object); + // logger.debug("Disposing Application"); + + // var vStart = (new Date).valueOf(); + qx.core.Object._disposeAll = true; + var vObject; + + for (var i=qx.core.Object._db.length-1; i>=0; i--) + { + vObject = qx.core.Object._db[i]; + + if (vObject && vObject._disposed === false) + { + // logger.debug("Disposing: " + vObject); + vObject.dispose(); + } + } + + // logger.debug("Done in: " + ((new Date).valueOf() - vStart) + "ms"); +} + + +/** + * Summary of allocated objects + * + * @return {String} summary of allocated objects. + */ +qx.Class.summary = function() +{ + var vData = {}; + var vCounter = 0; + var vObject; + + for (var i=qx.core.Object._db.length-1; i>=0; i--) + { + vObject = qx.core.Object._db[i]; + + if (vObject && vObject._disposed === false) + { + if (vData[vObject.classname] == null) + { + vData[vObject.classname] = 1; + } + else + { + vData[vObject.classname]++; + } + + vCounter++; + } + } + + var vArrData = []; + + for (var vClassName in vData) { + vArrData.push({ classname : vClassName, number : vData[vClassName] }); + } + + vArrData.sort(function(a, b) { + return b.number - a.number; + }); + + var vMsg = "Summary: (" + vCounter + " Objects)\n\n"; + + for (var i=0; i<vArrData.length; i++) { + vMsg += vArrData[i].number + ": " + vArrData[i].classname + "\n"; + } + + alert(vMsg); +}; + +/** + * Enable or disable the Object. + * + * The actual semantic of this property depends on concrete subclass of qx.core.Object. + */ +qx.OO.addProperty({ name : "enabled", type : "boolean", defaultValue : true, getAlias : "isEnabled" }); + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +/** + * Returns a string represantation of the qooxdoo object. + * + * @return {String} string representation of the object + */ +qx.Proto.toString = function() +{ + if(this.classname) { + return "[object " + this.classname + "]"; + } + + return "[object Object]"; +} + + +/** + * Return unique hash code of object + * + * @return {Integer} unique hash code of the object + */ +qx.Proto.toHashCode = function() { + return this._hashCode; +} + + +/** + * Returns true if the object is disposed. + * + * @return {Boolean} wether the object has been disposed + */ +qx.Proto.getDisposed = function() { + return this._disposed; +} + + +/** + * Returns true if the object is disposed. + * + * @return {Boolean} wether the object has been disposed + */ +qx.Proto.isDisposed = function() { + return this._disposed; +} + + +/** + * Returns a settings from global setting definition + * + * @param vKey {String} the key + * @return {Object} value of the global setting + */ +qx.Proto.getSetting = function(vKey) { + return qx.Settings.getValueOfClass(this.classname, vKey); +} + + +/* +--------------------------------------------------------------------------- + I18N INTERFACE +--------------------------------------------------------------------------- +*/ + +/** + * Translate a message + * Mark the message for translation. + * @see qx.lang.String.format + * + * @param messageId {String} message id (may contain format strings) + * @param varargs {Object} variable number of argumes applied to the format string + * @return {qx.locale.LocalizedString} + */ +qx.Proto.tr = function(messageId, varargs) { + var nlsManager = qx.locale.Manager; + return nlsManager.tr.apply(nlsManager, arguments); +}; + + +/** + * Translate a plural message + * Mark the messages for translation. + * + * Depending on the third argument the plursl or the singular form is chosen. + * + * @see qx.lang.String.format + * + * @param singularMessageId {String} message id of the singular form (may contain format strings) + * @param pluralMessageId {String} message id of the plural form (may contain format strings) + * @param count {Integer} if greater than 1 the plural form otherwhise the singular form is returned. + * @param varargs {Object} variable number of argumes applied to the format string + * @return {qx.locale.LocalizedString) + */ +qx.Proto.trn = function(singularMessageId, pluralMessageId, count, varargs) { + var nlsManager = qx.locale.Manager; + return nlsManager.trn.apply(nlsManager, arguments); +}; + + +/** + * Mark the message for translation but return the original message. + * + * @param messageId {String} the message ID + * @return {String} messageId + */ +qx.Proto.marktr = function(messageId) { + var nlsManager = qx.locale.Manager; + return nlsManager.marktr.apply(nlsManager, arguments); +}; + +/* +--------------------------------------------------------------------------- + LOGGING INTERFACE +--------------------------------------------------------------------------- +*/ + +/** + * Returns the logger of this class. + * + * @return {qx.log.Logger} the logger of this class. + */ +qx.Proto.getLogger = function() { + return qx.log.Logger.getClassLogger(this.constructor); +} + + +/** + * Logs a debug message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.debug = function(msg, exc) { + this.getLogger().debug(msg, this._hashCode, exc); +} + + +/** + * Logs an info message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.info = function(msg, exc) { + this.getLogger().info(msg, this._hashCode, exc); +} + + +/** + * Logs a warning message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.warn = function(msg, exc) { + this.getLogger().warn(msg, this._hashCode, exc); +} + + +/** + * Logs an error message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.error = function(msg, exc) { + this.getLogger().error(msg, this._hashCode, exc); +} + + + + +/* +--------------------------------------------------------------------------- + COMMON SETTER/GETTER SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Sets multiple properties at once by using a property list + * + * @param propertyValues {Object} A hash of key-value pairs. + */ +qx.Proto.set = function(propertyValues) +{ + if (typeof propertyValues !== "object") { + throw new Error("Please use a valid hash of property key-values pairs."); + } + + for (var prop in propertyValues) + { + try + { + this[qx.OO.setter[prop]](propertyValues[prop]); + } + catch(ex) + { + this.error("Setter of property '" + prop + "' returned with an error", ex); + } + } + + return this; +} + +/** + * Gets multiple properties at once by using a property list + * + * @param propertyNames {String | Array | Map} list of the properties to get + * @param outputHint {String ? "array"} how should the values be returned. Possible values are "hash" and "array". +*/ +qx.Proto.get = function(propertyNames, outputHint) +{ + switch(typeof propertyNames) + { + case "string": + return this["get" + qx.lang.String.toFirstUp(propertyNames)](); + + case "object": + if (typeof propertyNames.length === "number") + { + if (outputHint == "hash") + { + var h = {}; + + propertyLength = propertyNames.length; + for (var i=0; i<propertyLength; i++) + { + try{ + h[propertyNames[i]] = this["get" + qx.lang.String.toFirstUp(propertyNames[i])](); + } + catch(ex) + { + throw new Error("Could not get a valid value from property: " + propertyNames[i] + "! Is the property existing? (" + ex + ")"); + } + } + + return h; + } + else + { + propertyLength = propertyNames.length; + for (var i=0; i<propertyLength; i++) + { + try{ + propertyNames[i] = this["get" + qx.lang.String.toFirstUp(propertyNames[i])](); + } + catch(ex) + { + throw new Error("Could not get a valid value from property: " + propertyNames[i] + "! Is the property existing? (" + ex + ")"); + } + } + + return propertyNames; + } + } + else + { + for (var i in propertyNames) { + propertyNames[i] = this["get" + qx.lang.String.toFirstUp(i)](); + } + + return propertyNames; + } + + default: + throw new Error("Please use a valid array, hash or string as parameter!"); + } +} + + + + + +/* +--------------------------------------------------------------------------- + USER DATA +--------------------------------------------------------------------------- +*/ + +/** + * Store user defined data inside the object. + * + * @param vKey {String} the key + * @param vValue {Object} the value of the user data + */ +qx.Proto.setUserData = function(vKey, vValue) +{ + if (!this._userData) { + this._userData = {}; + } + + this._userData[vKey] = vValue; +} + + +/** + * Load user defined data from the object + * + * @param vKey {String} the key + * @return {Object} the user data + */ +qx.Proto.getUserData = function(vKey) +{ + if (!this._userData) { + return null; + } + + return this._userData[vKey]; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto._disposed = false; + +/** + * Dispose this object + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Dispose user data + if (this._userData) + { + for(var vKey in this._userData) { + this._userData[vKey] = null; + } + + this._userData = null; + } + + // Finally cleanup properties + if (this._objectproperties) + { + var a = this._objectproperties.split(","); + var d = qx.OO.values; + + for (var i=0, l=a.length; i<l; i++) { + this[d[a[i]]] = null; + } + + this._objectproperties = null; + } + + if (this.getSetting("enableDisposerDebug")) + { + for (var vKey in this) + { + if (this[vKey] !== null && typeof this[vKey] === "object") + { + this.debug("Missing class implementation to dispose: " + vKey); + delete this[vKey]; + } + } + } + + /* + if (typeof CollectGarbage === "function") { + CollectGarbage(); + } + */ + + /* + // see bug #258. + if(this._dbKey != this._hashCode) { + console.log("Disposing wrong entry: " + this._dbKey + " vs. " + this._hashCode); + } + */ + + // Delete Entry from Object DB + if (this._dbKey != null) + { + if (qx.core.Object._disposeAll) + { + qx.core.Object._db[this._dbKey] = null; + this._hashCode = null; + this._dbKey = null; + } + else + { + delete qx.core.Object._db[this._dbKey]; + delete this._hashCode; + delete this._dbKey; + } + } + + // Mark as disposed + this._disposed = true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Target.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Target.js new file mode 100644 index 0000000000..a22d7a62bb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Target.js @@ -0,0 +1,297 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * This is the main constructor for all objects that need to be connected to qx.event.type.Event objects. + * + * In objects created with this constructor, you find functions to addEventListener or + * removeEventListener to or from the created object. Each event to connect to has a type in + * form of an identification string. This type could be the name of a regular dom event like "click" or + * something self-defined like "ready". + * + * @param vAutoDispose {Boolean ? true} wether the object should be disposed automatically by qooxdoo + */ +qx.OO.defineClass("qx.core.Target", qx.core.Object, +function(vAutoDispose) { + qx.core.Object.call(this, vAutoDispose); +}); + +/** + * @private + */ +qx.Class.EVENTPREFIX = "evt"; + + + + +/* +--------------------------------------------------------------------------- + EVENT CONNECTION +--------------------------------------------------------------------------- +*/ + +/** + * Add event listener to an object. + * + * @param vType {String} name of the event type + * @param vFunction {Function} event callback function + * @param vObject {Object ? window} reference to the 'this' variable inside the callback + */ +qx.Proto.addEventListener = function(vType, vFunction, vObject) +{ + if(this._disposed) { + return; + } + + if(typeof vFunction !== "function") { + throw new Error("qx.core.Target: addEventListener(" + vType + "): '" + vFunction + "' is not a function!"); + } + + // If this is the first event of given type, we need to create a subobject + // that contains all the actions that will be assigned to this type + if (this._listeners === undefined) { + this._listeners = {}; + } + + if(this._listeners[vType] === undefined) { + this._listeners[vType] = {}; + } + + // Create a special vKey string to allow identification of each bound action + var vKey = qx.core.Target.EVENTPREFIX + qx.core.Object.toHashCode(vFunction) + (vObject ? "_" + qx.core.Object.toHashCode(vObject) : ""); + + // Finally set up the listeners object + this._listeners[vType][vKey] = + { + handler : vFunction, + object : vObject + } +} + + +/** + * Remove event listener from object + * + * @param vType {String} name of the event type + * @param vFunction {Function} event callback function + * @param vObject {Object ? window} reference to the 'this' variable inside the callback + */ +qx.Proto.removeEventListener = function(vType, vFunction, vObject) +{ + if(this._disposed) { + return; + } + + var vListeners = this._listeners; + if (!vListeners || vListeners[vType] === undefined) { + return; + } + + if(typeof vFunction !== "function") { + throw new Error("qx.core.Target: removeEventListener(" + vType + "): '" + vFunction + "' is not a function!"); + } + + // Create a special vKey string to allow identification of each bound action + var vKey = qx.core.Target.EVENTPREFIX + qx.core.Object.toHashCode(vFunction) + (vObject ? "_" + qx.core.Object.toHashCode(vObject) : ""); + + // Delete object entry for this action + delete this._listeners[vType][vKey]; +} + + + +/* +--------------------------------------------------------------------------- + EVENT CONNECTION UTILITIES +--------------------------------------------------------------------------- +*/ + +/** + * Check if there are one or more listeners for an event type. + * + * @param vType {String} name of the event type + */ +qx.Proto.hasEventListeners = function(vType) { + return this._listeners && typeof this._listeners[vType] !== "undefined" && !qx.lang.Object.isEmpty(this._listeners[vType]); +} + + +/** + * Checks if the event is registered. If so it creates an event object and dispatches it. + * + * @param vType {String} name of the event type + */ +qx.Proto.createDispatchEvent = function(vType) +{ + if (this.hasEventListeners(vType)) { + this.dispatchEvent(new qx.event.type.Event(vType), true); + } +} + + +/** + * Checks if the event is registered. If so it creates an event object and dispatches it. + * + * @param vType {String} name of the event type + * @param vData {Object} user defined data attached to the event object + */ +qx.Proto.createDispatchDataEvent = function(vType, vData) +{ + if (this.hasEventListeners(vType)) { + this.dispatchEvent(new qx.event.type.DataEvent(vType, vData), true); + } +} + + + +/* +--------------------------------------------------------------------------- + EVENT DISPATCH +--------------------------------------------------------------------------- +*/ + +/** + * Dispatch an event + * + * @param vEvent {qx.event.type.Event} event to dispatch + * @param vEnableDispose {Boolean} wether the event object should be disposed after all event handlers run. + * @return {Boolean} wether the event default was prevented or not. Returns true, when the event was NOT prevented. + */ +qx.Proto.dispatchEvent = function(vEvent, vEnableDispose) +{ + // Ignore event if eventTarget is disposed + if(this.getDisposed() && this.getEnabled()) { + return; + } + + if (vEvent.getTarget() == null) { + vEvent.setTarget(this); + } + + if (vEvent.getCurrentTarget() == null) { + vEvent.setCurrentTarget(this); + } + + // Dispatch Event + this._dispatchEvent(vEvent, vEnableDispose); + + // Read default prevented + var defaultPrevented = vEvent._defaultPrevented; + + // enable dispose for event? + vEnableDispose && vEvent.dispose(); + + return !defaultPrevented; +} + + +/** + * Internal event dispatch method + * + * @param vEvent {qx.event.type.Event} event to dispatch + */ +qx.Proto._dispatchEvent = function(vEvent) +{ + var vListeners = this._listeners; + if (vListeners) + { + // Setup current target + vEvent.setCurrentTarget(this); + + // Shortcut for listener data + var vTypeListeners = vListeners[vEvent.getType()]; + + if(vTypeListeners) + { + var vFunction, vObject; + + // Handle all events for the specified type + for (var vHashCode in vTypeListeners) + { + // Shortcuts for handler and object + vFunction = vTypeListeners[vHashCode].handler; + vObject = vTypeListeners[vHashCode].object || this; + + // Call object function + try + { + vFunction.call(vObject, vEvent); + } + catch(ex) + { + this.error("Could not dispatch event of type \"" + vEvent.getType() + "\"", ex); + } + } + } + } + + // Bubble event to parents + // TODO: Move this to Parent or Widget? + if(vEvent.getBubbles() && !vEvent.getPropagationStopped() && this.getParent) + { + var vParent = this.getParent(); + if (vParent && !vParent.getDisposed() && vParent.getEnabled()) { + vParent._dispatchEvent(vEvent); + } + } +} + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Destructor. + */ +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + if (typeof this._listeners === "object") + { + for (var vType in this._listeners) + { + var listener = this._listeners[vType]; + for (var vKey in listener) + { + listener[vKey] = null; + } + + this._listeners[vType] = null; + } + } + + this._listeners = null; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Version.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Version.js new file mode 100755 index 0000000000..6c67f7b763 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/core/Version.js @@ -0,0 +1,107 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Framework version number information + * + * TODO: + * <ul> + * <li>Resemble naming of http://en.wikipedia.org/wiki/Software_version</li> + * <li>Compare/unify with qx.type.Version</li> + * <li>The following class variables are not yet included in the api viewer: + * <ul> + * <li>major</li> + * <li>minor</li> + * <li>revision (rename to: maintenance)</li> + * <li>state</li> + * <li>svn (rename to: revision)</li> + * </ul> + * </li> + * </ul> + */ +qx.OO.defineClass("qx.core.Version"); + +/** {Integer} Major version number */ +qx.Class.major = 0; + +/** {Integer} Minor version number */ +qx.Class.minor = 0; + +/** {Integer} Maintenance number */ +qx.Class.revision = 0; + +/** {String} Revision state */ +qx.Class.state = ""; + +/** {Integer} Subversion revision number */ +qx.Class.svn = 0; + +/** {String} Subversion folder e.g. trunk, release_0_6_3, ... */ +qx.Class.folder = ""; + +/** + * returns the qooxdoo version string + * + * @return {String} qooxdoo version string + */ +qx.Class.toString = function() +{ + var vClass = qx.core.Version; + return vClass.major + "." + vClass.minor + + (vClass.revision==0 ? "" : "." + vClass.revision) + + (vClass.state == "" ? "" : "-" + vClass.state) + + (vClass.svn==0 ? "" : " (r" + vClass.svn + ")") + + (vClass.folder == "" ? "" : " [" + vClass.folder + "]"); +}; + +/** + * Initialize class members + */ +qx.Class._init = function() +{ + var vClass = qx.core.Version; + + var vSplit = qx.VERSION.split(" "); + var vVersion = vSplit.shift(); + var vInfos = vSplit.join(" "); + + if (/([0-9]+)\.([0-9]+)(\.([0-9]))?(-([a-z]+))?/.test(vVersion)) + { + vClass.major = (RegExp.$1 != "" ? parseInt(RegExp.$1) : 0); + vClass.minor = (RegExp.$2 != "" ? parseInt(RegExp.$2) : 0); + vClass.revision = (RegExp.$4 != "" ? parseInt(RegExp.$4) : 0); + vClass.state = typeof RegExp.$6 == "string" ? RegExp.$6 : ""; + } + + if (/(\(r([0-9]+)\))?(\s\[(\w+)\])?/.test(vInfos)) + { + vClass.svn = (RegExp.$2 != "" ? parseInt(RegExp.$2) : 0); + vClass.folder = typeof RegExp.$4 == "string" ? RegExp.$4 : ""; + } +}; + +// Initialize at load time +qx.Class._init(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/Pollution.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/Pollution.js new file mode 100644 index 0000000000..73d17afe4c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/Pollution.js @@ -0,0 +1,290 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(dev) + +************************************************************************ */ + +/** + * Retrieve information about global namespace pollution + */ +qx.OO.defineClass("qx.dev.Pollution"); + +qx.Class.names = +{ + "window" : window, + "document" : document, + "body" : document.body +} + +qx.Class.ignore = +{ + "window" : + [ + // qooxdoo + "qx", + + // Java + "java", + "sun", + "Packages", + + // Firefox + "__firebug__", + "Components", + "controllers", + "sessionStorage", + "globalStorage", + + // Firefox extension: Firebug + "console", + + // IE + "event", + "offscreenBuffering", + "clipboardData", + "clientInformation", + "Option", + "Image", + "external", + "screenTop", + "screenLeft", + + // Standard + "length", + "window", + "document", + "location", + "navigator", + "netscape", + "parent", + "frames", + "top", + "scrollbars", + "name", + "scrollX", + "scrollY", + "self", + "screen", + "history", + "content", + "menubar", + "toolbar", + "locationbar", + "personalbar", + "statusbar", + "directories", + "closed", + "crypto", + "pkcs11", + "opener", + "status", + "defaultStatus", + "innerWidth", + "innerHeight", + "outerWidth", + "outerHeight", + "screenX", + "screenY", + "pageXOffset", + "pageYOffset", + "scrollMaxX", + "scrollMaxY", + "fullScreen", + "frameElement", + "XMLHttpRequest" + ], + + "document" : + [ + "domConfig", + "location", + "compatMode", + "implementation", + "defaultView", + "title", + "body", + "styleSheets", + "documentElement", + "nodeName", + "nodeType", + "firstChild", + "lastChild", + "doctype", + "images", + "applets", + "links", + "forms", + "anchors", + "cookie", + "embeds", + "plugins", + "designMode", + "childNodes" + ], + + "body" : + [ + "textContent", + "innerHTML", + "outerHTML", + "innerText", + "outerText", + "scopeName", + "parentElement", + "tagName", + "filters", + "contentEditable", + "document", + "currentStyle", + "isMultiLine", + "clientHeight", + "clientWidth", + + "lastChild", + "firstChild", + "offsetTop", + "offsetLeft", + "offsetWidth", + "offsetHeight", + "tabIndex", + "className", + "attributes", + "previousSibling", + "nextSibling", + "ownerDocument", + "localName", + "childNodes", + "parentNode", + "nodeType", + "nodeName", + "style", + + "scrollTop", + "scrollLeft", + "scrollWidth", + "scrollHeight" + ] +} + +qx.Class.consoleInfo = function(object) +{ + var msg = qx.dev.Pollution.getTextList(object); + + if (msg) { + alert("Global namespace is polluted by the following unknown objects:\n\n" + msg); + } else { + alert("Global namespace is not polluted by any unknown objects."); + } +} + +qx.Class.extract = function(object) +{ + var ext = []; + var ign = qx.dev.Pollution.ignore[object]; + var clientInfos = qx.core.Client.getInstance(); + + //IE offers a window[index] access to the frames of a window, i. e. + //for three frame, the window object will have attributes "0", "1" and "2" + if (clientInfos.isMshtml() && (object == "window")){ + ign = ign.slice(); + for (var frameIndex = 0; frameIndex < window.length; frameIndex++){ + ign.push("" + frameIndex); + } + } + + var obj = qx.dev.Pollution.names[object]; + + for (var key in obj) + { + try + { + //MS IE 7 crashes when doing typeof(window.external), catch here + if ( clientInfos.isMshtml() && (clientInfos.getMajor() >= 7) + && (object == "window") && (key == "external") ) { + continue; + } + + // Ignore null or undefined values + if (typeof obj[key] == "undefined" || obj[key] === null) { + continue; + } + + // Ignore native code + if (typeof obj[key] == "function" && obj[key].toString().indexOf("[native code]") != -1) { + continue; + } + + // Ignore if configured + if (qx.lang.Array.contains(ign, key)) { + continue; + } + + } + catch(ex) + { + continue; + } + + ext.push({ "key" : key, "value" : obj[key] }); + } + + return ext; +} + +qx.Class.getHtmlTable = function(object) +{ + var all = []; + + var rowStart = "<tr style='vertical-align:top'><td>"; + var cellSplit = "</td><td>"; + var rowEnd = "</td></tr>"; + + all.push("<table>"); + + var ext = this.extract(object); + + for (var i=0; i<ext.length; i++) { + all.push(rowStart + ext[i].key + cellSplit + ext[i].value + rowEnd); + } + + all.push("</table>"); + + return all.join(""); +} + +qx.Class.getTextList = function(object) +{ + var all = []; + + var cellSplit = ": "; + var rowEnd = "\n"; + + var ext = this.extract(object); + + for (var i=0; i<ext.length; i++) { + all.push(ext[i].key + cellSplit + ext[i].value + rowEnd); + } + + return all.join(""); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/TimeTracker.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/TimeTracker.js new file mode 100755 index 0000000000..15d09af537 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dev/TimeTracker.js @@ -0,0 +1,323 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(dev) +#embed(qx.icontheme/16/actions/dialog-ok.png) + +************************************************************************ */ + +qx.OO.defineClass("qx.dev.TimeTracker", qx.core.Object, +function() +{ + qx.core.Object.call(this); + + this._functions = qx.lang.Array.fromArguments(arguments); + + this.buttonSets(); +}); + +qx.dev.TimeTracker.compare = function(a, b) { + return a-b; +} + + + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.buttonSets = function() +{ + var btnLayout = new qx.ui.layout.HorizontalBoxLayout; + + btnLayout.setLocation(20, 48); + btnLayout.setSpacing(5); + + var loopLabel = new qx.ui.basic.Atom("Method Loops: "); + loopLabel.setAllowStretchY(false); + loopLabel.setVerticalAlign("middle"); + + var loopInput = new qx.ui.form.TextField("100"); + loopInput.setAllowStretchY(false); + loopInput.setWidth(50); + loopInput.setVerticalAlign("middle"); + + var repeatLabel = new qx.ui.basic.Atom("Repeat Number: "); + repeatLabel.setAllowStretchY(false); + repeatLabel.setVerticalAlign("middle"); + repeatLabel.setMarginLeft(30); + + var btnStart1 = new qx.ui.form.Button("Start 3x", "icon/16/actions/dialog-ok.png"); + var btnStart2 = new qx.ui.form.Button("Start 7x", "icon/16/actions/dialog-ok.png"); + var btnStart3 = new qx.ui.form.Button("Start 15x", "icon/16/actions/dialog-ok.png"); + var btnStart4 = new qx.ui.form.Button("Start 25x", "icon/16/actions/dialog-ok.png"); + + btnStart1.addEventListener("execute", function() { this.start(3, parseInt(loopInput.getValue())); }, this); + btnStart2.addEventListener("execute", function() { this.start(7, parseInt(loopInput.getValue())); }, this); + btnStart3.addEventListener("execute", function() { this.start(15, parseInt(loopInput.getValue())); }, this); + btnStart4.addEventListener("execute", function() { this.start(25, parseInt(loopInput.getValue())); }, this); + + var htmlOutput = this._output = new qx.ui.embed.HtmlEmbed(); + + htmlOutput.setHtml(""); + htmlOutput.setLocation(20, 78); + htmlOutput.setRight(335); + htmlOutput.setBottom(48); + htmlOutput.setBorder("1px solid black"); + htmlOutput.setBackgroundColor("white"); + htmlOutput.setPadding(10); + htmlOutput.setOverflow("auto"); + htmlOutput.addToDocument(); + + btnLayout.add(loopLabel, loopInput, repeatLabel, btnStart1, btnStart2, btnStart3, btnStart4); + btnLayout.addToDocument(); +} + +qx.Proto.start = function(vRounds, vLoops) +{ + var vFuncs = this._functions; + var vLength = vFuncs.length; + var vStart; + var vLocalTimes; + var vAllTimes = []; + var vHtmlMeasured = []; + var vHtmlResults = []; + var vCellWidth = Math.round(100 / (vLength+1)) + "%"; + + vHtmlMeasured.push("<h3>Measured Values</h3>"); + + vHtmlMeasured.push("<style type='text/css'>.output{border: 1px solid black; width:100%; margin-bottom: 20px } .output thead{ font-weight: bold; } .output td, .output th{ text-align:left; width: " + vCellWidth + "; } .output td{padding:4px}</style>"); + + vHtmlMeasured.push("<table class='output'>"); + + vHtmlMeasured.push("<thead>"); + + vHtmlMeasured.push("<tr><td> </td>"); + + for (var j=0; j<vLength; j++) { + vHtmlMeasured.push("<td>Method " + (j+1) + "</td>"); + } + + vHtmlMeasured.push("</thead><tbody>"); + + for (var i=0; i<vRounds; i++) + { + vLocalTimes = []; + + for (var j=0; j<vLength; j++) + { + vStart = (new Date).valueOf(); + + vFuncs[j](vLoops); + + vLocalTimes.push((new Date).valueOf()-vStart); + } + + vHtmlMeasured.push("<tr><th>Round " + i + "</th>"); + + for (var j=0; j<vLocalTimes.length; j++) { + vHtmlMeasured.push("<td>" + vLocalTimes[j] + "</td>"); + } + + vHtmlMeasured.push("</tr>"); + vAllTimes.push(vLocalTimes); + } + + vHtmlMeasured.push("</tbody></table>"); + + + + + + var vSum, vMeanValue, vMeanAll=[], vMeanMin=1e7, vMeanMax=0; + + for (var j=0; j<vLength; j++) + { + vSum = 0; + + for (var i=0; i<vRounds; i++) + { + vSum += vAllTimes[i][j]; + } + + vMeanValue = Math.round(vSum / vRounds); + + vMeanAll.push(vMeanValue); + + vMeanMin = Math.min(vMeanMin, vMeanValue); + vMeanMax = Math.max(vMeanMax, vMeanValue); + } + + + + var vMedian, vMedianValue, vMedianAll=[], vMedianMin=1e7, vMedianMax=0; + + for (var j=0; j<vLength; j++) + { + vMedian = []; + + for (var i=0; i<vRounds; i++) + { + vMedian.push(vAllTimes[i][j]); + } + + vMedian.sort(qx.dev.TimeTracker.compare); + vMedianValue = vMedian[Math.floor(vRounds / 2)].toString(); + + vMedianAll.push(vMedianValue); + + vMedianMin = Math.min(vMedianValue, vMedianMin); + vMedianMax = Math.max(vMedianValue, vMedianMax); + } + + + + + + vHtmlResults.push("<h3>Results Summary</h3>"); + + vHtmlResults.push("<table class='output'>"); + + vHtmlResults.push("<thead>"); + + vHtmlResults.push("<tr><td> </td>"); + + for (var j=0; j<vLength; j++) { + vHtmlResults.push("<td>Method " + (j+1) + "</td>"); + } + + vHtmlResults.push("</thead><tbody>"); + + + vHtmlResults.push("<tr>"); + + vHtmlResults.push("<th>Median</th>"); + + for (var j=0; j<vLength; j++) { + vHtmlResults.push("<td>" + vMedianAll[j] + "</td>"); + } + + vHtmlResults.push("</tr>"); + + + + vHtmlResults.push("<tr>"); + + vHtmlResults.push("<th>Median Factor</th>"); + + for (var j=0; j<vLength; j++) + { + vHtmlResults.push("<td>"); + vHtmlResults.push(vMedianMin > 0 ? Math.round(vMedianAll[j] / vMedianMin) : "1"); + vHtmlResults.push("x</td>"); + } + + vHtmlResults.push("</tr>"); + + + + vHtmlResults.push("<tr>"); + + vHtmlResults.push("<th>Mean</th>"); + + for (var j=0; j<vLength; j++) { + vHtmlResults.push("<td>" + vMeanAll[j] + "</td>"); + } + + vHtmlResults.push("</tr>"); + + + + vHtmlResults.push("<tr>"); + + vHtmlResults.push("<th>Mean Factor</th>"); + + for (var j=0; j<vLength; j++) + { + vHtmlResults.push("<td>"); + vHtmlResults.push(vMeanMin > 0 ? Math.round(vMeanAll[j] / vMeanMin) : 1); + vHtmlResults.push("x</td>"); + } + + vHtmlResults.push("</tr>"); + + + + vHtmlResults.push("<tr>"); + + vHtmlResults.push("<th>Winner</th>"); + + for (var j=0; j<vLength; j++) + { + vHtmlResults.push("<td>"); + + if (vMedianMin == vMedianAll[j] && vMeanMin == vMeanAll[j]) + { + vHtmlResults.push("BOTH"); + } + + else if (vMedianMin == vMedianAll[j]) + { + vHtmlResults.push("MEDIAN"); + } + + else if (vMeanMin == vMeanAll[j]) + { + vHtmlResults.push("MEAN"); + } + + vHtmlResults.push("</td>"); + } + + vHtmlResults.push("</tr>"); + + vHtmlResults.push("</tbody></table>"); + + this._output.setHtml(vHtmlResults.join("") + vHtmlMeasured.join("")); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._functions = null; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Element.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Element.js new file mode 100644 index 0000000000..cf570f74f8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Element.js @@ -0,0 +1,96 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/** + * Crossbrowser operations on DOM Elements + */ +qx.OO.defineClass("qx.dom.Element"); + + +/** + * Removes whitespace-only text node children + * + * @param vElement {Element} DOM element + */ +qx.Class.cleanWhitespace = function(vElement) +{ + for (var i=0; i<vElement.childNodes.length; i++) + { + var node = vElement.childNodes[i]; + + if (node.nodeType == qx.dom.Node.TEXT && !/\S/.test(node.nodeValue)) { + vElement.removeChild(node); + } + } +} + + +/** + * Checks if a element has no content + * + * @param vElement {Element} DOM element + */ +qx.Class.isEmpty = function(vElement) { + return vElement.innerHTML.match(/^\s*$/); +} + + +/** + * Returns the text content of a DOM element + * http://developer.mozilla.org/en/docs/DOM:element.textContent + * + * @param element {Element} DOM element + * @return {String} + */ + qx.Class.getTextContent = function(element) { + var text = ""; + var childNodes = element.childNodes; + for (var i=0; i<childNodes.length; i++) { + var node = childNodes[i]; + if (node.nodeType == qx.dom.Node.TEXT || node.nodeType == qx.dom.Node.CDATA_SECTION) { + text += node.nodeValue; + } + } + return text; +}; + + +/** + * Sets the textValue of the given DOM element (http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent). + * Wrapper for element.innerText and element.textContent. + * + * @param vElement {Element} DOM element + * @param sValue {String} the value + */ +qx.Class.setTextContent = function(vElement, sValue) {}; + +if (qx.core.Client.getInstance().supportsTextContent()) { + qx.Class.setTextContent = function(vElement, sValue) { + vElement.textContent = sValue; + }; +} else if (qx.core.Client.getInstance().supportsInnerText()) { + qx.Class.setTextContent = function(vElement, sValue) { + vElement.innerText = sValue; + }; +} else { + qx.Class.setTextContent = function(vElement, sValue) { + vElement.innerHTML = qx.html.String.escape(sValue); + }; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Node.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Node.js new file mode 100644 index 0000000000..aa747a099c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/Node.js @@ -0,0 +1,43 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Types of DOM nodes + */ +qx.OO.defineClass("qx.dom.Node", +{ + ELEMENT : 1, + ATTRIBUTE : 2, + TEXT : 3, + CDATA_SECTION : 4, + ENTITY_REFERENCE : 5, + ENTITY : 6, + PROCESSING_INSTRUCTION : 7, + COMMENT : 8, + DOCUMENT : 9, + DOCUMENT_TYPE : 10, + DOCUMENT_FRAGMENT : 11, + NOTATION : 12 +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/String.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/String.js new file mode 100644 index 0000000000..a5979c026b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/dom/String.js @@ -0,0 +1,109 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.lang.Object) + +************************************************************************ */ + +/** + * Generic escaping and unescaping of DOM strings. + * + * {@link qx.html.String} for (un)escaping of HTML strings. + * + * {@link qx.xml.String} for (un)escaping of XML strings. + */ +qx.OO.defineClass("qx.dom.String"); + + +/** + * generic escaping method + * + * @param str {String} string to escape + * @param charcodeToEntities {Map} entity to charcode map + */ +qx.Class.escapeEntities = function(str, charcodeToEntities) { + var result = []; + for (var i=0; i<str.length; i++) { + var chr = str.charAt(i); + var code = chr.charCodeAt(0) + if (charcodeToEntities[code]) { + var entity = "&" + charcodeToEntities[code] + ";"; + } else { + if (code > 0x7F) { + entity = "&#" + code + ";"; + } else { + entity = chr; + } + } + result.push(entity); + } + return result.join(""); +}; + + +/** + * generic unescaping method + * + * @param str {String} string to unescape + * @param entitiesToCharCode {Map} charcode to entity map + */ +qx.Class.unescapeEntities = function(str, entitiesToCharCode) { + return str.replace(/&[#\w]+;/gi, function(entity) { + var chr = entity; + var entity = entity.substring(1, entity.length-1); + var code = entitiesToCharCode[entity]; + if (code) { + chr = String.fromCharCode(code); + } else { + if (entity.charAt(0) == '#') { + if (entity.charAt(1).toUpperCase() == 'X') { + var code = entity.substring(2); + // match hex number + if (code.match(/^[0-9A-Fa-f]+$/gi)) { + chr = String.fromCharCode(parseInt("0x" + code)); + } + } else { + var code = entity.substring(1); + // match integer + if (code.match(/^\d+$/gi)) { + chr = String.fromCharCode(parseInt(code)); + } + } + } + } + return chr; + }); +}; + + +/** + * Remove HTML/XML tags from a string + * Example: + * <pre>qx.dom.String.stripTags("<h1>Hello</h1>") == "Hello"</pre> + * + * @param str {String} string containing tags + * @return {String} the string with stripped tags + */ +qx.Class.stripTags = function(str) { + return str.replace(/<\/?[^>]+>/gi, ""); +}; + + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/DragAndDropHandler.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/DragAndDropHandler.js new file mode 100644 index 0000000000..48b3cdf517 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/DragAndDropHandler.js @@ -0,0 +1,952 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_dragdrop) +#load(qx.html.ElementFromPoint) +#embed(qx.widgettheme/cursors/*) + +************************************************************************ */ + +/** + * This manager (singleton) manage all drag and drop handling of a qx.core.Init instance. + */ +qx.OO.defineClass("qx.event.handler.DragAndDropHandler", qx.manager.object.ObjectManager, +function() +{ + qx.core.Target.call(this); + + this._data = {}; + this._actions = {}; + this._cursors = {}; + + var vCursor; + for (var vAction in this._actionNames) + { + vCursor = this._cursors[vAction] = new qx.ui.basic.Image(this._cursorPath + vAction + "." + this._cursorFormat); + vCursor.setZIndex(1e8); + } +}); + +qx.OO.addProperty({ name : "sourceWidget", type : "object" }); +qx.OO.addProperty({ name : "destinationWidget", type : "object" }); +qx.OO.addProperty({ name : "cursor", type : "object" }); +qx.OO.addProperty({ name : "currentAction", type : "string" }); + +/** + * The default delta x of the cursor feedback. + * + * @see #setCursorPosition + */ +qx.OO.addProperty({ name : "defaultCursorDeltaX", type : "number", defaultValue : 5, allowNull : false }); + +/** + * The default delta y of the cursor feedback. + * + * @see #setCursorPosition + */ +qx.OO.addProperty({ name : "defaultCursorDeltaY", type : "number", defaultValue : 15, allowNull : false }); + +qx.Proto._actionNames = +{ + move : "move", + copy : "copy", + alias : "alias", + nodrop : "nodrop" +} + +qx.Proto._cursorPath = "widget/cursors/"; +qx.Proto._cursorFormat = "gif"; +qx.Proto._lastDestinationEvent = null; + + + + + +/* +--------------------------------------------------------------------------- + COMMON MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyDestinationWidget = function(propValue, propOldValue, propData) +{ + if (propValue) + { + propValue.dispatchEvent(new qx.event.type.DragEvent("dragdrop", this._lastDestinationEvent, propValue, this.getSourceWidget())); + this._lastDestinationEvent = null; + } + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DATA HANDLING +--------------------------------------------------------------------------- +*/ + +/*! +Add data of mimetype. + +#param vMimeType[String]: A valid mimetype +#param vData[Any]: Any value for the mimetype +*/ +qx.Proto.addData = function(vMimeType, vData) { + this._data[vMimeType] = vData; +} + +qx.Proto.getData = function(vMimeType) { + return this._data[vMimeType]; +} + +qx.Proto.clearData = function() { + this._data = {}; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + MIME TYPE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getDropDataTypes = function() +{ + var vDestination = this.getDestinationWidget(); + var vDropTypes = []; + + // If there is not any destination, simple return + if (!vDestination) { + return vDropTypes; + } + + // Search for matching mimetypes + var vDropDataTypes = vDestination.getDropDataTypes(); + + for (var i=0, l=vDropDataTypes.length; i<l; i++) { + if (vDropDataTypes[i] in this._data) { + vDropTypes.push(vDropDataTypes[i]); + } + } + + return vDropTypes; +} + + + + + + + +/* +--------------------------------------------------------------------------- + START DRAG +--------------------------------------------------------------------------- +*/ + +/*! +This needed be called from any "dragstart" event to really start drag session. +*/ +qx.Proto.startDrag = function() +{ + if (!this._dragCache) { + throw new Error("Invalid usage of startDrag. Missing dragInfo!"); + } + + // Update status flag + this._dragCache.dragHandlerActive = true; + + // Internal storage of source widget + this.setSourceWidget(this._dragCache.sourceWidget); + + // Add feedback widget + if (this._feedbackWidget) { + this._feedbackWidget.setVisibility(false); + + var doc = qx.ui.core.ClientDocument.getInstance(); + doc.add(this._feedbackWidget); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + FIRE IMPLEMENTATION FOR USER EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._fireUserEvents = function(fromWidget, toWidget, e) +{ + if (fromWidget && fromWidget != toWidget && fromWidget.hasEventListeners("dragout")) { + fromWidget.dispatchEvent(new qx.event.type.DragEvent("dragout", e, fromWidget, toWidget), true); + } + + if (toWidget) + { + if (fromWidget != toWidget && toWidget.hasEventListeners("dragover")) { + toWidget.dispatchEvent(new qx.event.type.DragEvent("dragover", e, toWidget, fromWidget), true); + } + + if (toWidget.hasEventListeners("dragmove")) { + toWidget.dispatchEvent(new qx.event.type.DragEvent("dragmove", e, toWidget, null), true); + } + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + HANDLER FOR MOUSE EVENTS +--------------------------------------------------------------------------- +*/ + +/*! +This wraps the mouse events to custom handlers. +*/ +qx.Proto.handleMouseEvent = function(e) +{ + switch (e.getType()) + { + case "mousedown": + return this._handleMouseDown(e); + + case "mouseup": + return this._handleMouseUp(e); + + case "mousemove": + return this._handleMouseMove(e); + } +} + +/*! +This starts the core drag and drop session. + +To really get drag and drop working you need to define +a function which you attach to "dragstart"-event, which +invokes at least this.startDrag() +*/ +qx.Proto._handleMouseDown = function(e) +{ + if (e.getDefaultPrevented() || ! e.isLeftButtonPressed()) { + return; + } + + // Store initial dragCache + this._dragCache = + { + startScreenX : e.getScreenX(), + startScreenY : e.getScreenY(), + + pageX : e.getPageX(), + pageY : e.getPageY(), + + sourceWidget : e.getTarget(), + sourceTopLevel : e.getTarget().getTopLevelWidget(), + + dragHandlerActive : false, + hasFiredDragStart : false + } +} + + +/*! +Handler for mouse move events +*/ + +qx.Proto._handleMouseMove = function(e) +{ + // Return if dragCache was not filled before + if (!this._dragCache) { + return; + } + + /* + Default handling if drag handler is activated + */ + + if (this._dragCache.dragHandlerActive) + { + // Update page coordinates + this._dragCache.pageX = e.getPageX(); + this._dragCache.pageY = e.getPageY(); + + // Get current target + var currentDropTarget = this.getDropTarget(e); + + // Update action + this.setCurrentAction(currentDropTarget ? this._evalNewAction(e.isShiftPressed(), e.isCtrlPressed(), e.isAltPressed()) : null); + + // Fire user events + this._fireUserEvents(this._dragCache.currentDropWidget, currentDropTarget, e); + + // Store current widget + this._dragCache.currentDropWidget = currentDropTarget; + + // Update cursor icon + this._renderCursor(); + + // Update user feedback + this._renderFeedbackWidget(); + } + + /* + Initial activation and fire of dragstart + */ + else if (!this._dragCache.hasFiredDragStart) + { + if (Math.abs(e.getScreenX() - this._dragCache.startScreenX) > 5 || Math.abs(e.getScreenY() - this._dragCache.startScreenY) > 5) + { + // Fire dragstart event to finally allow the above if to handle next events + this._dragCache.sourceWidget.dispatchEvent(new qx.event.type.DragEvent("dragstart", e, this._dragCache.sourceWidget), true); + + // Update status flag + this._dragCache.hasFiredDragStart = true; + + // Look if handler become active + if (this._dragCache.dragHandlerActive) + { + // Fire first user events + this._fireUserEvents(this._dragCache.currentDropWidget, this._dragCache.sourceWidget, e); + + // Update status flags + this._dragCache.currentDropWidget = this._dragCache.sourceWidget; + + // Activate capture for clientDocument + qx.ui.core.ClientDocument.getInstance().setCapture(true); + } + } + } +} + +/*! +Handle mouse up event. Normally this finalize the drag and drop event. +*/ +qx.Proto._handleMouseUp = function(e) +{ + // Return if dragCache was not filled before + if (!this._dragCache) { + return; + } + + if (this._dragCache.dragHandlerActive) + { + this._endDrag(this.getDropTarget(e), e); + } + else + { + // Clear drag cache + this._dragCache = null; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + HANDLER FOR KEY EVENTS +--------------------------------------------------------------------------- +*/ + +/*! +This wraps the key events to custom handlers. +*/ +qx.Proto.handleKeyEvent = function(e) +{ + if (!this._dragCache) { + return; + } + + switch (e.getType()) + { + case "keydown": + this._handleKeyDown(e); + return; + + case "keyup": + this._handleKeyUp(e); + return; + } +} + +qx.Proto._handleKeyDown = function(e) +{ + // Stop Drag on Escape + if (e.getKeyIdentifier() == "Escape") + { + this.cancelDrag(e); + } + + // Update cursor and action on press of modifier keys + else if (this.getCurrentAction() != null) + { + // TODO this doesn't work in WebKit because WebKit doesn't fire keyevents for modifier keys + switch(e.getKeyIdentifier()) + { + case "Shift": + case "Control": + case "Alt": + this.setAction(this._evalNewAction(e.isShiftPressed(), e.isCtrlPressed(), e.isAltPressed())); + this._renderCursor(); + + e.preventDefault(); + } + } +} + +qx.Proto._handleKeyUp = function(e) +{ + // TODO this doesn't work in WebKit because WebKit doesn't fire keyevents for modifier keys + var bShiftPressed = e.getKeyIdentifier() == "Shift"; + var bCtrlPressed = e.getKeyIdentifier() == "Control"; + var bAltPressed = e.getKeyIdentifier() == "Alt"; + + if (bShiftPressed || bCtrlPressed || bAltPressed) + { + if (this.getCurrentAction() != null) + { + this.setAction(this._evalNewAction(!bShiftPressed && e.isShiftPressed(), ! bCtrlPressed && e.isCtrlPressed(), !bAltPressed && e.isAltPressed())); + this._renderCursor(); + + e.preventDefault(); + } + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + IMPLEMENTATION OF DRAG&DROP SESSION FINALISATION +--------------------------------------------------------------------------- +*/ + +/*! + Cancel current drag and drop session +*/ +qx.Proto.cancelDrag = function(e) { + // Return if dragCache was not filled before + if (!this._dragCache) { + return; + } + + if (this._dragCache.dragHandlerActive) + { + this._endDrag(null, e); + } + else + { + // Clear drag cache + this._dragCache = null; + } +} + +qx.Proto.globalCancelDrag = function() +{ + if (this._dragCache && this._dragCache.dragHandlerActive) { + this._endDragCore(); + } +} + +/*! + This will be called to the end of each drag and drop session +*/ +qx.Proto._endDrag = function(currentDestinationWidget, e) +{ + // Use given destination widget + if (currentDestinationWidget) + { + this._lastDestinationEvent = e; + this.setDestinationWidget(currentDestinationWidget); + } + + // Dispatch dragend event + this.getSourceWidget().dispatchEvent(new qx.event.type.DragEvent("dragend", e, this.getSourceWidget(), currentDestinationWidget), true); + + // Fire dragout event + this._fireUserEvents(this._dragCache && this._dragCache.currentDropWidget, null, e); + + // Call helper + this._endDragCore(); +} + +qx.Proto._endDragCore = function() +{ + // Cleanup feedback widget + if (this._feedbackWidget) { + var doc = qx.ui.core.ClientDocument.getInstance(); + doc.remove(this._feedbackWidget); + + if (this._feedbackAutoDispose) { + this._feedbackWidget.dispose(); + } + + this._feedbackWidget = null; + } + + // Remove cursor + var oldCursor = this.getCursor(); + if (oldCursor) + { + oldCursor._style.display = "none"; + this.forceCursor(null); + } + + this._cursorDeltaX = null; + this._cursorDeltaY = null; + + // Reset drag cache for next drag and drop session + if (this._dragCache) + { + this._dragCache.currentDropWidget = null; + this._dragCache = null; + } + + // Deactivate capture for clientDocument + qx.ui.core.ClientDocument.getInstance().setCapture(false); + + // Cleanup data and actions + this.clearData(); + this.clearActions(); + + // Cleanup widgets + this.setSourceWidget(null); + this.setDestinationWidget(null); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + IMPLEMENTATION OF CURSOR UPDATES +--------------------------------------------------------------------------- +*/ + +/** + * Sets the position of the cursor feedback (the icon showing whether dropping + * is allowed at the current position and which action a drop will do). + * + * @param deltaX {int} The number of pixels the top-left corner of the + * cursor feedback should be away from the mouse cursor in x direction. + * @param deltaY {int} The number of pixels the top-left corner of the + * cursor feedback should be away from the mouse cursor in y direction. + */ +qx.Proto.setCursorPosition = function(deltaX, deltaY) { + this._cursorDeltaX = deltaX; + this._cursorDeltaY = deltaY; +}; + +/*! + Select and setup the current used cursor +*/ +qx.Proto._renderCursor = function() +{ + var vNewCursor; + var vOldCursor = this.getCursor(); + + switch(this.getCurrentAction()) + { + case this._actionNames.move: + vNewCursor = this._cursors.move; + break; + + case this._actionNames.copy: + vNewCursor = this._cursors.copy; + break; + + case this._actionNames.alias: + vNewCursor = this._cursors.alias; + break; + + default: + vNewCursor = this._cursors.nodrop; + } + + // Hide old cursor + if (vNewCursor != vOldCursor && vOldCursor != null) { + vOldCursor._style.display = "none"; + } + + // Ensure that the cursor is created + if (!vNewCursor._initialLayoutDone) + { + qx.ui.core.ClientDocument.getInstance().add(vNewCursor); + qx.ui.core.Widget.flushGlobalQueues(); + } + + // Apply position with runtime style (fastest qooxdoo method) + vNewCursor._applyRuntimeLeft(this._dragCache.pageX + + ((this._cursorDeltaX != null) ? this._cursorDeltaX : this.getDefaultCursorDeltaX())); + vNewCursor._applyRuntimeTop(this._dragCache.pageY + + ((this._cursorDeltaY != null) ? this._cursorDeltaY : this.getDefaultCursorDeltaY())); + + // Finally show new cursor + if (vNewCursor != vOldCursor) { + vNewCursor._style.display = ""; + } + + // Store new cursor + this.forceCursor(vNewCursor); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + IMPLEMENTATION OF DROP TARGET VALIDATION +--------------------------------------------------------------------------- +*/ + +qx.Proto.supportsDrop = function(vWidget) +{ + var vTypes = vWidget.getDropDataTypes(); + + if (!vTypes) { + return false; + } + + for (var i=0; i<vTypes.length; i++) + { + if (vTypes[i] in this._data) { + return true; + } + } + + return false; +} + +/*! +#param e[qx.event.type.MouseEvent]: Current MouseEvent for dragdrop action +*/ +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto.getDropTarget = function(e) + { + var vCurrent = e.getTarget(); + + // work around gecko bug (all other browsers are correct) + // clicking on a free space and drag prohibit the get of + // a valid event target. The target is always the element + // which was the one with the mousedown event before. + if (vCurrent == this._dragCache.sourceWidget) + { + // vCurrent = qx.event.handler.EventHandler.getTargetObject(qx.html.ElementFromPoint.getElementFromPoint(e.getPageX(), e.getPageY())); + + // this is around 8-12 times faster as the above method + vCurrent = this._dragCache.sourceTopLevel.getWidgetFromPoint(e.getPageX(), e.getPageY()); + } + else + { + vCurrent = qx.event.handler.EventHandler.getTargetObject(null, vCurrent); + } + + while (vCurrent != null && vCurrent != this._dragCache.sourceWidget) + { + if (!vCurrent.supportsDrop(this._dragCache)) { + return null; + } + + if (this.supportsDrop(vCurrent)) { + return vCurrent; + } + + vCurrent = vCurrent.getParent(); + } + + return null; + } +} +else +{ + qx.Proto.getDropTarget = function(e) + { + var vCurrent = e.getTarget(); + + while (vCurrent != null) + { + if (!vCurrent.supportsDrop(this._dragCache)) { + return null; + } + + if (this.supportsDrop(vCurrent)) { + return vCurrent; + } + + vCurrent = vCurrent.getParent(); + } + + return null; + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + ACTION HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addAction = function(vAction, vForce) +{ + this._actions[vAction] = true; + + // Defaults to first added action + if (vForce || this.getCurrentAction() == null) { + this.setCurrentAction(vAction); + } +} + +qx.Proto.clearActions = function() +{ + this._actions = {}; + this.setCurrentAction(null); +} + +qx.Proto.removeAction = function(vAction) +{ + delete this._actions[vAction]; + + // Reset current action on remove + if (this.getCurrentAction() == vAction) { + this.setCurrentAction(null); + } +} + +qx.Proto.setAction = function(vAction) +{ + if (vAction != null && !(vAction in this._actions)) { + this.addAction(vAction, true); + } + else + { + this.setCurrentAction(vAction); + } +} + +qx.Proto._evalNewAction = function(vKeyShift, vKeyCtrl, vKeyAlt) +{ + if (vKeyShift && vKeyCtrl && this._actionNames.alias in this._actions) + { + return this._actionNames.alias; + } + else if (vKeyShift && vKeyAlt && this._actionNames.copy in this._actions) + { + return this._actionNames.copy; + } + else if (vKeyShift && this._actionNames.move in this._actions) + { + return this._actionNames.move; + } + else if (vKeyAlt && this._actionNames.alias in this._actions) + { + return this._actionNames.alias; + } + else if (vKeyCtrl && this._actionNames.copy in this._actions) + { + return this._actionNames.copy; + } + else + { + // Return the first action found + for (var vAction in this._actions) { + return vAction; + } + } + + return null; +} + + + + + + +/* +--------------------------------------------------------------------------- + USER FEEDBACK SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Sets the widget to show as feedback for the user. This widget should + * represent the object(s) the user is dragging. + * + * @param widget {qx.ui.core.Widget} the feedback widget. + * @param deltaX {int ? 10} the number of pixels the top-left corner of the widget + * should be away from the mouse cursor in x direction. + * @param deltaY {int ? 10} the number of pixels the top-left corner of the widget + * should be away from the mouse cursor in y direction. + * @param autoDisposeWidget {boolean} whether the widget should be disposed when + * dragging is finished or cancelled. + */ +qx.Proto.setFeedbackWidget = function(widget, deltaX, deltaY, autoDisposeWidget) { + this._feedbackWidget = widget; + this._feedbackDeltaX = (deltaX != null) ? deltaX : 10; + this._feedbackDeltaY = (deltaY != null) ? deltaY : 10; + this._feedbackAutoDispose = autoDisposeWidget ? true : false; +}; + +/** + * Renders the user feedback widget at the correct location. + */ +qx.Proto._renderFeedbackWidget = function() { + if (this._feedbackWidget) { + this._feedbackWidget.setVisibility(true); + + // Apply position with runtime style (fastest qooxdoo method) + this._feedbackWidget._applyRuntimeLeft(this._dragCache.pageX + this._feedbackDeltaX); + this._feedbackWidget._applyRuntimeTop(this._dragCache.pageY + this._feedbackDeltaY); + } +}; + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Reset drag cache for next drag and drop session + if (this._dragCache) + { + this._dragCache.currentDropWidget = null; + this._dragCache = null; + } + + // Cleanup data and actions + this._data = null; + this._actions = null; + this._actionNames = null; + + this._lastDestinationEvent = null; + + if (this._cursors) + { + if (this._cursors.move) + { + this._cursors.move.dispose(); + delete this._cursors.move; + } + + if (this._cursors.copy) + { + this._cursors.copy.dispose(); + delete this._cursors.copy; + } + + if (this._cursors.alias) + { + this._cursors.alias.dispose(); + delete this._cursors.alias; + } + + if (this._cursors.nodrop) + { + this._cursors.nodrop.dispose(); + delete this._cursors.nodrop; + } + + this._cursors = null; + } + + return qx.manager.object.ObjectManager.prototype.dispose.call(this); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/EventHandler.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/EventHandler.js new file mode 100644 index 0000000000..858f8d6096 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/EventHandler.js @@ -0,0 +1,1182 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.event.type.KeyEvent) +#require(qx.event.handler.KeyEventHandler) +#optional(qx.event.handler.DragAndDropHandler) +#optional(qx.manager.object.MenuManager) +#optional(qx.event.handler.FocusHandler) +#optional(qx.manager.object.PopupManager) +#optional(qx.manager.object.ToolTipManager) + +************************************************************************ */ + +/** + * This manager registers and manage all incoming key and mouse events. + * + * @event error {qx.event.type.DataEvent} Fired when an exception was thrown + * when dispatching the event to the listeners. The event's property + * "data" holds the exception. + */ +qx.OO.defineClass("qx.event.handler.EventHandler", qx.core.Target, +function() +{ + qx.core.Target.call(this); + + // Object Wrapper to Events (Needed for DOM-Events) + var o = this; + + // User Events + this.__onmouseevent = function(e) { return o._onmouseevent(e); }; + this.__ondragevent = function(e) { return o._ondragevent(e); }; + this.__onselectevent = function(e) { return o._onselectevent(e); }; + + // Window Events + this.__onwindowblur = function(e) { return o._onwindowblur(e); }; + this.__onwindowfocus = function(e) { return o._onwindowfocus(e); }; + this.__onwindowresize = function(e) { return o._onwindowresize(e); }; + + // Init Command Interface + this._commands = {}; +}); + + + + + + +qx.OO.addProperty({ name : "allowClientContextMenu", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "allowClientSelectAll", type : "boolean", defaultValue : false }); + +qx.OO.addProperty({ name : "captureWidget", type : "object", instance : "qx.ui.core.Widget", allowNull : true }); +qx.OO.addProperty({ name : "focusRoot", type : "object", instance : "qx.ui.core.Parent", allowNull : true }); + + + + + + +qx.Class.mouseEventTypes = [ "mouseover", "mousemove", "mouseout", "mousedown", "mouseup", "click", "dblclick", "contextmenu", qx.core.Client.getInstance().isMshtml() ? "mousewheel" : "DOMMouseScroll" ]; +qx.Class.keyEventTypes = [ "keydown", "keypress", "keyup" ]; + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Class.dragEventTypes = [ "dragdrop", "dragover", "dragenter", "dragexit", "draggesture" ]; +} +else if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Class.dragEventTypes = [ "dragend", "dragover", "dragstart", "drag", "dragenter", "dragleave" ]; +} +else +{ + qx.Class.dragEventTypes = [ "dragstart", "dragdrop", "dragover", "drag", "dragleave", "dragenter", "dragexit", "draggesture" ]; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + STATE FLAGS +--------------------------------------------------------------------------- +*/ + +qx.Proto._lastMouseEventType = null; +qx.Proto._lastMouseDown = false; +qx.Proto._lastMouseEventDate = 0; + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCaptureWidget = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.setCapture(false); + } + + if (propValue) { + propValue.setCapture(true); + } + + return true; +} + +qx.Proto._modifyFocusRoot = function(propValue, propOldValue, propData) +{ + // this.debug("FocusRoot: " + propValue + "(from:" + propOldValue + ")"); + + if (propOldValue) { + propOldValue.setFocusedChild(null); + } + + if (propValue) + { + if (propValue.getFocusedChild() == null) { + propValue.setFocusedChild(propValue); + } + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + COMMAND INTERFACE +--------------------------------------------------------------------------- +*/ + +qx.Proto.addCommand = function(vCommand) { + this._commands[vCommand.toHashCode()] = vCommand; +} + +qx.Proto.removeCommand = function(vCommand) { + delete this._commands[vCommand.toHashCode()]; +} + +qx.Proto._checkKeyEventMatch = function(e) +{ + var vCommand; + + for (var vHash in this._commands) + { + vCommand = this._commands[vHash]; + + if (vCommand.getEnabled() && vCommand._matchesKeyEvent(e)) + { + // allow the user to stop the event + // through the execute event. + if (!vCommand.execute(e.getTarget())) { + e.preventDefault(); + } + + break; + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-MAPPING +--------------------------------------------------------------------------- +*/ + +qx.Proto.attachEvents = function() +{ + // Register dom events + this.attachEventTypes(qx.event.handler.EventHandler.mouseEventTypes, this.__onmouseevent); + this.attachEventTypes(qx.event.handler.EventHandler.dragEventTypes, this.__ondragevent); + + // Unregister separate handler events + qx.event.handler.KeyEventHandler.getInstance()._attachEvents(); + + // Register window events + qx.html.EventRegistration.addEventListener(window, "blur", this.__onwindowblur); + qx.html.EventRegistration.addEventListener(window, "focus", this.__onwindowfocus); + qx.html.EventRegistration.addEventListener(window, "resize", this.__onwindowresize); + + // Register selection events + document.body.onselect = document.onselectstart = document.onselectionchange = this.__onselectevent; +} + +qx.Proto.detachEvents = function() +{ + // Unregister dom events + this.detachEventTypes(qx.event.handler.EventHandler.mouseEventTypes, this.__onmouseevent); + this.detachEventTypes(qx.event.handler.EventHandler.dragEventTypes, this.__ondragevent); + + // Unregister separate handler events + qx.event.handler.KeyEventHandler.getInstance()._detachEvents(); + + // Unregister window events + qx.html.EventRegistration.removeEventListener(window, "blur", this.__onwindowblur); + qx.html.EventRegistration.removeEventListener(window, "focus", this.__onwindowfocus); + qx.html.EventRegistration.removeEventListener(window, "resize", this.__onwindowresize); + + // Unregister selection events + document.body.onselect = document.onselectstart = document.onselectionchange = null; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-MAPPING HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.attachEventTypes = function(vEventTypes, vFunctionPointer) +{ + try + { + // Gecko is a bit buggy to handle key events on document if not previously focused + // I think they will fix this sometimes, and we should add a version check here. + // Internet Explorer has problems to use 'window', so there we use the 'body' element + // as previously. + var el = qx.core.Client.getInstance().isGecko() ? window : document.body; + + for (var i=0, l=vEventTypes.length; i<l; i++) { + qx.html.EventRegistration.addEventListener(el, vEventTypes[i], vFunctionPointer); + } + } + catch(ex) + { + throw new Error("qx.event.handler.EventHandler: Failed to attach window event types: " + vEventTypes + ": " + ex); + } +} + +qx.Proto.detachEventTypes = function(vEventTypes, vFunctionPointer) +{ + try + { + var el = qx.core.Client.getInstance().isGecko() ? window : document.body; + + for (var i=0, l=vEventTypes.length; i<l; i++) { + qx.html.EventRegistration.removeEventListener(el, vEventTypes[i], vFunctionPointer); + } + } + catch(ex) + { + throw new Error("qx.event.handler.EventHandler: Failed to detach window event types: " + vEventTypes + ": " + ex); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + HELPER METHODS +--------------------------------------------------------------------------- +*/ + +// BUG: http://xscroll.mozdev.org/ +// If your Mozilla was built with an option `--enable-default-toolkit=gtk2', +// it can not return the correct event target for DOMMouseScroll. + +qx.Class.getOriginalTargetObject = function(vNode) +{ + // Events on the HTML element, when using absolute locations which + // are outside the HTML element. Opera does not seem to fire events + // on the HTML element. + if (vNode == document.documentElement) { + vNode = document.body; + } + + // Walk up the tree and search for an qx.ui.core.Widget + while(vNode != null && vNode.qx_Widget == null) + { + try { + vNode = vNode.parentNode; + } + catch(vDomEvent) + { + vNode = null; + } + } + + return vNode ? vNode.qx_Widget : null; +} + +if (qx.core.Client.getInstance().isWebkit()) +{ + /** + * extract the target node from a DOM event + * http://www.quirksmode.org/js/events_properties.html + * + * @param vDomEvent {Event} + * @return {Element} the target node + */ + qx.Class.getDomTarget = function(vDomEvent) + { + var vNode = vDomEvent.target || vDomEvent.srcElement; + + // Safari takes text nodes as targets for events + if (vNode && (vNode.nodeType == qx.dom.Node.TEXT)) { + vNode = vNode.parentNode; + } + + return vNode; + }; +} +else if (qx.core.Client.getInstance().isMshtml()) +{ + /** + * extract the target node from a DOM event + * http://www.quirksmode.org/js/events_properties.html + * + * @param vDomEvent {Event} + * @return {Element} the target node + */ + qx.Class.getDomTarget = function(vDomEvent) { + return vDomEvent.target || vDomEvent.srcElement; + }; +} +else +{ + /** + * extract the target node from a DOM event + * http://www.quirksmode.org/js/events_properties.html + * + * @param vDomEvent {Event} + * @return {Element} the target node + */ + qx.Class.getDomTarget = function(vDomEvent) { + return vDomEvent.target; + }; +} + + +qx.Class.getOriginalTargetObjectFromEvent = function(vDomEvent, vWindow) +{ + var vNode = qx.event.handler.EventHandler.getDomTarget(vDomEvent); + + // Especially to fix key events. + // 'vWindow' is the window reference then + if (vWindow) + { + var vDocument = vWindow.document; + + if (vNode == vWindow || vNode == vDocument || vNode == vDocument.documentElement || vNode == vDocument.body) { + return vDocument.body.qx_Widget; + } + } + + return qx.event.handler.EventHandler.getOriginalTargetObject(vNode); +} + +qx.Class.getRelatedOriginalTargetObjectFromEvent = function(vDomEvent) { + return qx.event.handler.EventHandler.getOriginalTargetObject(vDomEvent.relatedTarget || (vDomEvent.type == "mouseover" ? vDomEvent.fromElement : vDomEvent.toElement)); +} + + + + + + + +qx.Class.getTargetObject = function(vNode, vObject, allowDisabled) +{ + if (!vObject) + { + var vObject = qx.event.handler.EventHandler.getOriginalTargetObject(vNode); + + if (!vObject) { + return null; + } + } + + // Search parent tree + while(vObject) + { + // Break if current object is disabled - + // event should be ignored then. + if (!allowDisabled && !vObject.getEnabled()) { + return null; + } + + // If object is anonymous, search for + // first parent which is not anonymous + // and not disabled + if (!vObject.getAnonymous()) { + break; + } + + vObject = vObject.getParent(); + } + + return vObject; +}; + + +qx.Class.getTargetObjectFromEvent = function(vDomEvent) { + return qx.event.handler.EventHandler.getTargetObject(qx.event.handler.EventHandler.getDomTarget(vDomEvent)); +}; + + +qx.Class.getRelatedTargetObjectFromEvent = function(vDomEvent) { + var target = vDomEvent.relatedTarget; + if (!target) { + if (vDomEvent.type == "mouseover") { + target = vDomEvent.fromElement + } else { + target = vDomEvent.toElement + } + } + return qx.event.handler.EventHandler.getTargetObject(target); +}; + + +/** + * stops further propagation of the event + * + * @param vDomEvent {Element} DOM event object + */ +qx.Class.stopDomEvent = function(vDomEvent) {}; +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Class.stopDomEvent = function(vDomEvent) { + vDomEvent.returnValue = false; + } +} +else +{ + qx.Class.stopDomEvent = function(vDomEvent) + { + vDomEvent.preventDefault(); + vDomEvent.returnValue = false; + } +}; + + + + + + + +/* +--------------------------------------------------------------------------- + KEY EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeyevent_post = function(vDomEvent, vType, vKeyCode, vCharCode, vKeyIdentifier) +{ + var vDomTarget = qx.event.handler.EventHandler.getDomTarget(vDomEvent); + + + // Find current active qooxdoo object + var vFocusRoot = this.getFocusRoot(); + var vTarget = this.getCaptureWidget() || (vFocusRoot == null ? null : vFocusRoot.getActiveChild()); + + if (vTarget == null || !vTarget.getEnabled()) { + return false; + } + + var vDomEventTarget = vTarget.getElement(); + + + + + // Hide Menus + switch(vKeyIdentifier) + { + case "Escape": + case "Tab": + if (qx.OO.isAvailable("qx.manager.object.MenuManager")) { + qx.manager.object.MenuManager.getInstance().update(vTarget, vType); + } + + break; + } + + + + + // TODO: Move this to KeyEvent? + + // Prohibit CTRL+A + if (!this.getAllowClientSelectAll()) + { + if (vDomEvent.ctrlKey && vKeyIdentifier == "A") + { + switch(vDomTarget.tagName.toLowerCase()) + { + case "input": + case "textarea": + case "iframe": + break; + + default: + qx.event.handler.EventHandler.stopDomEvent(vDomEvent); + } + } + } + + + + // Create Event Object + var vKeyEventObject = new qx.event.type.KeyEvent(vType, vDomEvent, vDomTarget, vTarget, null, vKeyCode, vCharCode, vKeyIdentifier); + + // Check for commands + if (vDomEvent.type == "keydown") { + this._checkKeyEventMatch(vKeyEventObject); + } + + try { + // Starting Objects Internal Event Dispatcher + // This handles the real event action + vTarget.dispatchEvent(vKeyEventObject); + + // Send event to qx.event.handler.DragAndDropHandler + if (qx.OO.isAvailable("qx.event.handler.DragAndDropHandler")) { + qx.event.handler.DragAndDropHandler.getInstance().handleKeyEvent(vKeyEventObject); + } + } catch (ex) { + this.error("Failed to dispatch key event", ex); + this.createDispatchDataEvent("error", ex); + } + + // Cleanup Event Object + vKeyEventObject.dispose(); + + // Flush Queues + qx.ui.core.Widget.flushGlobalQueues(); +} + + + + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENTS +--------------------------------------------------------------------------- +*/ + +/*! + This one handle all mouse events + + When a user double clicks on a qx.ui.core.Widget the + order of the mouse events is the following: + + 1. mousedown + 2. mouseup + 3. click + 4. mousedown + 5. mouseup + 6. click + 7. dblclick +*/ + +if(qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._onmouseevent = function(vDomEvent) + { + qx.core.Init.getInstance().getComponent().preload(); + + if(!vDomEvent) { + vDomEvent = window.event; + } + + var vDomTarget = qx.event.handler.EventHandler.getDomTarget(vDomEvent); + var vType = vDomEvent.type; + + if(vType == "mousemove") + { + if (this._mouseIsDown && vDomEvent.button == 0) + { + this._onmouseevent_post(vDomEvent, "mouseup"); + this._mouseIsDown = false; + } + } + else + { + if(vType == "mousedown") + { + this._mouseIsDown = true; + } + else if(vType == "mouseup") + { + this._mouseIsDown = false; + } + + // Fix MSHTML Mouseup, should be after a normal click or contextmenu event, like Mozilla does this + if(vType == "mouseup" && !this._lastMouseDown && ((new Date).valueOf() - this._lastMouseEventDate) < 250) + { + this._onmouseevent_post(vDomEvent, "mousedown"); + } + // Fix MSHTML Doubleclick, should be after a normal click event, like Mozilla does this + else if(vType == "dblclick" && this._lastMouseEventType == "mouseup" && ((new Date).valueOf() - this._lastMouseEventDate) < 250) + { + this._onmouseevent_post(vDomEvent, "click"); + } + + switch(vType) + { + case "mousedown": + case "mouseup": + case "click": + case "dblclick": + case "contextmenu": + this._lastMouseEventType = vType; + this._lastMouseEventDate = (new Date).valueOf(); + this._lastMouseDown = vType == "mousedown"; + } + } + + this._onmouseevent_post(vDomEvent, vType, vDomTarget); + } +} +else +{ + qx.Proto._onmouseevent = function(vDomEvent) + { + qx.core.Init.getInstance().getComponent().preload(); + + var vDomTarget = qx.event.handler.EventHandler.getDomTarget(vDomEvent); + var vType = vDomEvent.type; + + switch(vType) + { + case "DOMMouseScroll": + // normalize mousewheel event + vType = "mousewheel"; + break; + + case "click": + case "dblclick": + // ignore click or dblclick events with other then the left mouse button + if (vDomEvent.which !== 1) { + return; + } + } + + this._onmouseevent_post(vDomEvent, vType, vDomTarget); + } +} + +/*! +Fixes browser quirks with 'click' detection + +Firefox 1.5.0.6: The DOM-targets are different. The click event only fires, if the target of the + mousedown is the same than with the mouseup. If the content moved away, the click isn't fired. + +Internet Explorer 6.0: The DOM-targets are identical and the click fires fine. + +Opera 9.01: The DOM-targets are different, but the click fires fine. Fires click successfull, + even if the content under the cursor was moved away. +*/ +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._onmouseevent_click_fix = function(vDomTarget, vType, vDispatchTarget) + { + var vReturn = false; + + switch(vType) + { + case "mousedown": + this._lastMouseDownDomTarget = vDomTarget; + this._lastMouseDownDispatchTarget = vDispatchTarget; + break; + + case "mouseup": + // Add additional click event if the dispatch target is the same, but the dom target is different + if (this._lastMouseDownDispatchTarget === vDispatchTarget && vDomTarget !== this._lastMouseDownDomTarget) + { + vReturn = true; + } + else + { + this._lastMouseDownDomTarget = null; + this._lastMouseDownDispatchTarget = null; + } + } + + return vReturn; + }; +} +else +{ + qx.Proto._onmouseevent_click_fix = function(vDomTarget, vDispatchTarget) { + return false; + } +}; + +/*! + This is the crossbrowser post handler for all mouse events. +*/ +qx.Proto._onmouseevent_post = function(vDomEvent, vType, vDomTarget) +{ + try + { + var vEventObject, vCaptureTarget, vDispatchTarget, vTarget, vOriginalTarget, vRelatedTarget, vFixClick, vTargetIsEnabled; + + + + // Check for capturing, if enabled the target is the captured widget. + vCaptureTarget = this.getCaptureWidget(); + + // Event Target Object + vOriginalTarget = qx.event.handler.EventHandler.getOriginalTargetObject(vDomTarget); + + // If capturing isn't active search for a valid target object + if (!vCaptureTarget) + { + // Get Target Object + vDispatchTarget = vTarget = qx.event.handler.EventHandler.getTargetObject(null, vOriginalTarget, true); + } + else + { + vDispatchTarget = vCaptureTarget; + vTarget = qx.event.handler.EventHandler.getTargetObject(null, vOriginalTarget, true); + } + + + + // If there is no target, we have nothing to do + if (!vTarget) { + return; + } + vTargetIsEnabled = vTarget.getEnabled(); + + // Fix click event + vFixClick = this._onmouseevent_click_fix(vDomTarget, vType, vDispatchTarget); + + + // Prevent the browser's native context menu + if (vType == "contextmenu" && !this.getAllowClientContextMenu()) { + qx.event.handler.EventHandler.stopDomEvent(vDomEvent); + } + + + // Update focus + if (vTargetIsEnabled && vType == "mousedown") { + qx.event.handler.FocusHandler.mouseFocus = true; + + var vRoot = vTarget.getFocusRoot(); + + if (vRoot) + { + this.setFocusRoot(vRoot); + + vRoot.setActiveChild(vTarget); + + // Active focus on element (if possible, else search up the parent tree) + var vFocusTarget = vTarget; + while (!vFocusTarget.isFocusable() && vFocusTarget != vRoot) { + vFocusTarget = vFocusTarget.getParent(); + } + + vRoot.setFocusedChild(vFocusTarget); + } + } + + + + + var vDomEventTarget = vTarget.getElement(); + + + + + // Find related target object + switch(vType) + { + case "mouseover": + case "mouseout": + vRelatedTarget = qx.event.handler.EventHandler.getRelatedTargetObjectFromEvent(vDomEvent); + + // Ignore events where the related target and + // the real target are equal - from our sight + if (vRelatedTarget == vTarget) { + return; + } + } + + + + try + { + + // Create Mouse Event Object + vEventObject = new qx.event.type.MouseEvent(vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget, vRelatedTarget); + } + catch(ex) + { + return this.error("Failed to create mouse event", ex); + } + + + // Store last Event in MouseEvent Constructor + // Needed for Tooltips, ... + qx.event.type.MouseEvent._storeEventState(vEventObject); + + + if (vTargetIsEnabled) { + // Dispatch Event through target (eventtarget-)object + var vEventWasProcessed = false; + try { + vEventWasProcessed = vDispatchTarget ? vDispatchTarget.dispatchEvent(vEventObject) : true; + + // Handle Special Post Events + this._onmouseevent_special_post(vType, vTarget, vOriginalTarget, vDispatchTarget, vEventWasProcessed, vEventObject, vDomEvent); + } catch(ex) { + this.error("Failed to dispatch mouse event", ex); + this.createDispatchDataEvent("error", ex); + } + } else { + // target is disabled -> Pass the event only to the ToolTipManager + if (vType == "mouseover") { + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) { + qx.manager.object.ToolTipManager.getInstance().handleMouseOver(vEventObject); + } + } + } + + + + // Dispose Event Object + vEventObject.dispose(); + vEventObject = null; + + + + + // Flush Queues + qx.ui.core.Widget.flushGlobalQueues(); + + + // Fix Click (Gecko Bug, see above) + if (vFixClick) + { + this._onmouseevent_post(vDomEvent, "click", this._lastMouseDownDomTarget); + + this._lastMouseDownDomTarget = null; + this._lastMouseDownDispatchTarget = null; + } + } + catch(ex) + { + return this.error("Failed to handle mouse event", ex); + } +} + + +qx.Proto._onmouseevent_special_post = function(vType, vTarget, vOriginalTarget, vDispatchTarget, vEventWasProcessed, vEventObject, vDomEvent) { + switch(vType) + { + case "mousedown": + if (qx.OO.isAvailable("qx.manager.object.PopupManager")) { + qx.manager.object.PopupManager.getInstance().update(vTarget); + } + + if (qx.OO.isAvailable("qx.manager.object.MenuManager")) { + qx.manager.object.MenuManager.getInstance().update(vTarget, vType); + } + + if (qx.OO.isAvailable("qx.manager.object.IframeManager")) { + qx.manager.object.IframeManager.getInstance().handleMouseDown(vEventObject); + } + + break; + + case "mouseup": + + // Mouseup event should always hide, independed of target, so don't send a target + if (qx.OO.isAvailable("qx.manager.object.MenuManager")) { + qx.manager.object.MenuManager.getInstance().update(vTarget, vType); + } + + if (qx.OO.isAvailable("qx.manager.object.IframeManager")) { + qx.manager.object.IframeManager.getInstance().handleMouseUp(vEventObject); + } + + break; + + case "mouseover": + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) { + qx.manager.object.ToolTipManager.getInstance().handleMouseOver(vEventObject); + } + + break; + + case "mouseout": + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) { + qx.manager.object.ToolTipManager.getInstance().handleMouseOut(vEventObject); + } + + break; + + case "mousewheel": + // priority for the real target not the (eventually captured) dispatch target + vEventWasProcessed ? this._onmousewheel(vOriginalTarget || vDispatchTarget, vEventObject) : qx.event.handler.EventHandler.stopDomEvent(vDomEvent); + + break; + } + + + + this._ignoreWindowBlur = vType === "mousedown"; + + + + + // Send Event Object to Drag&Drop Manager + if (qx.OO.isAvailable("qx.event.handler.DragAndDropHandler") && vTarget) { + qx.event.handler.DragAndDropHandler.getInstance().handleMouseEvent(vEventObject); + } +} + + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._onmousewheel = function(vTarget, vEvent) + { + if(vTarget == null) { + return; + } + + // ingore if overflow is configured as hidden + // in this case send the event to the parent instead + if(vTarget.getOverflowY() == "hidden") { + return this._onmousewheel(vTarget.getParent(), vEvent); + } + + var vScrollTop = vTarget.getScrollTop(); + var vDelta = 20 * vEvent.getWheelDelta(); + + // if already at the top edge and the user scrolls up + // then send the event to the parent instead + if(vScrollTop == 0 && vDelta > 0) { + return this._onmousewheel(vTarget.getParent(), vEvent); + } + + var vScrollHeight = vTarget.getScrollHeight(); + var vClientHeight = vTarget.getClientHeight(); + + // if already at the bottom edge and the user scrolls down + // then send the event to the parent instead + if(vScrollTop + vClientHeight >= vScrollHeight && vDelta < 0) { + return this._onmousewheel(vTarget.getParent(), vEvent); + } + + // apply new scroll position + vTarget.setScrollTop(vScrollTop - vDelta); + + // stop default handling, that works sometimes, too + vEvent.preventDefault(); + } +} +else +{ + qx.Proto._onmousewheel = function() {}; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DRAG EVENTS + + Currently only to stop non needed events +--------------------------------------------------------------------------- +*/ + +qx.Proto._ondragevent = function(vEvent) +{ + if (!vEvent) { + vEvent = window.event; + } + + qx.event.handler.EventHandler.stopDomEvent(vEvent); +} + + + + + + + +/* +--------------------------------------------------------------------------- + SELECT EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onselectevent = function(e) +{ + if(!e) { + e = window.event; + } + + var vTarget = qx.event.handler.EventHandler.getOriginalTargetObjectFromEvent(e); + + if(vTarget && !vTarget.getSelectable()) { + qx.event.handler.EventHandler.stopDomEvent(e); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + WINDOW EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._focused = false; + +qx.Proto._onwindowblur = function(e) +{ + // this.debug("Try Window blur..."); + + if (!this._focused || this._ignoreWindowBlur) { + return; + } + + this._focused = false; + + // this.debug("Window blur..."); + + // Disable capturing + this.setCaptureWidget(null); + + // Hide Popups, Tooltips, ... + if (qx.OO.isAvailable("qx.manager.object.PopupManager")) { + qx.manager.object.PopupManager.getInstance().update(); + } + + // Hide Menus + if (qx.OO.isAvailable("qx.manager.object.MenuManager")) { + qx.manager.object.MenuManager.getInstance().update(); + } + + // Cancel Drag Operations + if (qx.OO.isAvailable("qx.event.handler.DragAndDropHandler")) { + qx.event.handler.DragAndDropHandler.getInstance().globalCancelDrag(); + } + + // Send blur event to client document + qx.ui.core.ClientDocument.getInstance().createDispatchEvent("windowblur"); +} + +qx.Proto._onwindowfocus = function(e) +{ + // this.debug("Try Window focus..."); + + if (this._focused) { + return; + } + + this._focused = true; + + // this.debug("Window focus..."); + + // Send focus event to client document + qx.ui.core.ClientDocument.getInstance().createDispatchEvent("windowfocus"); +} + +qx.Proto._onwindowresize = function(e) +{ + // Send resize event to client document + qx.ui.core.ClientDocument.getInstance().createDispatchEvent("windowresize"); +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Detach mouse events + this.detachEvents(); + + // Reset functions + this.__onmouseevent = this.__ondragevent = this.__onselectevent = null; + this.__onwindowblur = this.__onwindowfocus = this.__onwindowresize = null; + + // Cleanup + this._lastMouseEventType = null; + this._lastMouseDown = null; + this._lastMouseEventDate = null; + + this._lastMouseDownDomTarget = null; + this._lastMouseDownDispatchTarget = null; + + if (this._commands) + { + for (var vHash in this._commands) + { + this._commands[vHash].dispose(); + delete this._commands[vHash]; + } + + this._commands = null; + } + + qx.core.Target.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/FocusHandler.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/FocusHandler.js new file mode 100644 index 0000000000..d21639e3dd --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/FocusHandler.js @@ -0,0 +1,344 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#optional(qx.ui.core.Parent) +#optional(qx.ui.basic.Terminator) + +************************************************************************ */ + +/*! + This object gets an instance in each focus root and manage the focus handling for it. +*/ +qx.OO.defineClass("qx.event.handler.FocusHandler", qx.core.Target, +function(vWidget) +{ + qx.core.Target.call(this); + + if (vWidget != null) { + this._attachedWidget = vWidget; + } +}); + +qx.event.handler.FocusHandler.mouseFocus = false; + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getAttachedWidget = function() { + return this._attachedWidget; +} + + + + + + +/* +--------------------------------------------------------------------------- + TAB-EVENT HANDLING +--------------------------------------------------------------------------- +*/ + +// Check for TAB pressed +// * use keydown on mshtml +// * use keypress on vAll other (correct) browsers +// = same behaviour +qx.event.handler.FocusHandler.tabEventType = qx.core.Client.getInstance().isMshtml() ? "keydown" : "keypress"; + +qx.Proto._onkeyevent = function(vContainer, vEvent) +{ + if (vEvent.getKeyIdentifier() != "Tab") { + return; + } + + // Stop all key-events with a TAB keycode + vEvent.stopPropagation(); + vEvent.preventDefault(); + + // But only react on the one to use for this browser. + if (vEvent.getType() != qx.event.handler.FocusHandler.tabEventType) { + return; + } + + qx.event.handler.FocusHandler.mouseFocus = false; + + var vCurrent = this.getAttachedWidget().getFocusedChild(); + + // Support shift key to reverse widget detection order + if(!vEvent.isShiftPressed()) { + var vNext = vCurrent ? this.getWidgetAfter(vContainer, vCurrent) : this.getFirstWidget(vContainer); + } else { + var vNext = vCurrent ? this.getWidgetBefore(vContainer, vCurrent) : this.getLastWidget(vContainer); + } + + // If there was a widget found, focus it + if(vNext) + { + vNext.setFocused(true); + vNext._ontabfocus(); + } +} + +qx.Proto.compareTabOrder = function(c1, c2) +{ + // Sort-Check #1: Tab-Index + if(c1 == c2) { + return 0; + } + + var t1 = c1.getTabIndex(); + var t2 = c2.getTabIndex(); + + // The following are some ideas to handle focus after tabindex. + + // Sort-Check #2: Top-Position + if(t1 != t2) { + return t1 - t2; + } + + var y1 = qx.html.Location.getPageBoxTop(c1.getElement()); + var y2 = qx.html.Location.getPageBoxTop(c2.getElement()); + + if(y1 != y2) { + return y1 - y2; + } + + // Sort-Check #3: Left-Position + var x1 = qx.html.Location.getPageBoxLeft(c1.getElement()); + var x2 = qx.html.Location.getPageBoxLeft(c2.getElement()); + + if(x1 != x2) { + return x1 - x2; + } + + // Sort-Check #4: zIndex + var z1 = c1.getZIndex(); + var z2 = c2.getZIndex(); + + if(z1 != z2) { + return z1 - z2; + } + + return 0; +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES FOR TAB HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getFirstWidget = function(vParentContainer) { + return this._getFirst(vParentContainer, null); +} + +qx.Proto.getLastWidget = function(vParentContainer) { + return this._getLast(vParentContainer, null); +} + +qx.Proto.getWidgetAfter = function(vParentContainer, vWidget) +{ + if(vParentContainer == vWidget) { + return this.getFirstWidget(vParentContainer); + } + + if(vWidget.getAnonymous()) { + vWidget = vWidget.getParent(); + } + + if(vWidget == null) { + return []; + } + + var vAll = []; + + this._getAllAfter(vParentContainer, vWidget, vAll); + + vAll.sort(this.compareTabOrder); + + return vAll.length > 0 ? vAll[0] : this.getFirstWidget(vParentContainer); +} + +qx.Proto.getWidgetBefore = function(vParentContainer, vWidget) +{ + if(vParentContainer == vWidget) { + return this.getLastWidget(vParentContainer); + } + + if(vWidget.getAnonymous()) { + vWidget = vWidget.getParent(); + } + + if(vWidget == null) { + return []; + } + + var vAll = []; + + this._getAllBefore(vParentContainer, vWidget, vAll); + + vAll.sort(this.compareTabOrder); + + var vChildrenLength = vAll.length; + return vChildrenLength > 0 ? vAll[vChildrenLength-1] : this.getLastWidget(vParentContainer); +} + +qx.Proto._getAllAfter = function(vParent, vWidget, vArray) +{ + var vChildren = vParent.getChildren(); + var vCurrentChild; + var vChildrenLength = vChildren.length; + + for (var i = 0; i < vChildrenLength; i++) + { + vCurrentChild = vChildren[i]; + + if(!(vCurrentChild instanceof qx.ui.core.Parent) && !(vCurrentChild instanceof qx.ui.basic.Terminator)) { + continue; + } + + if(vCurrentChild.isFocusable() && vCurrentChild.getTabIndex() > 0 && this.compareTabOrder(vWidget, vCurrentChild) < 0) { + vArray.push(vChildren[i]); + } + + if(!vCurrentChild.isFocusRoot() && vCurrentChild instanceof qx.ui.core.Parent) { + this._getAllAfter(vCurrentChild, vWidget, vArray); + } + } +} + +qx.Proto._getAllBefore = function(vParent, vWidget, vArray) +{ + var vChildren = vParent.getChildren(); + var vCurrentChild; + var vChildrenLength = vChildren.length; + + for (var i = 0; i < vChildrenLength; i++) + { + vCurrentChild = vChildren[i]; + + if(!(vCurrentChild instanceof qx.ui.core.Parent) && !(vCurrentChild instanceof qx.ui.basic.Terminator)) { + continue; + } + + if(vCurrentChild.isFocusable() && vCurrentChild.getTabIndex() > 0 && this.compareTabOrder(vWidget, vCurrentChild) > 0) { + vArray.push(vCurrentChild); + } + + if(!vCurrentChild.isFocusRoot() && vCurrentChild instanceof qx.ui.core.Parent) { + this._getAllBefore(vCurrentChild, vWidget, vArray); + } + } +} + +qx.Proto._getFirst = function(vParent, vFirstWidget) +{ + var vChildren = vParent.getChildren(); + var vCurrentChild; + var vChildrenLength = vChildren.length; + + for (var i = 0; i < vChildrenLength; i++) + { + vCurrentChild = vChildren[i]; + + if(!(vCurrentChild instanceof qx.ui.core.Parent) && !(vCurrentChild instanceof qx.ui.basic.Terminator)) { + continue; + } + + if(vCurrentChild.isFocusable() && vCurrentChild.getTabIndex() > 0) + { + if(vFirstWidget == null || this.compareTabOrder(vCurrentChild, vFirstWidget) < 0) { + vFirstWidget = vCurrentChild; + } + } + + if(!vCurrentChild.isFocusRoot() && vCurrentChild instanceof qx.ui.core.Parent) { + vFirstWidget = this._getFirst(vCurrentChild, vFirstWidget); + } + } + + return vFirstWidget; +} + +qx.Proto._getLast = function(vParent, vLastWidget) +{ + var vChildren = vParent.getChildren(); + var vCurrentChild; + var vChildrenLength = vChildren.length; + + for (var i = 0; i < vChildrenLength; i++) + { + vCurrentChild = vChildren[i]; + + if(!(vCurrentChild instanceof qx.ui.core.Parent) && !(vCurrentChild instanceof qx.ui.basic.Terminator)) { + continue; + } + + if(vCurrentChild.isFocusable() && vCurrentChild.getTabIndex() > 0) + { + if(vLastWidget == null || this.compareTabOrder(vCurrentChild, vLastWidget) > 0) { + vLastWidget = vCurrentChild; + } + } + + if(!vCurrentChild.isFocusRoot() && vCurrentChild instanceof qx.ui.core.Parent) { + vLastWidget = this._getLast(vCurrentChild, vLastWidget); + } + } + + return vLastWidget; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._attachedWidget = null; + + qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/KeyEventHandler.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/KeyEventHandler.js new file mode 100644 index 0000000000..fd44b75c79 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/handler/KeyEventHandler.js @@ -0,0 +1,659 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.event.type.KeyEvent) +#require(qx.lang.Function); + +************************************************************************ */ + +/** + * This class provides unified key event handler for Internet Explorer, + * Firefox, Opera and Safari + */ +qx.OO.defineClass("qx.event.handler.KeyEventHandler", qx.core.Target, function() +{ + qx.core.Target.call(this); + + // Object Wrapper to Events (Needed for DOM-Events) + var o = this; + + /** + * private + * + * @param e {Event} event + */ + this.__onkeypress = function(e) { o._onkeypress(e); }; + + /** + * private + * + * @param e {Event} event + */ + this.__onkeyupdown = function(e) { o._onkeyupdown(e); }; +}); + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-MAPPING +--------------------------------------------------------------------------- +*/ + +/** attach the key event handler to the DOM events */ +qx.Proto._attachEvents = function() +{ + var el = qx.core.Client.getInstance().isGecko() ? window : document.body; + + qx.html.EventRegistration.addEventListener(el, "keypress", this.__onkeypress); + qx.html.EventRegistration.addEventListener(el, "keyup", this.__onkeyupdown); + qx.html.EventRegistration.addEventListener(el, "keydown", this.__onkeyupdown); +}; + +/** detach the key event handler from the DOM events */ +qx.Proto._detachEvents = function() +{ + var el = qx.core.Client.getInstance().isGecko() ? window : document.body; + + // Unregister dom events + qx.html.EventRegistration.removeEventListener(el, "keypress", this.__onkeypress); + qx.html.EventRegistration.removeEventListener(el, "keyup", this.__onkeyupdown); + qx.html.EventRegistration.removeEventListener(el, "keydown", this.__onkeyupdown); +}; + + + + + + + + +/* +--------------------------------------------------------------------------- + KEY-MAPS +--------------------------------------------------------------------------- +*/ + +/** maps the charcodes of special printable keys to key identifiers */ +qx.Proto._specialCharCodeMap = +{ + 8 : "Backspace", // The Backspace (Back) key. + 9 : "Tab", // The Horizontal Tabulation (Tab) key. + 32 : "Space" // The Space (Spacebar) key. +}; + +/** maps the keycodes of non printable keys to key identifiers */ +qx.Proto._keyCodeToIdentifierMap = +{ + 13 : "Enter", // The Enter key. + // Note: This key identifier is also used for the + // Return (Macintosh numpad) key. + 16 : "Shift", // The Shift key. + 17 : "Control", // The Control (Ctrl) key. + 18 : "Alt", // The Alt (Menu) key. + 20 : "CapsLock", // The CapsLock key + 224 : "Meta", // The Meta key. (Apple Meta and Windows key) + + 27 : "Escape", // The Escape (Esc) key. + + 37 : "Left", // The Left Arrow key. + 38 : "Up", // The Up Arrow key. + 39 : "Right", // The Right Arrow key. + 40 : "Down", // The Down Arrow key. + + 33 : "PageUp", // The Page Up key. + 34 : "PageDown", // The Page Down (Next) key. + + 35 : "End", // The End key. + 36 : "Home", // The Home key. + 45 : "Insert", // The Insert (Ins) key. (Does not fire in Opera/Win) + 46 : "Delete", // The Delete (Del) Key. + + 112 : "F1", // The F1 key. + 113 : "F2", // The F2 key. + 114 : "F3", // The F3 key. + 115 : "F4", // The F4 key. + 116 : "F5", // The F5 key. + 117 : "F6", // The F6 key. + 118 : "F7", // The F7 key. + 119 : "F8", // The F8 key. + 120 : "F9", // The F9 key. + 121 : "F10", // The F10 key. + 122 : "F11", // The F11 key. + 123 : "F12", // The F12 key. + + 144 : "NumLock", // The Num Lock key. + 44 : "PrintScreen", // The Print Screen (PrintScrn, SnapShot) key. + 145 : "Scroll", // The scroll lock key + 19 : "Pause", // The pause/break key + + 91 : "Win", // The Windows Logo key + 93 : "Apps" // The Application key (Windows Context Menu) +}; + +/** maps the keycodes of the numpad keys to the right charcodes */ +qx.Proto._numpadToCharCode = +{ + 96 : "0".charCodeAt(0), + 97 : "1".charCodeAt(0), + 98 : "2".charCodeAt(0), + 99 : "3".charCodeAt(0), + 100 : "4".charCodeAt(0), + 101 : "5".charCodeAt(0), + 102 : "6".charCodeAt(0), + 103 : "7".charCodeAt(0), + 104 : "8".charCodeAt(0), + 105 : "9".charCodeAt(0), + + 106 : "*".charCodeAt(0), + 107 : "+".charCodeAt(0), + 109 : "-".charCodeAt(0), + 110 : ",".charCodeAt(0), + 111 : "/".charCodeAt(0) +}; + + +// construct invers of keyCodeToIdentifierMap +(function() +{ + if (!qx.Proto._identifierToKeyCodeMap) + { + qx.Proto._identifierToKeyCodeMap = {}; + + for (var key in qx.Proto._keyCodeToIdentifierMap) { + qx.Proto._identifierToKeyCodeMap[qx.Proto._keyCodeToIdentifierMap[key]] = parseInt(key); + } + + for (var key in qx.Proto._specialCharCodeMap) { + qx.Proto._identifierToKeyCodeMap[qx.Proto._specialCharCodeMap[key]] = parseInt(key); + } + } +})(); + + + + + + + +/* +--------------------------------------------------------------------------- + HELPER-METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto._charCodeA = "A".charCodeAt(0); +qx.Proto._charCodeZ = "Z".charCodeAt(0); +qx.Proto._charCode0 = "0".charCodeAt(0); +qx.Proto._charCode9 = "9".charCodeAt(0); + +/** + * Checks wether the keyCode represents a non printable key + * + * @param keyCode {String} + * @return {Boolean} + */ +qx.Proto._isNonPrintableKeyCode = function(keyCode) { + return this._keyCodeToIdentifierMap[keyCode] ? true : false; +}; + + +/** + * Check wether the keycode can be reliably detected in keyup/keydown events + * + * @param keyCode {String} + * @return {Boolean} + */ +qx.Proto._isIdentifiableKeyCode = function(keyCode) +{ + // A-Z + if (keyCode >= this._charCodeA && keyCode <= this._charCodeZ) { + return true; + } + + // 0-9 + if (keyCode >= this._charCode0 && keyCode <= this._charCode9) { + return true; + } + + // Enter, Space, Tab, Backspace + if (this._specialCharCodeMap[keyCode]) { + return true; + } + + // Numpad + if (this._numpadToCharCode[keyCode]) { + return true; + } + + // non printable keys + if (this._isNonPrintableKeyCode(keyCode)) { + return true; + } + + return false; +}; + + +/** + * Checks wether a given string is a valid keyIdentifier + * + * @param keyIdentifier {String} The key identifier. + * @return {Boolean} wether the given string is a valid keyIdentifier + */ +qx.Proto.isValidKeyIdentifier = function(keyIdentifier) +{ + if (this._identifierToKeyCodeMap[keyIdentifier]) { + return true; + } + + if (keyIdentifier.length != 1) { + return false; + } + + if (keyIdentifier >= "0" && keyIdentifier <= "9") { + return true; + } + + if (keyIdentifier >= "A" && keyIdentifier <= "Z") { + return true; + } + + switch (keyIdentifier) + { + case "+": + case "-": + case "*": + case "/": + return true; + + default: + return false; + } +}; + + +/** + * converts a keyboard code to the corresponding identifier + * + * @param keyCode {Integer} + * @return {String} key identifier + */ +qx.Proto._keyCodeToIdentifier = function(keyCode) +{ + if (this._isIdentifiableKeyCode(keyCode)) + { + var numPadKeyCode = this._numpadToCharCode[keyCode]; + if (numPadKeyCode) { + return String.fromCharCode(numPadKeyCode); + } + + return ( + this._keyCodeToIdentifierMap[keyCode] || + this._specialCharCodeMap[keyCode] || + String.fromCharCode(keyCode) + ); + } + else + { + return "Unidentified"; + } +}; + + +/** + * converts a character code to the corresponding identifier + * + * @param charCode {String} + * @return {String} key identifier + */ +qx.Proto._charCodeToIdentifier = function(charCode) { + return this._specialCharCodeMap[charCode] || String.fromCharCode(charCode).toUpperCase(); +}; + + +/** + * converts a key identifier back to a keycode + * + * @param keyIdentifier {String} + * @return {Integer} keyboard code + */ +qx.Proto._identifierToKeyCode = function(keyIdentifier) { + return this._identifierToKeyCodeMap[keyIdentifier] || keyIdentifier.charCodeAt(0); +}; + + + + + + + + +/* +--------------------------------------------------------------------------- + IDEALIZED-KEY-HANDLER +--------------------------------------------------------------------------- +*/ + +/** + * Key handler for an idealized browser. + * Runs after the browser specific key handlers have normalized the key events. + * + * @param keyCode {String} keyboard code + * @param charCode {String} character code + * @param eventType {String} type of the event (keydown, keypress, keyup) + * @param domEvent {Element} DomEvent + */ +qx.Proto._idealKeyHandler = function(keyCode, charCode, eventType, domEvent) +{ + if (!keyCode && !charCode) { + return; + } + + var keyIdentifier; + + // Use: keyCode + if (keyCode) + { + keyIdentifier = this._keyCodeToIdentifier(keyCode); + qx.event.handler.EventHandler.getInstance()._onkeyevent_post(domEvent, eventType, keyCode, charCode, keyIdentifier); + } + + // Use: charCode + else + { + keyIdentifier = this._charCodeToIdentifier(charCode); + qx.event.handler.EventHandler.getInstance()._onkeyevent_post(domEvent, "keypress", keyCode, charCode, keyIdentifier); + qx.event.handler.EventHandler.getInstance()._onkeyevent_post(domEvent, "keyinput", keyCode, charCode, keyIdentifier); + } +}; + + + + + + + + + +/* +--------------------------------------------------------------------------- + BROWSER-SPECIFIC-KEY-HANDLER: MSHTML +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._lastUpDownType = {}; + + qx.Proto._charCode2KeyCode = + { + 13 : 13, + 27 : 27 + }; + + qx.Proto._onkeyupdown = function(domEvent) + { + domEvent = window.event || domEvent; + + var keyCode = domEvent.keyCode; + var charcode = 0; + var type = domEvent.type; + + // Ignore the down in such sequences dp dp dp + if (!(this._lastUpDownType[keyCode] == "keydown" && type == "keydown")) { + this._idealKeyHandler(keyCode, charcode, type, domEvent); + } + + // On non print-able character be sure to add a keypress event + if (this._isNonPrintableKeyCode(keyCode) && type == "keydown") { + this._idealKeyHandler(keyCode, charcode, "keypress", domEvent); + } + + // Store last type + this._lastUpDownType[keyCode] = type; + }; + + qx.Proto._onkeypress = function(domEvent) + { + domEvent = window.event || domEvent; + + if (this._charCode2KeyCode[domEvent.keyCode]) { + this._idealKeyHandler(this._charCode2KeyCode[domEvent.keyCode], 0, domEvent.type, domEvent); + } else { + this._idealKeyHandler(0, domEvent.keyCode, domEvent.type, domEvent); + } + }; +} + + + + + + +/* +--------------------------------------------------------------------------- + BROWSER-SPECIFIC-KEY-HANDLER: GECKO +--------------------------------------------------------------------------- +*/ + +else if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._lastUpDownType = {}; + + qx.Proto._keyCodeFix = { + 12 : qx.Proto._identifierToKeyCode("NumLock") + }; + + /** + * key handler for Gecko + * + * @param domEvent {Element} DomEvent + */ + qx.Proto._onkeyupdown = qx.Proto._onkeypress = function(domEvent) + { + var keyCode = this._keyCodeFix[domEvent.keyCode] || domEvent.keyCode; + var charCode = domEvent.charCode; + var type = domEvent.type; + + // FF repeats under windows keydown events like IE + if (qx.core.Client.getInstance().runsOnWindows()) + { + var keyIdentifier = keyCode ? this._keyCodeToIdentifier(keyCode) : this._charCodeToIdentifier(charCode) + + if (!(this._lastUpDownType[keyIdentifier] == "keypress" && type == "keydown")) { + this._idealKeyHandler(keyCode, charCode, type, domEvent); + } + + // Store last type + this._lastUpDownType[keyIdentifier] = type; + } + + // all other OSes + else + { + this._idealKeyHandler(keyCode, charCode, type, domEvent); + } + }; +} + + + + + + +/* +--------------------------------------------------------------------------- + BROWSER-SPECIFIC-KEY-HANDLER: WEBKIT +--------------------------------------------------------------------------- +*/ + +else if (qx.core.Client.getInstance().isWebkit()) +{ + qx.Proto._charCode2KeyCode = + { + // Safari/Webkit Mappings + 63289 : qx.Proto._identifierToKeyCode("NumLock"), + 63276 : qx.Proto._identifierToKeyCode("PageUp"), + 63277 : qx.Proto._identifierToKeyCode("PageDown"), + 63275 : qx.Proto._identifierToKeyCode("End"), + 63273 : qx.Proto._identifierToKeyCode("Home"), + 63234 : qx.Proto._identifierToKeyCode("Left"), + 63232 : qx.Proto._identifierToKeyCode("Up"), + 63235 : qx.Proto._identifierToKeyCode("Right"), + 63233 : qx.Proto._identifierToKeyCode("Down"), + 63272 : qx.Proto._identifierToKeyCode("Delete"), + 63302 : qx.Proto._identifierToKeyCode("Insert"), + 63236 : qx.Proto._identifierToKeyCode("F1"), + 63237 : qx.Proto._identifierToKeyCode("F2"), + 63238 : qx.Proto._identifierToKeyCode("F3"), + 63239 : qx.Proto._identifierToKeyCode("F4"), + 63240 : qx.Proto._identifierToKeyCode("F5"), + 63241 : qx.Proto._identifierToKeyCode("F6"), + 63242 : qx.Proto._identifierToKeyCode("F7"), + 63243 : qx.Proto._identifierToKeyCode("F8"), + 63244 : qx.Proto._identifierToKeyCode("F9"), + 63245 : qx.Proto._identifierToKeyCode("F10"), + 63246 : qx.Proto._identifierToKeyCode("F11"), + 63247 : qx.Proto._identifierToKeyCode("F12"), + 63248 : qx.Proto._identifierToKeyCode("PrintScreen"), + + 3 : qx.Proto._identifierToKeyCode("Enter"), + 12 : qx.Proto._identifierToKeyCode("NumLock"), + 13 : qx.Proto._identifierToKeyCode("Enter") + }; + + qx.Proto._onkeyupdown = qx.Proto._onkeypress = function(domEvent) + { + var keyCode = 0; + var charCode = 0; + var type = domEvent.type; + + // prevent Safari from sending key signals twice + // This bug is fixed in recent Webkit builds so we need a revision check + // see http://trac.mochikit.com/ticket/182 for details + if (qx.core.Client.getInstance().getVersion() < 420) + { + if (!this._lastCharCodeForType) { + this._lastCharCodeForType = {}; + } + + var isSafariSpecialKey = this._lastCharCodeForType[type] > 63000; + + if (isSafariSpecialKey) { + this._lastCharCodeForType[type] = null; + return; + } + + this._lastCharCodeForType[type] = domEvent.charCode; + } + + if (type == "keyup" || type == "keydown") { + keyCode = this._charCode2KeyCode[domEvent.charCode] || domEvent.keyCode; + } + else + { + if (this._charCode2KeyCode[domEvent.charCode]) { + keyCode = this._charCode2KeyCode[domEvent.charCode]; + } else { + charCode = domEvent.charCode; + } + } + + this._idealKeyHandler(keyCode, charCode, type, domEvent); + }; +} + + + + + +/* +--------------------------------------------------------------------------- + BROWSER-SPECIFIC-KEY-HANDLER: OPERA +--------------------------------------------------------------------------- +*/ + +else if (qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._onkeyupdown = function(domEvent) { + this._idealKeyHandler(domEvent.keyCode, 0, domEvent.type, domEvent); + }; + + qx.Proto._onkeypress = function(domEvent) + { + if (this._keyCodeToIdentifierMap[domEvent.keyCode]) { + this._idealKeyHandler(domEvent.keyCode, 0, domEvent.type, domEvent); + } else { + this._idealKeyHandler(0, domEvent.keyCode, domEvent.type, domEvent); + } + }; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +/** + * Destructor + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Detach keyboard events + this._detachEvents(); + + return qx.core.Target.prototype.dispose.call(this); +}; + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DataEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DataEvent.js new file mode 100644 index 0000000000..47e08a1771 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DataEvent.js @@ -0,0 +1,50 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/*! + Event object for property changes. +*/ +qx.OO.defineClass("qx.event.type.DataEvent", qx.event.type.Event, +function(vType, vData) +{ + qx.event.type.Event.call(this, vType); + + this.setData(vData); +}); + +qx.OO.addFastProperty({ name : "propagationStopped", defaultValue : false }); +qx.OO.addFastProperty({ name : "data" }); + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this._valueData = null; + + return qx.event.type.Event.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DomEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DomEvent.js new file mode 100644 index 0000000000..b6fb710c7a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DomEvent.js @@ -0,0 +1,229 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.event.type.DomEvent", qx.event.type.Event, +function(vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget) +{ + qx.event.type.Event.call(this, vType); + + this.setDomEvent(vDomEvent); + this.setDomTarget(vDomTarget); + + this.setTarget(vTarget); + this.setOriginalTarget(vOriginalTarget); +}); + +qx.OO.addFastProperty({ name : "bubbles", defaultValue : true, noCompute : true }); +qx.OO.addFastProperty({ name : "propagationStopped", defaultValue : false, noCompute : true }); + +qx.OO.addFastProperty({ name : "domEvent", setOnlyOnce : true, noCompute : true }); +qx.OO.addFastProperty({ name : "domTarget", setOnlyOnce : true, noCompute : true }); + +/** + * The modifiers. A mask of the pressed modifier keys. This is an OR-combination of + * {@link #SHIFT_MASK}, {@link #CTRL_MASK}, {@link #ALT_MASK} and {@link #META_MASK}. + */ +qx.OO.addCachedProperty({ name : "modifiers", defaultValue : null }); + + +// property computer +qx.Proto._computeModifiers = function() { + var mask = 0; + var evt = this.getDomEvent(); + if (evt.shiftKey) mask |= qx.event.type.DomEvent.SHIFT_MASK; + if (evt.ctrlKey) mask |= qx.event.type.DomEvent.CTRL_MASK; + if (evt.altKey) mask |= qx.event.type.DomEvent.ALT_MASK; + if (evt.metaKey) mask |= qx.event.type.DomEvent.META_MASK; + return mask; +} + + + + + + +/* +--------------------------------------------------------------------------- + SPECIAL KEY SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Returns whether the the ctrl key is pressed. + * + * @return {Boolean} whether the the ctrl key is pressed. + */ +qx.Proto.isCtrlPressed = function() { + return this.getDomEvent().ctrlKey; +} + +/** + * Returns whether the the ctrl key is pressed. + * + * @return {Boolean} whether the the ctrl key is pressed. + * @deprecated Use {@link #isCtrlPressed} instead. + */ +qx.Proto.getCtrlKey = qx.Proto.isCtrlPressed; + + +/** + * Returns whether the the shift key is pressed. + * + * @return {Boolean} whether the the shift key is pressed. + */ +qx.Proto.isShiftPressed = function() { + return this.getDomEvent().shiftKey; +} + +/** + * Returns whether the the shift key is pressed. + * + * @return {Boolean} whether the the shift key is pressed. + * @deprecated Use {@link #isShiftPressed} instead. + */ +qx.Proto.getShiftKey = qx.Proto.isShiftPressed; + + +/** + * Returns whether the the alt key is pressed. + * + * @return {Boolean} whether the the alt key is pressed. + */ +qx.Proto.isAltPressed = function() { + return this.getDomEvent().altKey; +} + +/** + * Returns whether the the alt key is pressed. + * + * @return {Boolean} whether the the alt key is pressed. + * @deprecated Use {@link #isAltPressed} instead. + */ +qx.Proto.getAltKey = qx.Proto.isAltPressed; + + +/** + * Returns whether the the meta key is pressed. + * + * @return {Boolean} whether the the meta key is pressed. + */ +qx.Proto.isMetaPressed = function() { + return this.getDomEvent().metaKey; +} + + +/** + * Returns whether the ctrl key or (on the Mac) the command key is pressed. + * + * @return {Boolean} <code>true</code> if the command key is pressed on the Mac + * or the ctrl key is pressed on another system. + */ +qx.Proto.isCtrlOrCommandPressed = function() { + if (qx.core.Client.getInstance().runsOnMacintosh()) { + return this.getDomEvent().metaKey; + } else { + return this.getDomEvent().ctrlKey; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + PREVENT DEFAULT +--------------------------------------------------------------------------- +*/ + +if(qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.setDefaultPrevented = function(vValue) + { + if (!vValue) { + return this.error("It is not possible to set preventDefault to false if it was true before!", "setDefaultPrevented"); + } + + this.getDomEvent().returnValue = false; + + qx.event.type.Event.prototype.setDefaultPrevented.call(this, vValue); + } +} +else +{ + qx.Proto.setDefaultPrevented = function(vValue) + { + if (!vValue) { + return this.error("It is not possible to set preventDefault to false if it was true before!", "setDefaultPrevented"); + } + + this.getDomEvent().preventDefault(); + this.getDomEvent().returnValue = false; + + qx.event.type.Event.prototype.setDefaultPrevented.call(this, vValue); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._valueDomEvent = null; + this._valueDomTarget = null; + + return qx.event.type.Event.prototype.dispose.call(this); +} + + + + +/** {int} The modifier mask for the shift key. */ +qx.Class.SHIFT_MASK = 1; + +/** {int} The modifier mask for the control key. */ +qx.Class.CTRL_MASK = 2; + +/** {int} The modifier mask for the alt key. */ +qx.Class.ALT_MASK = 4; + +/** {int} The modifier mask for the meta key (e.g. apple key on Macs). */ +qx.Class.META_MASK = 8; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DragEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DragEvent.js new file mode 100644 index 0000000000..a6bd360bbe --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/DragEvent.js @@ -0,0 +1,207 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_dragdrop) + +************************************************************************ */ + +/*! + The event object for drag and drop sessions +*/ +qx.OO.defineClass("qx.event.type.DragEvent", qx.event.type.MouseEvent, +function(vType, vMouseEvent, vTarget, vRelatedTarget) +{ + this._mouseEvent = vMouseEvent; + + var vOriginalTarget = null; + + switch(vType) + { + case "dragstart": + case "dragover": + vOriginalTarget = vMouseEvent.getOriginalTarget(); + } + + qx.event.type.MouseEvent.call(this, vType, vMouseEvent.getDomEvent(), vTarget.getElement(), vTarget, vOriginalTarget, vRelatedTarget); +}); + + + + + +/* +--------------------------------------------------------------------------- + UTILITIY +--------------------------------------------------------------------------- +*/ + +qx.Proto.getMouseEvent = function() { + return this._mouseEvent; +} + + + + + + +/* +--------------------------------------------------------------------------- + APPLICATION CONNECTION +--------------------------------------------------------------------------- +*/ + +qx.Proto.startDrag = function() +{ + if (this.getType() != "dragstart") { + throw new Error("qx.event.type.DragEvent startDrag can only be called during the dragstart event: " + this.getType()); + } + + this.stopPropagation(); + qx.event.handler.DragAndDropHandler.getInstance().startDrag(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DATA SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.addData = function(sType, oData) { + qx.event.handler.DragAndDropHandler.getInstance().addData(sType, oData); +} + +qx.Proto.getData = function(sType) { + return qx.event.handler.DragAndDropHandler.getInstance().getData(sType); +} + +qx.Proto.clearData = function() { + qx.event.handler.DragAndDropHandler.getInstance().clearData(); +} + +qx.Proto.getDropDataTypes = function() { + return qx.event.handler.DragAndDropHandler.getInstance().getDropDataTypes(); +} + + + + + + +/* +--------------------------------------------------------------------------- + ACTION SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.addAction = function(sAction) { + qx.event.handler.DragAndDropHandler.getInstance().addAction(sAction); +} + +qx.Proto.removeAction = function(sAction) { + qx.event.handler.DragAndDropHandler.getInstance().removeAction(sAction); +} + +qx.Proto.getAction = function() { + return qx.event.handler.DragAndDropHandler.getInstance().getCurrentAction(); +} + +qx.Proto.clearActions = function() { + qx.event.handler.DragAndDropHandler.getInstance().clearActions(); +} + + + + + + +/* +--------------------------------------------------------------------------- + USER FEEDBACK SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Sets the widget to show as feedback for the user. This widget should + * represent the object(s) the user is dragging. + * + * @param widget {qx.ui.core.Widget} the feedback widget. + * @param deltaX {int ? 10} the number of pixels the top-left corner of the widget + * should be away from the mouse cursor in x direction. + * @param deltaY {int ? 10} the number of pixels the top-left corner of the widget + * should be away from the mouse cursor in y direction. + * @param autoDisposeWidget {boolean} whether the widget should be disposed when + * dragging is finished or cancelled. + */ +qx.Proto.setFeedbackWidget = function(widget, deltaX, deltaY, autoDisposeWidget) { + qx.event.handler.DragAndDropHandler.getInstance().setFeedbackWidget(widget, deltaX, deltaY, autoDisposeWidget); +}; + + + + + + +/* +--------------------------------------------------------------------------- + CURSPOR POSITIONING SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Sets the position of the cursor feedback (the icon showing whether dropping + * is allowed at the current position and which action a drop will do). + * + * @param deltaX {int} The number of pixels the top-left corner of the + * cursor feedback should be away from the mouse cursor in x direction. + * @param deltaY {int} The number of pixels the top-left corner of the + * cursor feedback should be away from the mouse cursor in y direction. + */ +qx.Proto.setCursorPosition = function(deltaX, deltaY) { + qx.event.handler.DragAndDropHandler.getInstance().setCursorPosition(deltaX, deltaY); +}; + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._mouseEvent = null; + + return qx.event.type.MouseEvent.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/Event.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/Event.js new file mode 100644 index 0000000000..82798da893 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/Event.js @@ -0,0 +1,90 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/*! + The qooxdoo core event object. Each event object for qx.core.Targets should extend this class. +*/ +qx.OO.defineClass("qx.event.type.Event", qx.core.Object, +function(vType) +{ + qx.core.Object.call(this, false); + + this.setType(vType); +}); + +qx.OO.addFastProperty({ name : "type", setOnlyOnce : true }); + +qx.OO.addFastProperty({ name : "originalTarget", setOnlyOnce : true }); +qx.OO.addFastProperty({ name : "target", setOnlyOnce : true }); +qx.OO.addFastProperty({ name : "relatedTarget", setOnlyOnce : true }); +qx.OO.addFastProperty({ name : "currentTarget" }); + +qx.OO.addFastProperty({ name : "bubbles", defaultValue : false, noCompute : true }); +qx.OO.addFastProperty({ name : "propagationStopped", defaultValue : true, noCompute : true }); +qx.OO.addFastProperty({ name : "defaultPrevented", defaultValue : false, noCompute : true }); + +/** If the event object should automatically be disposed by the dispatcher */ +qx.OO.addFastProperty({ name : "autoDispose", defaultValue : false }); + + + + +/* +--------------------------------------------------------------------------- + SHORTCUTS +--------------------------------------------------------------------------- +*/ + +qx.Proto.preventDefault = function() { + this.setDefaultPrevented(true); +} + +qx.Proto.stopPropagation = function() { + this.setPropagationStopped(true); +} + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this._valueOriginalTarget = null; + this._valueTarget = null; + this._valueRelatedTarget = null; + this._valueCurrentTarget = null; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/FocusEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/FocusEvent.js new file mode 100644 index 0000000000..d8b327cb78 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/FocusEvent.js @@ -0,0 +1,48 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + This event handles all focus events. + + The four supported types are: + 1+2: focus and blur also propagate the target object + 3+4: focusout and focusin are bubbling to the parent objects +*/ +qx.OO.defineClass("qx.event.type.FocusEvent", qx.event.type.Event, +function(vType, vTarget) +{ + qx.event.type.Event.call(this, vType); + + this.setTarget(vTarget); + + switch(vType) + { + case "focusin": + case "focusout": + this.setBubbles(true); + this.setPropagationStopped(false); + } +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/KeyEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/KeyEvent.js new file mode 100644 index 0000000000..eb69c51242 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/KeyEvent.js @@ -0,0 +1,200 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/** + * A key event instance contains all data for each occured key event + * + * @param vType {String} event type (keydown, keypress, keyinput, keyup) + * @param vDomEvent {Element} DOM event object + * @param vDomTarget {Element} target element of the DOM event + * @param vTarget + * @param vOriginalTarget + * @param vKeyCode {Integer} emulated key code for compatibility with older qoodoo applications + * @param vCharCode {Integer} char code from the "keypress" event + * @param vKeyIdentifier {String} the key identifier + */ +qx.OO.defineClass("qx.event.type.KeyEvent", qx.event.type.DomEvent, +function(vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget, vKeyCode, vCharCode, vKeyIdentifier) +{ + qx.event.type.DomEvent.call(this, vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget); + + this.setKeyCode(vKeyCode); + this.setCharCode(vCharCode); + this.setKeyIdentifier(vKeyIdentifier); +}); + +/** + * Legacy keycode + * @deprecated Will be removed with qooxdoo 0.7 + */ +qx.OO.addFastProperty({ name : "keyCode", setOnlyOnce : true, noCompute : true }); + +/** + * Unicode number of the pressed character. + * Only valid in "keyinput" events + */ +qx.OO.addFastProperty({ name : "charCode", setOnlyOnce : true, noCompute : true }); + +/** + * Identifier of the pressed key. This property is modeled after the <em>KeyboardEvent.keyIdentifier</em> property + * of the W3C DOM 3 event specification (http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-KeyboardEvent-keyIdentifier). + * + * It is not valid in "keyinput" events" + * + * Printable keys are represented by a unicode string, non-printable keys have one of the following + * values: + * <br> + * <table> + * <tr><th>Backspace</th><td>The Backspace (Back) key.</td></tr> + * <tr><th>Tab</th><td>The Horizontal Tabulation (Tab) key.</td></tr> + * <tr><th>Space</th><td>The Space (Spacebar) key.</td></tr> + * <tr><th>Enter</th><td>The Enter key. Note: This key identifier is also used for the Return (Macintosh numpad) key.</td></tr> + * <tr><th>Shift</th><td>The Shift key.</td></tr> + * <tr><th>Control</th><td>The Control (Ctrl) key.</td></tr> + * <tr><th>Alt</th><td>The Alt (Menu) key.</td></tr> + * <tr><th>CapsLock</th><td>The CapsLock key</td></tr> + * <tr><th>Meta</th><td>The Meta key. (Apple Meta and Windows key)</td></tr> + * <tr><th>Escape</th><td>The Escape (Esc) key.</td></tr> + * <tr><th>Left</th><td>The Left Arrow key.</td></tr> + * <tr><th>Up</th><td>The Up Arrow key.</td></tr> + * <tr><th>Right</th><td>The Right Arrow key.</td></tr> + * <tr><th>Down</th><td>The Down Arrow key.</td></tr> + * <tr><th>PageUp</th><td>The Page Up key.</td></tr> + * <tr><th>PageDown</th><td>The Page Down (Next) key.</td></tr> + * <tr><th>End</th><td>The End key.</td></tr> + * <tr><th>Home</th><td>The Home key.</td></tr> + * <tr><th>Insert</th><td>The Insert (Ins) key. (Does not fire in Opera/Win)</td></tr> + * <tr><th>Delete</th><td>The Delete (Del) Key.</td></tr> + * <tr><th>F1</th><td>The F1 key.</td></tr> + * <tr><th>F2</th><td>The F2 key.</td></tr> + * <tr><th>F3</th><td>The F3 key.</td></tr> + * <tr><th>F4</th><td>The F4 key.</td></tr> + * <tr><th>F5</th><td>The F5 key.</td></tr> + * <tr><th>F6</th><td>The F6 key.</td></tr> + * <tr><th>F7</th><td>The F7 key.</td></tr> + * <tr><th>F8</th><td>The F8 key.</td></tr> + * <tr><th>F9</th><td>The F9 key.</td></tr> + * <tr><th>F10</th><td>The F10 key.</td></tr> + * <tr><th>F11</th><td>The F11 key.</td></tr> + * <tr><th>F12</th><td>The F12 key.</td></tr> + * <tr><th>NumLock</th><td>The Num Lock key.</td></tr> + * <tr><th>PrintScreen</th><td>The Print Screen (PrintScrn, SnapShot) key.</td></tr> + * <tr><th>Scroll</th><td>The scroll lock key</td></tr> + * <tr><th>Pause</th><td>The pause/break key</td></tr> + * <tr><th>Win</th><td>The Windows Logo key</td></tr> + * <tr><th>Apps</th><td>The Application key (Windows Context Menu)</td></tr> + * </table> + */ +qx.OO.addFastProperty({ name : "keyIdentifier", setOnlyOnce : true, noCompute : true }); + + + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + CLASS PROPERTIES AND METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Mapping of the old key identifiers to the key codes + * @deprecated + */ +qx.event.type.KeyEvent.keys = +{ + esc : 27, + enter : 13, + tab : 9, + space : 32, + + up : 38, + down : 40, + left : 37, + right : 39, + + shift : 16, + ctrl : 17, + alt : 18, + + f1 : 112, + f2 : 113, + f3 : 114, + f4 : 115, + f5 : 116, + f6 : 117, + f7 : 118, + f8 : 119, + f9 : 120, + f10 : 121, + f11 : 122, + f12 : 123, + + print : 124, + + del : 46, + backspace : 8, + insert : 45, + home : 36, + end : 35, + + pageup : 33, + pagedown : 34, + + numlock : 144, + + numpad_0 : 96, + numpad_1 : 97, + numpad_2 : 98, + numpad_3 : 99, + numpad_4 : 100, + numpad_5 : 101, + numpad_6 : 102, + numpad_7 : 103, + numpad_8 : 104, + numpad_9 : 105, + + numpad_divide : 111, + numpad_multiply : 106, + numpad_minus : 109, + numpad_plus : 107 +}; + +// create dynamic codes copy +(function() { + qx.event.type.KeyEvent.codes = {}; + for (var i in qx.event.type.KeyEvent.keys) { + qx.event.type.KeyEvent.codes[qx.event.type.KeyEvent.keys[i]] = i; + } +})(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/MouseEvent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/MouseEvent.js new file mode 100644 index 0000000000..053037b281 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/event/type/MouseEvent.js @@ -0,0 +1,311 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + A mouse event instance contains all data for each occured mouse event +*/ +qx.OO.defineClass("qx.event.type.MouseEvent", qx.event.type.DomEvent, +function(vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget, vRelatedTarget) +{ + qx.event.type.DomEvent.call(this, vType, vDomEvent, vDomTarget, vTarget, vOriginalTarget); + + if (vRelatedTarget) { + this.setRelatedTarget(vRelatedTarget); + } +}); + +qx.Class.C_BUTTON_LEFT = "left"; +qx.Class.C_BUTTON_MIDDLE = "middle"; +qx.Class.C_BUTTON_RIGHT = "right"; +qx.Class.C_BUTTON_NONE = "none"; + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + CLASS PROPERTIES AND METHODS +--------------------------------------------------------------------------- +*/ + +qx.event.type.MouseEvent._screenX = qx.event.type.MouseEvent._screenY = qx.event.type.MouseEvent._clientX = qx.event.type.MouseEvent._clientY = qx.event.type.MouseEvent._pageX = qx.event.type.MouseEvent._pageY = 0; +qx.event.type.MouseEvent._button = null; + +qx.event.type.MouseEvent._storeEventState = function(e) +{ + qx.event.type.MouseEvent._screenX = e.getScreenX(); + qx.event.type.MouseEvent._screenY = e.getScreenY(); + qx.event.type.MouseEvent._clientX = e.getClientX(); + qx.event.type.MouseEvent._clientY = e.getClientY(); + qx.event.type.MouseEvent._pageX = e.getPageX(); + qx.event.type.MouseEvent._pageY = e.getPageY(); + qx.event.type.MouseEvent._button = e.getButton(); +} + +qx.event.type.MouseEvent.getScreenX = function() { return qx.event.type.MouseEvent._screenX; } +qx.event.type.MouseEvent.getScreenY = function() { return qx.event.type.MouseEvent._screenY; } +qx.event.type.MouseEvent.getClientX = function() { return qx.event.type.MouseEvent._clientX; } +qx.event.type.MouseEvent.getClientY = function() { return qx.event.type.MouseEvent._clientY; } +qx.event.type.MouseEvent.getPageX = function() { return qx.event.type.MouseEvent._pageX; } +qx.event.type.MouseEvent.getPageY = function() { return qx.event.type.MouseEvent._pageY; } +qx.event.type.MouseEvent.getButton = function() { return qx.event.type.MouseEvent._button; } + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.event.type.MouseEvent.buttons = { left : 1, right : 2, middle : 4 } +} +else +{ + qx.event.type.MouseEvent.buttons = { left : 0, right : 2, middle : 1 } +} + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + SCREEN COORDINATES SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getScreenX = function() { + return this.getDomEvent().screenX; +} + +qx.Proto.getScreenY = function() { + return this.getDomEvent().screenY; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + PAGE COORDINATES SUPPORT +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ +qx.OO.addFastProperty({ name : "pageX", readOnly : true }); +qx.OO.addFastProperty({ name : "pageY", readOnly : true }); + + if (qx.core.Client.getInstance().isInQuirksMode()) + { + qx.Proto._computePageX = function() { + return this.getDomEvent().clientX + document.documentElement.scrollLeft; + } + + qx.Proto._computePageY = function() { + return this.getDomEvent().clientY + document.documentElement.scrollTop; + } + } + else + { + qx.Proto._computePageX = function() { + return this.getDomEvent().clientX + document.body.scrollLeft; + } + + qx.Proto._computePageY = function() { + return this.getDomEvent().clientY + document.body.scrollTop; + } + } +} +else if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto.getPageX = function() { + return this.getDomEvent().pageX; + } + + qx.Proto.getPageY = function() { + return this.getDomEvent().pageY; + } +} +else +{ + qx.Proto.getPageX = function() { + return this.getDomEvent().clientX; + } + + qx.Proto.getPageY = function() { + return this.getDomEvent().clientY; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + CLIENT COORDINATES SUPPORT +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isGecko()) +{ + qx.Proto.getClientX = function() { + return this.getDomEvent().clientX; + } + + qx.Proto.getClientY = function() { + return this.getDomEvent().clientY; + } +} +else +{ +qx.OO.addFastProperty({ name : "clientX", readOnly : true }); +qx.OO.addFastProperty({ name : "clientY", readOnly : true }); + + qx.Proto._computeClientX = function() { + return this.getDomEvent().clientX + (document.body && document.body.scrollLeft != null ? document.body.scrollLeft : 0); + } + + qx.Proto._computeClientY = function() { + return this.getDomEvent().clientY + (document.body && document.body.scrollTop != null ? document.body.scrollTop : 0); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + BUTTON SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.OO.addFastProperty({ name : "button", readOnly : true }); + +// IE does not set e.button in click events +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.isLeftButtonPressed = function() { + if (this.getType() == "click") { + return true; + } else { + return this.getButton() === qx.event.type.MouseEvent.C_BUTTON_LEFT; + } + } +} +else +{ + qx.Proto.isLeftButtonPressed = function() { + return this.getButton() === qx.event.type.MouseEvent.C_BUTTON_LEFT; + } +} + +qx.Proto.isMiddleButtonPressed = function() { + return this.getButton() === qx.event.type.MouseEvent.C_BUTTON_MIDDLE; +} + +qx.Proto.isRightButtonPressed = function() { + return this.getButton() === qx.event.type.MouseEvent.C_BUTTON_RIGHT; +} + +qx.Proto._computeButton = function() { + var e = this.getDomEvent(); + if (e.which) { + switch (e.which) { + case 1: + return qx.event.type.MouseEvent.C_BUTTON_LEFT; + + case 3: + return qx.event.type.MouseEvent.C_BUTTON_RIGHT; + + case 2: + return qx.event.type.MouseEvent.C_BUTTON_MIDDLE; + + default: + return qx.event.type.MouseEvent.C_BUTTON_NONE; + + } + } else { + switch(e.button) { + case 1: + return qx.event.type.MouseEvent.C_BUTTON_LEFT; + + case 2: + return qx.event.type.MouseEvent.C_BUTTON_RIGHT; + + case 4: + return qx.event.type.MouseEvent.C_BUTTON_MIDDLE; + + default: + return qx.event.type.MouseEvent.C_BUTTON_NONE; + } + } +} + + + + +/* +--------------------------------------------------------------------------- + WHEEL SUPPORT +--------------------------------------------------------------------------- +*/ + +// Implementation differences: http://ajaxian.com/archives/javascript-and-mouse-wheels + +qx.OO.addFastProperty({ name : "wheelDelta", readOnly : true }); + +if(qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._computeWheelDelta = function() { + return this.getDomEvent().wheelDelta / 120; + } +} +else if(qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._computeWheelDelta = function() { + return -this.getDomEvent().wheelDelta / 120; + } +} +else +{ + qx.Proto._computeWheelDelta = function() { + return -this.getDomEvent().detail / 3; + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Dimension.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Dimension.js new file mode 100644 index 0000000000..cfbbf68fd2 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Dimension.js @@ -0,0 +1,233 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Dimension"); + +/* ++-Outer----------------------------------------+ +| Margin | +| +-Box------------------------------+ | +| | Border (+ Scrollbar) | | +| | +-Area--------------------+ | | +| | | Padding | | | +| | | +-Inner----------+ | | | +| | | | | | | | +| | | +----------------+ | | | +| | +-------------------------+ | | +| +----------------------------------+ | ++----------------------------------------------+ +*/ + +// Dimensions +qx.html.Dimension.getOuterWidth = function(el) { return qx.html.Dimension.getBoxWidth(el) + qx.html.Style.getMarginLeft(el) + qx.html.Style.getMarginRight(el); } +qx.html.Dimension.getOuterHeight = function(el) { return qx.html.Dimension.getBoxHeight(el) + qx.html.Style.getMarginTop(el) + qx.html.Style.getMarginBottom(el); } + +qx.html.Dimension.getBoxWidthForZeroHeight = function(el) +{ + var h = el.offsetHeight; + if (h == 0) { + var o = el.style.height; + el.style.height = "1px"; + } + + var v = el.offsetWidth; + + if (h == 0) { + el.style.height = o; + } + + return v; +} + +qx.html.Dimension.getBoxHeightForZeroWidth = function(el) +{ + var w = el.offsetWidth; + if (w == 0) { + var o = el.style.width; + el.style.width = "1px"; + } + + var v = el.offsetHeight; + + if (w == 0) { + el.style.width = o; + } + + return v; +} + +qx.html.Dimension.getBoxWidth = function(el) { + return el.offsetWidth; +} + +qx.html.Dimension.getBoxHeight = function(el) { + return el.offsetHeight; +} + + +qx.html.Dimension.getAreaWidth = function(el) {}; +qx.html.Dimension.getAreaHeight = function(el) {}; + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.html.Dimension.getAreaWidth = function(el) + { + // 0 in clientWidth could mean both: That it is really 0 or + // that the element is not rendered by the browser and + // therefore it is 0, too + + // In Gecko based browsers there is sometimes another + // behaviour: The clientHeight is equal to the border + // sum. This is normally not correct and so we + // fix this value with a more complex calculation. + + // (Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1) + + if (el.clientWidth != 0 && el.clientWidth != (qx.html.Style.getBorderLeft(el) + qx.html.Style.getBorderRight(el))) + { + return el.clientWidth; + } + else + { + return qx.html.Dimension.getBoxWidth(el) - qx.html.Dimension.getInsetLeft(el) - qx.html.Dimension.getInsetRight(el); + } + } + + qx.html.Dimension.getAreaHeight = function(el) + { + // 0 in clientHeight could mean both: That it is really 0 or + // that the element is not rendered by the browser and + // therefore it is 0, too + + // In Gecko based browsers there is sometimes another + // behaviour: The clientHeight is equal to the border + // sum. This is normally not correct and so we + // fix this value with a more complex calculation. + + // (Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1) + + if (el.clientHeight != 0 && el.clientHeight != (qx.html.Style.getBorderTop(el) + qx.html.Style.getBorderBottom(el))) + { + return el.clientHeight; + } + else + { + return qx.html.Dimension.getBoxHeight(el) - qx.html.Dimension.getInsetTop(el) - qx.html.Dimension.getInsetBottom(el); + } + } +} +else +{ + qx.html.Dimension.getAreaWidth = function(el) + { + // 0 in clientWidth could mean both: That it is really 0 or + // that the element is not rendered by the browser and + // therefore it is 0, too + + return el.clientWidth != 0 ? el.clientWidth : (qx.html.Dimension.getBoxWidth(el) - qx.html.Dimension.getInsetLeft(el) - qx.html.Dimension.getInsetRight(el)); + } + + qx.html.Dimension.getAreaHeight = function(el) + { + // 0 in clientHeight could mean both: That it is really 0 or + // that the element is not rendered by the browser and + // therefore it is 0, too + + return el.clientHeight != 0 ? el.clientHeight : (qx.html.Dimension.getBoxHeight(el) - qx.html.Dimension.getInsetTop(el) - qx.html.Dimension.getInsetBottom(el)); + } +} + +qx.html.Dimension.getInnerWidth = function(el) { return qx.html.Dimension.getAreaWidth(el) - qx.html.Style.getPaddingLeft(el) - qx.html.Style.getPaddingRight(el); } +qx.html.Dimension.getInnerHeight = function(el) { return qx.html.Dimension.getAreaHeight(el) - qx.html.Style.getPaddingTop(el) - qx.html.Style.getPaddingBottom(el); } + + + + +// Insets +qx.html.Dimension.getInsetLeft = function(el) {}; +qx.html.Dimension.getInsetTop = function(el) {}; +qx.html.Dimension.getInsetRight = function(el) {}; +qx.html.Dimension.getInsetBottom = function(el) {}; + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Dimension.getInsetLeft = function(el) { return el.clientLeft; } + qx.html.Dimension.getInsetTop = function(el) { return el.clientTop; } + qx.html.Dimension.getInsetRight = function(el) { + if(qx.html.Style.getStyleProperty(el, "overflowY") == "hidden" || el.clientWidth == 0) { + return qx.html.Style.getBorderRight(el); + } + + return Math.max(0, el.offsetWidth - el.clientLeft - el.clientWidth); + } + + qx.html.Dimension.getInsetBottom = function(el) { + if(qx.html.Style.getStyleProperty(el, "overflowX") == "hidden" || el.clientHeight == 0) { + return qx.html.Style.getBorderBottom(el); + } + + return Math.max(0, el.offsetHeight - el.clientTop - el.clientHeight); + } +} +else +{ + qx.html.Dimension.getInsetLeft = function(el) { return qx.html.Style.getBorderLeft(el); } + qx.html.Dimension.getInsetTop = function(el) { return qx.html.Style.getBorderTop(el); } + + qx.html.Dimension.getInsetRight = function(el) { + // Alternative method if clientWidth is unavailable + // clientWidth == 0 could mean both: unavailable or really 0 + if (el.clientWidth == 0) { + var ov = qx.html.Style.getStyleProperty(el, "overflow"); + var sbv = ov == "scroll" || ov == "-moz-scrollbars-vertical" ? 16 : 0; + return Math.max(0, qx.html.Style.getBorderRight(el) + sbv); + } + + return Math.max(0, el.offsetWidth - el.clientWidth - qx.html.Style.getBorderLeft(el)); + } + + qx.html.Dimension.getInsetBottom = function(el) { + // Alternative method if clientHeight is unavailable + // clientHeight == 0 could mean both: unavailable or really 0 + if (el.clientHeight == 0) { + var ov = qx.html.Style.getStyleProperty(el, "overflow"); + var sbv = ov == "scroll" || ov == "-moz-scrollbars-horizontal" ? 16 : 0; + return Math.max(0, qx.html.Style.getBorderBottom(el) + sbv); + } + + return Math.max(0, el.offsetHeight - el.clientHeight - qx.html.Style.getBorderTop(el)); + } +} + + +// Scrollbar +qx.html.Dimension.getScrollBarSizeLeft = function(el) { return 0; } +qx.html.Dimension.getScrollBarSizeTop = function(el) { return 0; } +qx.html.Dimension.getScrollBarSizeRight = function(el) { return qx.html.Dimension.getInsetRight(el) - qx.html.Style.getBorderRight(el); } +qx.html.Dimension.getScrollBarSizeBottom = function(el) { return qx.html.Dimension.getInsetBottom(el) - qx.html.Style.getBorderBottom(el); } + +qx.html.Dimension.getScrollBarVisibleX = function(el) { return qx.html.Dimension.getScrollBarSizeRight(el) > 0; } +qx.html.Dimension.getScrollBarVisibleY = function(el) { return qx.html.Dimension.getScrollBarSizeBottom(el) > 0; } diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ElementFromPoint.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ElementFromPoint.js new file mode 100644 index 0000000000..572243c912 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ElementFromPoint.js @@ -0,0 +1,124 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.html.ElementFromPoint"); + +qx.html.ElementFromPoint.getElementFromPoint = function(x, y) { + return qx.html.ElementFromPoint.getElementFromPointHandler(document.body, x, y); +} + +qx.html.ElementFromPoint.getElementFromPointHandler = function(node, x, y, recursive) +{ + var ch = node.childNodes; + var chl = ch.length-1; + + if (chl < 0) { + return null; + } + + var chc, subres, ret; + + do + { + chc = ch[chl]; + ret = qx.html.ElementFromPoint.getElementFromPointChecker(chc, x, y); + + if (ret) + { + if (typeof recursive === "boolean" && recursive == false) + { + return chc; + } + else + { + subres = qx.html.ElementFromPoint.getElementFromPointHandler(chc, x-ret[0]-qx.html.Style.getBorderLeft(chc), y-ret[2]-qx.html.Style.getBorderTop(chc)); + return subres ? subres : chc; + } + } + } + while(chl--); + + return null; +} + +qx.html.ElementFromPoint.getElementFromPointChecker = function(chc, x, y) +{ + var xstart, ystart, xstop, ystop; + + if (chc.nodeType != 1) { + return false; + } + + xstart = qx.html.Offset.getLeft(chc); + if (x > xstart) + { + ystart = qx.html.Offset.getTop(chc); + if (y > ystart) + { + xstop = xstart + chc.offsetWidth; + + if (x < xstop) + { + ystop = ystart + chc.offsetHeight; + if (y < ystop) + { + return [ xstart, xstop, ystart, ystop ]; + } + } + } + } + + return false; +} + +qx.html.ElementFromPoint.getElementAbsolutePointChecker = function(chc, x, y) +{ + var xstart, ystart, xstop, ystop; + + if (!chc || chc.nodeType != 1) { + return false; + } + + xstart = qx.html.Location.getPageBoxLeft(chc); + if (x > xstart) + { + ystart = qx.html.Location.getPageBoxTop(chc); + if (y > ystart) + { + xstop = xstart + chc.offsetWidth; + + if (x < xstop) + { + ystop = ystart + chc.offsetHeight; + if (y < ystop) + { + return [ xstart, xstop, ystart, ystop ]; + } + } + } + } + + return false; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Entity.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Entity.js new file mode 100644 index 0000000000..6f00787d60 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Entity.js @@ -0,0 +1,323 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.lang.Object) + +************************************************************************ */ + +/** + * A Collection of utility functions to escape and unescape strings. + */ +qx.OO.defineClass("qx.html.Entity"); + + +/** Mapping of HTML entity names to the corresponding char code */ +qx.Class.TO_CHARCODE = { + "quot": 34, // " - double-quote + "amp": 38, // & + "lt": 60, // < + "gt": 62, // > + + // http://www.w3.org/TR/REC-html40/sgml/entities.html + // ISO 8859-1 characters + "nbsp": 160, // no-break space + "iexcl": 161, // inverted exclamation mark + "cent": 162, // cent sign + "pound": 163, // pound sterling sign + "curren": 164, // general currency sign + "yen": 165, // yen sign + "brvbar": 166, // broken (vertical) bar + "sect": 167, // section sign + "uml": 168, // umlaut (dieresis) + "copy": 169, // copyright sign + "ordf": 170, // ordinal indicator, feminine + "laquo": 171, // angle quotation mark, left + "not": 172, // not sign + "shy": 173, // soft hyphen + "reg": 174, // registered sign + "macr": 175, // macron + "deg": 176, // degree sign + "plusmn": 177, // plus-or-minus sign + "sup2": 178, // superscript two + "sup3": 179, // superscript three + "acute": 180, // acute accent + "micro": 181, // micro sign + "para": 182, // pilcrow (paragraph sign) + "middot": 183, // middle dot + "cedil": 184, // cedilla + "sup1": 185, // superscript one + "ordm": 186, // ordinal indicator, masculine + "raquo": 187, // angle quotation mark, right + "frac14": 188, // fraction one-quarter + "frac12": 189, // fraction one-half + "frac34": 190, // fraction three-quarters + "iquest": 191, // inverted question mark + "Agrave": 192, // capital A, grave accent + "Aacute": 193, // capital A, acute accent + "Acirc": 194, // capital A, circumflex accent + "Atilde": 195, // capital A, tilde + "Auml": 196, // capital A, dieresis or umlaut mark + "Aring": 197, // capital A, ring + "AElig": 198, // capital AE diphthong (ligature) + "Ccedil": 199, // capital C, cedilla + "Egrave": 200, // capital E, grave accent + "Eacute": 201, // capital E, acute accent + "Ecirc": 202, // capital E, circumflex accent + "Euml": 203, // capital E, dieresis or umlaut mark + "Igrave": 204, // capital I, grave accent + "Iacute": 205, // capital I, acute accent + "Icirc": 206, // capital I, circumflex accent + "Iuml": 207, // capital I, dieresis or umlaut mark + "ETH": 208, // capital Eth, Icelandic + "Ntilde": 209, // capital N, tilde + "Ograve": 210, // capital O, grave accent + "Oacute": 211, // capital O, acute accent + "Ocirc": 212, // capital O, circumflex accent + "Otilde": 213, // capital O, tilde + "Ouml": 214, // capital O, dieresis or umlaut mark + "times": 215, // multiply sign + "Oslash": 216, // capital O, slash + "Ugrave": 217, // capital U, grave accent + "Uacute": 218, // capital U, acute accent + "Ucirc": 219, // capital U, circumflex accent + "Uuml": 220, // capital U, dieresis or umlaut mark + "Yacute": 221, // capital Y, acute accent + "THORN": 222, // capital THORN, Icelandic + "szlig": 223, // small sharp s, German (sz ligature) + "agrave": 224, // small a, grave accent + "aacute": 225, // small a, acute accent + "acirc": 226, // small a, circumflex accent + "atilde": 227, // small a, tilde + "auml": 228, // small a, dieresis or umlaut mark + "aring": 229, // small a, ring + "aelig": 230, // small ae diphthong (ligature) + "ccedil": 231, // small c, cedilla + "egrave": 232, // small e, grave accent + "eacute": 233, // small e, acute accent + "ecirc": 234, // small e, circumflex accent + "euml": 235, // small e, dieresis or umlaut mark + "igrave": 236, // small i, grave accent + "iacute": 237, // small i, acute accent + "icirc": 238, // small i, circumflex accent + "iuml": 239, // small i, dieresis or umlaut mark + "eth": 240, // small eth, Icelandic + "ntilde": 241, // small n, tilde + "ograve": 242, // small o, grave accent + "oacute": 243, // small o, acute accent + "ocirc": 244, // small o, circumflex accent + "otilde": 245, // small o, tilde + "ouml": 246, // small o, dieresis or umlaut mark + "divide": 247, // divide sign + "oslash": 248, // small o, slash + "ugrave": 249, // small u, grave accent + "uacute": 250, // small u, acute accent + "ucirc": 251, // small u, circumflex accent + "uuml": 252, // small u, dieresis or umlaut mark + "yacute": 253, // small y, acute accent + "thorn": 254, // small thorn, Icelandic + "yuml": 255, // small y, dieresis or umlaut mark + // Latin Extended-B + "fnof": 402, //latin small f with hook = function= florin, U+0192 ISOtech + // Greek + "Alpha": 913, //greek capital letter alpha, U+0391 + "Beta": 914, //greek capital letter beta, U+0392 + "Gamma": 915, //greek capital letter gamma,U+0393 ISOgrk3 + "Delta": 916, //greek capital letter delta,U+0394 ISOgrk3 + "Epsilon": 917, //greek capital letter epsilon, U+0395 + "Zeta": 918, //greek capital letter zeta, U+0396 + "Eta": 919, //greek capital letter eta, U+0397 + "Theta": 920, //greek capital letter theta,U+0398 ISOgrk3 + "Iota": 921, //greek capital letter iota, U+0399 + "Kappa": 922, //greek capital letter kappa, U+039A + "Lambda": 923, //greek capital letter lambda,U+039B ISOgrk3 + "Mu": 924, //greek capital letter mu, U+039C + "Nu": 925, //greek capital letter nu, U+039D + "Xi": 926, //greek capital letter xi, U+039E ISOgrk3 + "Omicron": 927, //greek capital letter omicron, U+039F + "Pi": 928, //greek capital letter pi, U+03A0 ISOgrk3 + "Rho": 929, //greek capital letter rho, U+03A1 + // there is no Sigmaf, and no U+03A2 character either + "Sigma": 931, //greek capital letter sigma,U+03A3 ISOgrk3 + "Tau": 932, //greek capital letter tau, U+03A4 + "Upsilon": 933, //greek capital letter upsilon,U+03A5 ISOgrk3 + "Phi": 934, //greek capital letter phi,U+03A6 ISOgrk3 + "Chi": 935, //greek capital letter chi, U+03A7 + "Psi": 936, //greek capital letter psi,U+03A8 ISOgrk3 + "Omega": 937, //greek capital letter omega,U+03A9 ISOgrk3 + "alpha": 945, //greek small letter alpha,U+03B1 ISOgrk3 + "beta": 946, //greek small letter beta, U+03B2 ISOgrk3 + "gamma": 947, //greek small letter gamma,U+03B3 ISOgrk3 + "delta": 948, //greek small letter delta,U+03B4 ISOgrk3 + "epsilon": 949, //greek small letter epsilon,U+03B5 ISOgrk3 + "zeta": 950, //greek small letter zeta, U+03B6 ISOgrk3 + "eta": 951, //greek small letter eta, U+03B7 ISOgrk3 + "theta": 952, //greek small letter theta,U+03B8 ISOgrk3 + "iota": 953, //greek small letter iota, U+03B9 ISOgrk3 + "kappa": 954, //greek small letter kappa,U+03BA ISOgrk3 + "lambda": 955, //greek small letter lambda,U+03BB ISOgrk3 + "mu": 956, //greek small letter mu, U+03BC ISOgrk3 + "nu": 957, //greek small letter nu, U+03BD ISOgrk3 + "xi": 958, //greek small letter xi, U+03BE ISOgrk3 + "omicron": 959, //greek small letter omicron, U+03BF NEW + "pi": 960, //greek small letter pi, U+03C0 ISOgrk3 + "rho": 961, //greek small letter rho, U+03C1 ISOgrk3 + "sigmaf": 962, //greek small letter final sigma,U+03C2 ISOgrk3 + "sigma": 963, //greek small letter sigma,U+03C3 ISOgrk3 + "tau": 964, //greek small letter tau, U+03C4 ISOgrk3 + "upsilon": 965, //greek small letter upsilon,U+03C5 ISOgrk3 + "phi": 966, //greek small letter phi, U+03C6 ISOgrk3 + "chi": 967, //greek small letter chi, U+03C7 ISOgrk3 + "psi": 968, //greek small letter psi, U+03C8 ISOgrk3 + "omega": 969, //greek small letter omega,U+03C9 ISOgrk3 + "thetasym": 977, //greek small letter theta symbol,U+03D1 NEW + "upsih": 978, //greek upsilon with hook symbol,U+03D2 NEW + "piv": 982, //greek pi symbol, U+03D6 ISOgrk3 + // General Punctuation + "bull": 8226, //bullet = black small circle,U+2022 ISOpub + // bullet is NOT the same as bullet operator, U+2219 + "hellip": 8230, //horizontal ellipsis = three dot leader,U+2026 ISOpub + "prime": 8242, //prime = minutes = feet, U+2032 ISOtech + "Prime": 8243, //double prime = seconds = inches,U+2033 ISOtech + "oline": 8254, //overline = spacing overscore,U+203E NEW + "frasl": 8260, //fraction slash, U+2044 NEW + // Letterlike Symbols + "weierp": 8472, //script capital P = power set= Weierstrass p, U+2118 ISOamso + "image": 8465, //blackletter capital I = imaginary part,U+2111 ISOamso + "real": 8476, //blackletter capital R = real part symbol,U+211C ISOamso + "trade": 8482, //trade mark sign, U+2122 ISOnum + "alefsym": 8501, //alef symbol = first transfinite cardinal,U+2135 NEW + // alef symbol is NOT the same as hebrew letter alef,U+05D0 although the same glyph could be used to depict both characters + // Arrows + "larr": 8592, //leftwards arrow, U+2190 ISOnum + "uarr": 8593, //upwards arrow, U+2191 ISOnum--> + "rarr": 8594, //rightwards arrow, U+2192 ISOnum + "darr": 8595, //downwards arrow, U+2193 ISOnum + "harr": 8596, //left right arrow, U+2194 ISOamsa + "crarr": 8629, //downwards arrow with corner leftwards= carriage return, U+21B5 NEW + "lArr": 8656, //leftwards double arrow, U+21D0 ISOtech + // ISO 10646 does not say that lArr is the same as the 'is implied by' arrowbut also does not have any other character for that function. So ? lArr canbe used for 'is implied by' as ISOtech suggests + "uArr": 8657, //upwards double arrow, U+21D1 ISOamsa + "rArr": 8658, //rightwards double arrow,U+21D2 ISOtech + // ISO 10646 does not say this is the 'implies' character but does not have another character with this function so ?rArr can be used for 'implies' as ISOtech suggests + "dArr": 8659, //downwards double arrow, U+21D3 ISOamsa + "hArr": 8660, //left right double arrow,U+21D4 ISOamsa + // Mathematical Operators + "forall": 8704, //for all, U+2200 ISOtech + "part": 8706, //partial differential, U+2202 ISOtech + "exist": 8707, //there exists, U+2203 ISOtech + "empty": 8709, //empty set = null set = diameter,U+2205 ISOamso + "nabla": 8711, //nabla = backward difference,U+2207 ISOtech + "isin": 8712, //element of, U+2208 ISOtech + "notin": 8713, //not an element of, U+2209 ISOtech + "ni": 8715, //contains as member, U+220B ISOtech + // should there be a more memorable name than 'ni'? + "prod": 8719, //n-ary product = product sign,U+220F ISOamsb + // prod is NOT the same character as U+03A0 'greek capital letter pi' though the same glyph might be used for both + "sum": 8721, //n-ary summation, U+2211 ISOamsb + // sum is NOT the same character as U+03A3 'greek capital letter sigma' though the same glyph might be used for both + "minus": 8722, //minus sign, U+2212 ISOtech + "lowast": 8727, //asterisk operator, U+2217 ISOtech + "radic": 8730, //square root = radical sign,U+221A ISOtech + "prop": 8733, //proportional to, U+221D ISOtech + "infin": 8734, //infinity, U+221E ISOtech + "ang": 8736, //angle, U+2220 ISOamso + "and": 8743, //logical and = wedge, U+2227 ISOtech + "or": 8744, //logical or = vee, U+2228 ISOtech + "cap": 8745, //intersection = cap, U+2229 ISOtech + "cup": 8746, //union = cup, U+222A ISOtech + "int": 8747, //integral, U+222B ISOtech + "there4": 8756, //therefore, U+2234 ISOtech + "sim": 8764, //tilde operator = varies with = similar to,U+223C ISOtech + // tilde operator is NOT the same character as the tilde, U+007E,although the same glyph might be used to represent both + "cong": 8773, //approximately equal to, U+2245 ISOtech + "asymp": 8776, //almost equal to = asymptotic to,U+2248 ISOamsr + "ne": 8800, //not equal to, U+2260 ISOtech + "equiv": 8801, //identical to, U+2261 ISOtech + "le": 8804, //less-than or equal to, U+2264 ISOtech + "ge": 8805, //greater-than or equal to,U+2265 ISOtech + "sub": 8834, //subset of, U+2282 ISOtech + "sup": 8835, //superset of, U+2283 ISOtech + // note that nsup, 'not a superset of, U+2283' is not covered by the Symbol font encoding and is not included. Should it be, for symmetry?It is in ISOamsn --> <!ENTITY nsub": 8836, //not a subset of, U+2284 ISOamsn + "sube": 8838, //subset of or equal to, U+2286 ISOtech + "supe": 8839, //superset of or equal to,U+2287 ISOtech + "oplus": 8853, //circled plus = direct sum,U+2295 ISOamsb + "otimes": 8855, //circled times = vector product,U+2297 ISOamsb + "perp": 8869, //up tack = orthogonal to = perpendicular,U+22A5 ISOtech + "sdot": 8901, //dot operator, U+22C5 ISOamsb + // dot operator is NOT the same character as U+00B7 middle dot + // Miscellaneous Technical + "lceil": 8968, //left ceiling = apl upstile,U+2308 ISOamsc + "rceil": 8969, //right ceiling, U+2309 ISOamsc + "lfloor": 8970, //left floor = apl downstile,U+230A ISOamsc + "rfloor": 8971, //right floor, U+230B ISOamsc + "lang": 9001, //left-pointing angle bracket = bra,U+2329 ISOtech + // lang is NOT the same character as U+003C 'less than' or U+2039 'single left-pointing angle quotation mark' + "rang": 9002, //right-pointing angle bracket = ket,U+232A ISOtech + // rang is NOT the same character as U+003E 'greater than' or U+203A 'single right-pointing angle quotation mark' + // Geometric Shapes + "loz": 9674, //lozenge, U+25CA ISOpub + // Miscellaneous Symbols + "spades": 9824, //black spade suit, U+2660 ISOpub + // black here seems to mean filled as opposed to hollow + "clubs": 9827, //black club suit = shamrock,U+2663 ISOpub + "hearts": 9829, //black heart suit = valentine,U+2665 ISOpub + "diams": 9830, //black diamond suit, U+2666 ISOpub + + // Latin Extended-A + "OElig": 338, // -- latin capital ligature OE,U+0152 ISOlat2 + "oelig": 339, // -- latin small ligature oe, U+0153 ISOlat2 + // ligature is a misnomer, this is a separate character in some languages + "Scaron": 352, // -- latin capital letter S with caron,U+0160 ISOlat2 + "scaron": 353, // -- latin small letter s with caron,U+0161 ISOlat2 + "Yuml": 376, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 + // Spacing Modifier Letters + "circ": 710, // -- modifier letter circumflex accent,U+02C6 ISOpub + "tilde": 732, //small tilde, U+02DC ISOdia + // General Punctuation + "ensp": 8194, //en space, U+2002 ISOpub + "emsp": 8195, //em space, U+2003 ISOpub + "thinsp": 8201, //thin space, U+2009 ISOpub + "zwnj": 8204, //zero width non-joiner,U+200C NEW RFC 2070 + "zwj": 8205, //zero width joiner, U+200D NEW RFC 2070 + "lrm": 8206, //left-to-right mark, U+200E NEW RFC 2070 + "rlm": 8207, //right-to-left mark, U+200F NEW RFC 2070 + "ndash": 8211, //en dash, U+2013 ISOpub + "mdash": 8212, //em dash, U+2014 ISOpub + "lsquo": 8216, //left single quotation mark,U+2018 ISOnum + "rsquo": 8217, //right single quotation mark,U+2019 ISOnum + "sbquo": 8218, //single low-9 quotation mark, U+201A NEW + "ldquo": 8220, //left double quotation mark,U+201C ISOnum + "rdquo": 8221, //right double quotation mark,U+201D ISOnum + "bdquo": 8222, //double low-9 quotation mark, U+201E NEW + "dagger": 8224, //dagger, U+2020 ISOpub + "Dagger": 8225, //double dagger, U+2021 ISOpub + "permil": 8240, //per mille sign, U+2030 ISOtech + "lsaquo": 8249, //single left-pointing angle quotation mark,U+2039 ISO proposed + // lsaquo is proposed but not yet ISO standardized + "rsaquo": 8250, //single right-pointing angle quotation mark,U+203A ISO proposed + // rsaquo is proposed but not yet ISO standardized + "euro": 8364 // -- euro sign, U+20AC NEW +}; + + +/** Mapping of char codes to HTML entity names */ +qx.Class.FROM_CHARCODE = qx.lang.Object.invert(qx.Class.TO_CHARCODE); + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/EventRegistration.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/EventRegistration.js new file mode 100644 index 0000000000..d8a8d43884 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/EventRegistration.js @@ -0,0 +1,67 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.EventRegistration"); + +/** + * Assign a function to an event. + * + * @param vElement {Element} DOM Element + * @param vType {String} Name of the event + * @param vFunction {Function} The pointer to the function to assign + */ +qx.html.EventRegistration.addEventListener = function(vElement, vType, vFunction) {}; + +/** + * Unassign a function from an event. + * + * @param vElement {Element} DOM Element + * @param vType {String} Name of the event + * @param vFunction {Function} The pointer to the function to assign + */ +qx.html.EventRegistration.removeEventListener = function(vElement, vType, vFunction) {}; + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.EventRegistration.addEventListener = function(vElement, vType, vFunction) { + vElement.attachEvent("on" + vType, vFunction); + } + + qx.html.EventRegistration.removeEventListener = function(vElement, vType, vFunction) { + vElement.detachEvent("on" + vType, vFunction); + } +} +else +{ + qx.html.EventRegistration.addEventListener = function(vElement, vType, vFunction) { + vElement.addEventListener(vType, vFunction, false); + } + + qx.html.EventRegistration.removeEventListener = function(vElement, vType, vFunction) { + vElement.removeEventListener(vType, vFunction, false); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Form.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Form.js new file mode 100644 index 0000000000..4ebe0be8ca --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Form.js @@ -0,0 +1,111 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Form"); + +qx.Class.ignoreInputTypes = [ "file", "submit", "image", "reset", "button" ]; +qx.Class.ignoreElementTypes = [ "fieldset" ]; +qx.Class.checkElementTypes = [ "radio", "checkbox" ]; +qx.Class.multiSelectType = "select-multiple"; + +qx.Class.inputFilter = function(vNode) +{ + if (vNode.disabled) { + return false; + } + + var vTag = (vNode.tagName || "").toLowerCase(); + + if (qx.lang.Array.contains(qx.html.Form.ignoreElementTypes, vTag)) { + return false; + } + + var vType = vNode.type.toLowerCase(); + + if (qx.lang.Array.contains(qx.html.Form.ignoreInputTypes, vType)) { + return false; + } + + if (!vNode.checked && qx.lang.Array.contains(qx.html.Form.checkElementTypes, vType)) { + return false; + } + + return true; +} + +qx.Class.getFields = function(vForm) { + return Array.filter(vForm.elements, qx.html.Form.inputFilter); +} + +qx.Class.encodeField = function(vNode) +{ + var vName = vNode.name || ""; + var vType = (vNode.type || "").toLowerCase(); + + if(vType === qx.html.Form.multiSelectType) + { + var vValues = []; + + for(var i=0; i<vNode.options.length; i++) + { + if(vNode.options[i].selected) { + vValues.push(vName + "=" + vNode.options[i].value); + } + } + + return vValues.join("&"); + } + else + { + return vName + "=" + vNode.value; + } +} + +qx.Class.encodeForm = function(vForm) +{ + var vFields = qx.html.Form.getFields(vForm); + var vAll = []; + + for (var i=0, l=vFields.length; i<l; i++) { + vAll.push(qx.html.Form.encodeField(vFields[i])); + } + + return vAll.join("&"); +} + +qx.Class.bind = function(vForm, vMethod) +{ + qx.html.EventRegistration.addEventListener(vForm, "submit", function(e) + { + e.returnValue = false; + + if (typeof e.preventDefault === "function") { + e.preventDefault(); + } + + return vMethod(e); + }); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Iframe.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Iframe.js new file mode 100644 index 0000000000..adc4d8fcf7 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Iframe.js @@ -0,0 +1,92 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Iframe"); + +qx.html.Iframe.getWindow = function(vIframe) {}; +qx.html.Iframe.getDocument = function(vIframe) {}; + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Iframe.getWindow = function(vIframe) + { + try + { + return vIframe.contentWindow; + } + catch(ex) + { + return null; + } + } + + qx.html.Iframe.getDocument = function(vIframe) + { + try + { + var vWin = qx.html.Iframe.getWindow(vIframe); + return vWin ? vWin.document : null; + } + catch(ex) + { + return null; + } + } +} +else +{ + qx.html.Iframe.getWindow = function(vIframe) + { + try + { + var vDoc = qx.html.Iframe.getDocument(vIframe); + return vDoc ? vDoc.defaultView : null; + } + catch(ex) + { + return null; + } + } + + qx.html.Iframe.getDocument = function(vIframe) + { + try + { + return vIframe.contentDocument; + } + catch(ex) + { + return null; + } + } +} + +qx.html.Iframe.getBody = function(vIframe) +{ + var vDoc = qx.html.Iframe.getDocument(vIframe); + return vDoc ? vDoc.getElementsByTagName("body")[0] : null; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Location.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Location.js new file mode 100644 index 0000000000..b51241bb16 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Location.js @@ -0,0 +1,284 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Location"); + +qx.html.Location.getPageOuterLeft = function(el) { return qx.html.Location.getPageBoxLeft(el) - qx.html.Style.getMarginLeft(el); } +qx.html.Location.getPageOuterTop = function(el) { return qx.html.Location.getPageBoxTop(el) - qx.html.Style.getMarginTop(el); } +qx.html.Location.getPageOuterRight = function(el) { return qx.html.Location.getPageBoxRight(el) + qx.html.Style.getMarginRight(el); } +qx.html.Location.getPageOuterBottom = function(el) { return qx.html.Location.getPageBoxBottom(el) + qx.html.Style.getMarginBottom(el); } + +qx.html.Location.getClientOuterLeft = function(el) { return qx.html.Location.getClientBoxLeft(el) - qx.html.Style.getMarginLeft(el); } +qx.html.Location.getClientOuterTop = function(el) { return qx.html.Location.getClientBoxTop(el) - qx.html.Style.getMarginTop(el); } +qx.html.Location.getClientOuterRight = function(el) { return qx.html.Location.getClientBoxRight(el) + qx.html.Style.getMarginRight(el); } +qx.html.Location.getClientOuterBottom = function(el) { return qx.html.Location.getClientBoxBottom(el) + qx.html.Style.getMarginBottom(el); } + + +qx.html.Location.getClientBoxLeft = function(el) {} +qx.html.Location.getClientBoxTop = function(el) {} +qx.html.Location.getClientBoxRight = function(el) {} +qx.html.Location.getClientBoxBottom = function(el) {} +qx.html.Location.getPageBoxLeft = function(el) {} +qx.html.Location.getPageBoxTop = function(el) {} +qx.html.Location.getPageBoxRight = function(el) {} +qx.html.Location.getPageBoxBottom = function(el) {} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Location.getClientBoxLeft = function(el) { return el.getBoundingClientRect().left; } + qx.html.Location.getClientBoxTop = function(el) { return el.getBoundingClientRect().top; } + + qx.html.Location.getPageBoxLeft = function(el) { return qx.html.Location.getClientBoxLeft(el) + qx.html.Scroll.getLeftSum(el); } + qx.html.Location.getPageBoxTop = function(el) { return qx.html.Location.getClientBoxTop(el) + qx.html.Scroll.getTopSum(el); } +} +else if (qx.core.Client.getInstance().isGecko()) +{ + qx.html.Location.getClientBoxLeft = function(el) { return qx.html.Location.getClientAreaLeft(el) - qx.html.Style.getBorderLeft(el); } + qx.html.Location.getClientBoxTop = function(el) { return qx.html.Location.getClientAreaTop(el) - qx.html.Style.getBorderTop(el); } + + qx.html.Location.getPageBoxLeft = function(el) { return qx.html.Location.getPageAreaLeft(el) - qx.html.Style.getBorderLeft(el); } + qx.html.Location.getPageBoxTop = function(el) { return qx.html.Location.getPageAreaTop(el) - qx.html.Style.getBorderTop(el); } +} +else +{ + qx.html.Location.getPageBoxLeft = function(el) + { + var sum = el.offsetLeft; + while (el.tagName.toLowerCase() != "body") + { + el = el.offsetParent; + sum += el.offsetLeft; + } + + return sum; + } + + qx.html.Location.getPageBoxTop = function(el) + { + var sum = el.offsetTop; + while (el.tagName.toLowerCase() != "body") + { + el = el.offsetParent; + sum += el.offsetTop; + } + + return sum; + } + + qx.html.Location.getClientBoxLeft = function(el) + { + var sum = el.offsetLeft; + while (el.tagName.toLowerCase() != "body") + { + el = el.offsetParent; + sum += el.offsetLeft - el.scrollLeft; + } + + return sum; + } + + qx.html.Location.getClientBoxTop = function(el) + { + var sum = el.offsetTop; + while (el.tagName.toLowerCase() != "body") + { + el = el.offsetParent; + sum += el.offsetTop - el.scrollTop; + } + + return sum; + } +} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Location.getClientBoxRight = function(el) { return el.getBoundingClientRect().right; } + qx.html.Location.getClientBoxBottom = function(el) { return el.getBoundingClientRect().bottom; } + + qx.html.Location.getPageBoxRight = function(el) { return qx.html.Location.getClientBoxRight(el) + qx.html.Scroll.getLeftSum(el); } + qx.html.Location.getPageBoxBottom = function(el) { return qx.html.Location.getClientBoxBottom(el) + qx.html.Scroll.getTopSum(el); } +} +else +{ + qx.html.Location.getClientBoxRight = function(el) { return qx.html.Location.getClientBoxLeft(el) + qx.html.Dimension.getBoxWidth(el); } + qx.html.Location.getClientBoxBottom = function(el) { return qx.html.Location.getClientBoxTop(el) + qx.html.Dimension.getBoxHeight(el); } + + qx.html.Location.getPageBoxRight = function(el) { return qx.html.Location.getPageBoxLeft(el) + qx.html.Dimension.getBoxWidth(el); } + qx.html.Location.getPageBoxBottom = function(el) { return qx.html.Location.getPageBoxTop(el) + qx.html.Dimension.getBoxHeight(el); } +} + + +qx.html.Location.getClientAreaLeft = function(el) {}; +qx.html.Location.getClientAreaTop = function(el) {}; +qx.html.Location.getPageAreaLeft = function(el) {}; +qx.html.Location.getPageAreaTop = function(el) {}; + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.html.Location.getPageAreaLeft = function(el) { + return el.ownerDocument.getBoxObjectFor(el).x; + } + + qx.html.Location.getPageAreaTop = function(el) { + return el.ownerDocument.getBoxObjectFor(el).y; + } + + // We need to subtract the scroll position of all parent containers (bug #186229). + qx.html.Location.getClientAreaLeft = function(el) { + return qx.html.Location.getPageAreaLeft(el) - qx.html.Scroll.getLeftSum(el); + } + + // We need to subtract the scroll position of all parent containers (bug #186229). + qx.html.Location.getClientAreaTop = function(el) { + return qx.html.Location.getPageAreaTop(el) - qx.html.Scroll.getTopSum(el); + } +} +else +{ + qx.html.Location.getClientAreaLeft = function(el) { return qx.html.Location.getClientBoxLeft(el) + qx.html.Style.getBorderLeft(el); } + qx.html.Location.getClientAreaTop = function(el) { return qx.html.Location.getClientBoxTop(el) + qx.html.Style.getBorderTop(el); } + + qx.html.Location.getPageAreaLeft = function(el) { return qx.html.Location.getPageBoxLeft(el) + qx.html.Style.getBorderLeft(el); } + qx.html.Location.getPageAreaTop = function(el) { return qx.html.Location.getPageBoxTop(el) + qx.html.Style.getBorderTop(el); } +} + + + +qx.html.Location.getClientAreaRight = function(el) { return qx.html.Location.getClientAreaLeft(el) + qx.html.Dimension.getAreaWidth(el); } +qx.html.Location.getClientAreaBottom = function(el) { return qx.html.Location.getClientAreaTop(el) + qx.html.Dimension.getAreaHeight(el); } + +qx.html.Location.getPageAreaRight = function(el) { return qx.html.Location.getPageAreaLeft(el) + qx.html.Dimension.getAreaWidth(el); } +qx.html.Location.getPageAreaBottom = function(el) { return qx.html.Location.getPageAreaTop(el) + qx.html.Dimension.getAreaHeight(el); } + + + + +qx.html.Location.getClientInnerLeft = function(el) { return qx.html.Location.getClientAreaLeft(el) + qx.html.Style.getPaddingLeft(el); } +qx.html.Location.getClientInnerTop = function(el) { return qx.html.Location.getClientAreaTop(el) + qx.html.Style.getPaddingTop(el); } +qx.html.Location.getClientInnerRight = function(el) { return qx.html.Location.getClientInnerLeft(el) + qx.html.Dimension.getInnerWidth(el); } +qx.html.Location.getClientInnerBottom = function(el) { return qx.html.Location.getClientInnerTop(el) + qx.html.Dimension.getInnerHeight(el); } + +qx.html.Location.getPageInnerLeft = function(el) { return qx.html.Location.getPageAreaLeft(el) + qx.html.Style.getPaddingLeft(el); } +qx.html.Location.getPageInnerTop = function(el) { return qx.html.Location.getPageAreaTop(el) + qx.html.Style.getPaddingTop(el); } +qx.html.Location.getPageInnerRight = function(el) { return qx.html.Location.getPageInnerLeft(el) + qx.html.Dimension.getInnerWidth(el); } +qx.html.Location.getPageInnerBottom = function(el) { return qx.html.Location.getPageInnerTop(el) + qx.html.Dimension.getInnerHeight(el); } + + +// Screen +qx.html.Location.getScreenBoxLeft = function(el) {}; +qx.html.Location.getScreenBoxTop = function(el) {}; + +if (qx.core.Client.getInstance().isGecko()) +{ + /* + screenX and screenY seem to return the distance to the box + and not to the area. Confusing, especially as the x and y properties + of the BoxObject return the distance to the area. + */ + + qx.html.Location.getScreenBoxLeft = function(el) + { + // We need to subtract the scroll position of all + // parent containers (bug #186229). + var sum = 0; + var p = el.parentNode; + while (p.nodeType == 1) { + sum += p.scrollLeft; + p = p.parentNode; + } + + return el.ownerDocument.getBoxObjectFor(el).screenX - sum; + } + + qx.html.Location.getScreenBoxTop = function(el) + { + // We need to subtract the scroll position of all + // parent containers (bug #186229). + var sum = 0; + var p = el.parentNode; + while (p.nodeType == 1) { + sum += p.scrollTop; + p = p.parentNode; + } + + return el.ownerDocument.getBoxObjectFor(el).screenY - sum; + } +} +else +{ + // Hope this works in khtml, too (opera 7.6p3 seems to be ok) + qx.html.Location.getScreenBoxLeft = function(el) { return qx.html.Location.getScreenDocumentLeft(el) + qx.html.Location.getPageBoxLeft(el); } + qx.html.Location.getScreenBoxTop = function(el) { return qx.html.Location.getScreenDocumentTop(el) + qx.html.Location.getPageBoxTop(el); } +} + +qx.html.Location.getScreenBoxRight = function(el) { return qx.html.Location.getScreenBoxLeft(el) + qx.html.Dimension.getBoxWidth(el); } +qx.html.Location.getScreenBoxBottom = function(el) { return qx.html.Location.getScreenBoxTop(el) + qx.html.Dimension.getBoxHeight(el); } + +qx.html.Location.getScreenOuterLeft = function(el) { return qx.html.Location.getScreenBoxLeft(el) - qx.html.Style.getMarginLeft(el); } +qx.html.Location.getScreenOuterTop = function(el) { return qx.html.Location.getScreenBoxTop(el) - qx.html.Style.getMarginTop(el); } +qx.html.Location.getScreenOuterRight = function(el) { return qx.html.Location.getScreenBoxRight(el) + qx.html.Style.getMarginRight(el); } +qx.html.Location.getScreenOuterBottom = function(el) { return qx.html.Location.getScreenBoxBottom(el) + qx.html.Style.getMarginBottom(el); } + +qx.html.Location.getScreenAreaLeft = function(el) { return qx.html.Location.getScreenBoxLeft(el) + qx.html.Dimension.getInsetLeft(el); } +qx.html.Location.getScreenAreaTop = function(el) { return qx.html.Location.getScreenBoxTop(el) + qx.html.Dimension.getInsetTop(el); } +qx.html.Location.getScreenAreaRight = function(el) { return qx.html.Location.getScreenBoxRight(el) - qx.html.Dimension.getInsetRight(el); } +qx.html.Location.getScreenAreaBottom = function(el) { return qx.html.Location.getScreenBoxBottom(el) - qx.html.Dimension.getInsetBottom(el); } + +qx.html.Location.getScreenInnerLeft = function(el) { return qx.html.Location.getScreenAreaLeft(el) + qx.html.Style.getPaddingLeft(el); } +qx.html.Location.getScreenInnerTop = function(el) { return qx.html.Location.getScreenAreaTop(el) + qx.html.Style.getPaddingTop(el); } +qx.html.Location.getScreenInnerRight = function(el) { return qx.html.Location.getScreenAreaRight(el) - qx.html.Style.getPaddingRight(el); } +qx.html.Location.getScreenInnerBottom = function(el) { return qx.html.Location.getScreenAreaBottom(el) - qx.html.Style.getPaddingBottom(el); } + + +qx.html.Location.getScreenDocumentLeft = function(el) {}; +qx.html.Location.getScreenDocumentTop = function(el) {}; +qx.html.Location.getScreenDocumentRight = function(el) {}; +qx.html.Location.getScreenDocumentBottom = function(el) {}; + +if (qx.core.Client.getInstance().isGecko()) +{ + /* + Notice: + This doesn't work like the mshtml method: + el.ownerDocument.defaultView.screenX; + */ + + // Tested in Gecko 1.7.5 + qx.html.Location.getScreenDocumentLeft = function(el) { return qx.html.Location.getScreenOuterLeft(el.ownerDocument.body); } + qx.html.Location.getScreenDocumentTop = function(el) { return qx.html.Location.getScreenOuterTop(el.ownerDocument.body); } + qx.html.Location.getScreenDocumentRight = function(el) { return qx.html.Location.getScreenOuterRight(el.ownerDocument.body); } + qx.html.Location.getScreenDocumentBottom = function(el) { return qx.html.Location.getScreenOuterBottom(el.ownerDocument.body); } +} +else +{ + // Tested in Opera 7.6b3 and Mshtml 6.0 (XP-SP2) + // What's up with khtml (Safari/Konq)? + qx.html.Location.getScreenDocumentLeft = function(el) { return el.document.parentWindow.screenLeft; } + qx.html.Location.getScreenDocumentTop = function(el) { return el.document.parentWindow.screenTop; } + qx.html.Location.getScreenDocumentRight = function(el) {} + qx.html.Location.getScreenDocumentBottom = function(el) {} +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Offset.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Offset.js new file mode 100644 index 0000000000..e39631a9c4 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Offset.js @@ -0,0 +1,125 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Offset"); + +/* +Mozilla seems to be a little buggy here. +Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 + +It calculates some borders and/or paddings to the offsetProperties. +*/ + +qx.html.Offset.getLeft = function(vElement) {}; +qx.html.Offset.getTop = function(vElement) {}; + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.html.Offset.getLeft = function(el) + { + var val = el.offsetLeft; + var pa = el.parentNode; + + var pose = qx.html.Style.getStyleProperty(el, "position"); + var posp = qx.html.Style.getStyleProperty(pa, "position"); + + // If element is positioned non-static: Substract the border of the element + if (pose != "absolute" && pose != "fixed") { + val -= qx.html.Style.getBorderLeft(pa); + } + + // If parent is positioned static: Substract the border of the first + // parent element which is ab positioned non-static. + if (posp != "absolute" && posp != "fixed") + { + while(pa) + { + pa = pa.parentNode; + + if (!pa || typeof pa.tagName !== "string") { + break; + } + + var posi = qx.html.Style.getStyleProperty(pa, "position"); + + if (posi == "absolute" || posi == "fixed") { + val -= qx.html.Style.getBorderLeft(pa) + qx.html.Style.getPaddingLeft(pa); + break; + } + } + } + + return val; + } + + qx.html.Offset.getTop = function(el) + { + var val = el.offsetTop; + var pa = el.parentNode; + + var pose = qx.html.Style.getStyleProperty(el, "position"); + var posp = qx.html.Style.getStyleProperty(pa, "position"); + + // If element is positioned non-static: Substract the border of the element + if (pose != "absolute" && pose != "fixed") { + val -= qx.html.Style.getBorderTop(pa); + } + + // If parent is positioned static: Substract the border of the first + // parent element which is ab positioned non-static. + if (posp != "absolute" && posp != "fixed") + { + while(pa) + { + pa = pa.parentNode; + + if (!pa || typeof pa.tagName !== "string") { + break; + } + + var posi = qx.html.Style.getStyleProperty(pa, "position"); + + if (posi == "absolute" || posi == "fixed") { + val -= qx.html.Style.getBorderTop(pa) + qx.html.Style.getPaddingTop(pa); + break; + } + } + } + + return val; + } +} +else +{ + qx.html.Offset.getLeft = function(el) { + return el.offsetLeft; + } + + qx.html.Offset.getTop = function(el) { + return el.offsetTop; + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Scroll.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Scroll.js new file mode 100644 index 0000000000..afcd59f6d6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Scroll.js @@ -0,0 +1,55 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Scroll"); + +qx.html.Scroll.getLeftSum = function(el) +{ + var sum = 0; + var p = el.parentNode; + + while (p.nodeType == 1) + { + sum += p.scrollLeft; + p = p.parentNode; + } + + return sum; +} + +qx.html.Scroll.getTopSum = function(el) +{ + var sum = 0; + var p = el.parentNode; + + while (p.nodeType == 1) + { + sum += p.scrollTop; + p = p.parentNode; + } + + return sum; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ScrollIntoView.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ScrollIntoView.js new file mode 100644 index 0000000000..bb01b7658d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/ScrollIntoView.js @@ -0,0 +1,197 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.html.Style) + +************************************************************************ */ + +/** + * Functions to scroll DOM elements into the visible area of the parent element + */ +qx.OO.defineClass("qx.html.ScrollIntoView"); + +// Internet Explorer has invented scrollIntoView, but does not behave the same like in Mozilla (which would be better) +// Mozilla has a native well working method scrollIntoView +// Safari does not support scrollIntoView (but it can be found in Webkit since May 2005) +// Opera does not support scrollIntoView + +/** the documents body tag name */ +qx.dom.BODY_TAG_NAME = "body"; + + +/** + * Scroll the parent DOM element so that the element's so that the x coordinate is inside + * the visible area of the parent. + * + * @param vElement {Element} DOM node to be scrolled into view + * @param vAlignLeft {Boolean} whether the element should be left aligned + */ +qx.html.ScrollIntoView.scrollX = function(vElement, vAlignLeft) +{ + var vParentWidth, vParentScrollLeft, vWidth, vHasScroll; + + var vParent = vElement.parentNode; + var vOffset = vElement.offsetLeft; + var vWidth = vElement.offsetWidth; + + while(vParent) + { + switch(qx.html.Style.getStyleProperty(vParent, "overflow")) + { + case "scroll": + case "auto": + case "-moz-scrollbars-horizontal": + vHasScroll = true; + break; + + default: + switch(qx.html.Style.getStyleProperty(vParent, "overflowX")) + { + case "scroll": + case "auto": + vHasScroll = true; + break; + + default: + vHasScroll = false; + } + } + + if (vHasScroll) + { + vParentWidth = vParent.clientWidth; + vParentScrollLeft = vParent.scrollLeft; + + if (vAlignLeft) + { + vParent.scrollLeft = vOffset; + } + else if (vAlignLeft == false) + { + vParent.scrollLeft = vOffset + vWidth - vParentWidth; + } + else if (vWidth > vParentWidth || vOffset < vParentScrollLeft) + { + vParent.scrollLeft = vOffset; + } + else if ((vOffset + vWidth) > (vParentScrollLeft + vParentWidth)) + { + vParent.scrollLeft = vOffset + vWidth - vParentWidth; + } + + vOffset = vParent.offsetLeft; + vWidth = vParent.offsetWidth; + } + else + { + vOffset += vParent.offsetLeft; + } + + if (vParent.tagName.toLowerCase() == qx.dom.BODY_TAG_NAME) { + break; + } + + vParent = vParent.parentNode; + } + + return true; +} + + +/** + * Scroll the parent DOM element so that the element's so that the y coordinate is inside + * the visible area of the parent. + * + * @param vElement {Element} DOM node to be scrolled into view + * @param vAlignTop {Boolean} whether the element should be top aligned + */ +qx.html.ScrollIntoView.scrollY = function(vElement, vAlignTop) +{ + var vParentHeight, vParentScrollTop, vHeight, vHasScroll; + + var vParent = vElement.parentNode; + var vOffset = vElement.offsetTop; + var vHeight = vElement.offsetHeight; + + while(vParent) + { + switch(qx.html.Style.getStyleProperty(vParent, "overflow")) + { + case "scroll": + case "auto": + case "-moz-scrollbars-vertical": + vHasScroll = true; + break; + + default: + switch(qx.html.Style.getStyleProperty(vParent, "overflowY")) + { + case "scroll": + case "auto": + vHasScroll = true; + break; + + default: + vHasScroll = false; + } + } + + if (vHasScroll) + { + vParentHeight = vParent.clientHeight; + vParentScrollTop = vParent.scrollTop; + + if (vAlignTop) + { + vParent.scrollTop = vOffset; + } + else if (vAlignTop == false) + { + vParent.scrollTop = vOffset + vHeight - vParentHeight; + } + else if (vHeight > vParentHeight || vOffset < vParentScrollTop) + { + vParent.scrollTop = vOffset; + } + else if ((vOffset + vHeight) > (vParentScrollTop + vParentHeight)) + { + vParent.scrollTop = vOffset + vHeight - vParentHeight; + } + + vOffset = vParent.offsetTop; + vHeight = vParent.offsetHeight; + } + else + { + vOffset += vParent.offsetTop; + } + + if (vParent.tagName.toLowerCase() == qx.dom.BODY_TAG_NAME) { + break; + } + + vParent = vParent.parentNode; + } + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/String.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/String.js new file mode 100644 index 0000000000..b2664ecb6e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/String.js @@ -0,0 +1,123 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.lang.Object) + +************************************************************************ */ + +/** + * A Collection of utility functions to escape and unescape strings. + */ +qx.OO.defineClass("qx.html.String"); + + +/** + * Escapes the characters in a <code>String</code> using HTML entities. + * + * For example: <tt>"bread" & "butter"</tt> => <tt>&quot;bread&quot; &amp; &quot;butter&quot;</tt>. + * Supports all known HTML 4.0 entities, including funky accents. + * + * * <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a> + * * <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a> + * * <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a> + * * <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a> + * + * @see #unescape + * + * @param str {String} the String to escape + * @return {String} a new escaped String + */ +qx.Class.escape = function(str) { + return qx.dom.String.escapeEntities( + str, + qx.html.Entity.FROM_CHARCODE + ); +}; + + +/** + * Unescapes a string containing entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. Supports HTML 4.0 entities. + * + * For example, the string "&lt;Fran&ccedil;ais&gt;" + * will become "<Français>" + * + * If an entity is unrecognized, it is left alone, and inserted + * verbatim into the result string. e.g. "&gt;&zzzz;x" will + * become ">&zzzz;x". + * + * @see #escape + * + * @param str {String} the String to unescape, may be null + * @return a new unescaped String + */ +qx.Class.unescape = function(str) { + return qx.dom.String.unescapeEntities( + str, + qx.html.Entity.TO_CHARCODE + ); +}; + + +/** + * Converts a plain text string into HTML. + * This is similar to {@link #escape} but converts new lines to + * <tt><:br>:</tt> and preserves whitespaces. + * + * @see #escape + * + * @param str {String} the String to convert + * @return {String} a new converted String + */ +qx.Class.fromText = function(str) { + return qx.html.String.escape(str).replace(/( |\n)/g, function(chr) { + var map = { + " ": " ", + "\n": "<br>" + } + return map[chr] || chr; + }); +} + + +/** + * Converts HTML to plain text. + * + * * Strips all HTML tags + * * converts <tt><:br>:</tt> to new line + * * unescapes HTML entities + * + * @param str {String} HTML string to converts + * @return {String} plain text representaion of the HTML string + */ +qx.Class.toText = function(str) { + return qx.html.String.unescape(str.replace(/\s+|<([^>])+>/gi, function(chr) { + if (/\s+/.test(chr)) { + return " "; + } + else if (/^<BR|^<br/gi.test(chr)) { + return "\n"; + } else { + return ""; + } + })); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Style.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Style.js new file mode 100644 index 0000000000..9ab7847f97 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Style.js @@ -0,0 +1,228 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.core.Client) + +************************************************************************ */ + +/** + * Methods to get CSS style properties of DOM elements. + */ +qx.OO.defineClass("qx.html.Style"); + +/** + * TODO + */ +qx.html.Style.getStylePropertySure = function(vElement, propertyName) {}; + +/** + * Get the (CSS) style property of a given DOM element + * + * @param vElement {Element} the DOM element + * @param propertyName {String} the name of the style property. e.g. "color", "border", ... + * @return {String} the (CSS) style property + */ +qx.html.Style.getStyleProperty = function(vElement, propertyName) {}; + +if (Boolean(document.defaultView) && Boolean(document.defaultView.getComputedStyle)) +{ + qx.html.Style.getStylePropertySure = function(el, prop) { return !el ? null : el.ownerDocument ? el.ownerDocument.defaultView.getComputedStyle(el, "")[prop] : el.style[prop]; } + + qx.html.Style.getStyleProperty = function(el, prop) + { + try + { + return el.ownerDocument.defaultView.getComputedStyle(el, "")[prop]; + } + catch(ex) + { + throw new Error("Could not evaluate computed style: " + el + "[" + prop + "]: " + ex); + } + } +} +else if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Style.getStyleProperty = function(el, prop) + { + try + { + return el.currentStyle[prop]; + } + catch(ex) + { + throw new Error("Could not evaluate computed style: " + el + "[" + prop + "]: " + ex); + } + } + + qx.html.Style.getStylePropertySure = function(el, prop) + { + try + { + if (!el) { + return null; + } + + if (el.parentNode && el.currentStyle) + { + return el.currentStyle[prop]; + } + else + { + var v1 = el.runtimeStyle[prop]; + + if (v1 != null && typeof v1 != "undefined" && v1 != "") { + return v1; + } + + return el.style[prop]; + } + } + catch(ex) + { + throw new Error("Could not evaluate computed style: " + el + "[" + prop + "]: " + ex); + } + } +} +else +{ + qx.html.Style.getStylePropertySure = function(el, prop) { return !el ? null : el.style[prop]; } + + qx.html.Style.getStyleProperty = function(el, prop) + { + try + { + return el.style[prop]; + } + catch(ex) + { + throw new Error("Could not evaluate computed style: " + el + "[" + prop + "]"); + } + } +} + +/** + * Get a (CSS) style property of a given DOM element and interpret the property as integer value + * + * @param vElement {Element} the DOM element + * @param propertyName {String} the name of the style property. e.g. "paddingTop", "marginLeft", ... + * @return {Integer} the (CSS) style property converted to an integer value + */ +qx.html.Style.getStyleSize = function(vElement, propertyName) { return parseInt(qx.html.Style.getStyleProperty(vElement, propertyName)) || 0; } + + +// Properties +/** + * Get the element's left margin. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's left margin size + */ +qx.html.Style.getMarginLeft = function(vElement) { return qx.html.Style.getStyleSize(vElement, "marginLeft"); } + +/** + * Get the element's top margin. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's top margin size + */ +qx.html.Style.getMarginTop = function(vElement) { return qx.html.Style.getStyleSize(vElement, "marginTop"); } + +/** + * Get the element's right margin. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's right margin size + */ +qx.html.Style.getMarginRight = function(vElement) { return qx.html.Style.getStyleSize(vElement, "marginRight"); } + +/** + * Get the element's bottom margin. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's bottom margin size + */ +qx.html.Style.getMarginBottom = function(vElement) { return qx.html.Style.getStyleSize(vElement, "marginBottom"); } + +/** + * Get the element's left padding. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's left padding size + */ +qx.html.Style.getPaddingLeft = function(vElement) { return qx.html.Style.getStyleSize(vElement, "paddingLeft"); } + +/** + * Get the element's top padding. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's top padding size + */ +qx.html.Style.getPaddingTop = function(vElement) { return qx.html.Style.getStyleSize(vElement, "paddingTop"); } + +/** + * Get the element's right padding. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's right padding size + */ +qx.html.Style.getPaddingRight = function(vElement) { return qx.html.Style.getStyleSize(vElement, "paddingRight"); } + +/** + * Get the element's bottom padding. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's bottom padding size + */ +qx.html.Style.getPaddingBottom = function(vElement) { return qx.html.Style.getStyleSize(vElement, "paddingBottom"); } + +/** + * Get the element's left border width. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's left border width + */ +qx.html.Style.getBorderLeft = function(vElement) { return qx.html.Style.getStyleProperty(vElement, "borderLeftStyle") == "none" ? 0 : qx.html.Style.getStyleSize(vElement, "borderLeftWidth"); } + +/** + * Get the element's top border width. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's top border width + */ +qx.html.Style.getBorderTop = function(vElement) { return qx.html.Style.getStyleProperty(vElement, "borderTopStyle") == "none" ? 0 : qx.html.Style.getStyleSize(vElement, "borderTopWidth"); } + +/** + * Get the element's right border width. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's right border width + */ +qx.html.Style.getBorderRight = function(vElement) { return qx.html.Style.getStyleProperty(vElement, "borderRightStyle") == "none" ? 0 : qx.html.Style.getStyleSize(vElement, "borderRightWidth"); } + +/** + * Get the element's bottom border width. + * + * @param vElement {Element} the DOM element + * @return {Integer} the element's bottom border width + */ +qx.html.Style.getBorderBottom = function(vElement) { return qx.html.Style.getStyleProperty(vElement, "borderBottomStyle") == "none" ? 0 : qx.html.Style.getStyleSize(vElement, "borderBottomWidth"); } diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/StyleSheet.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/StyleSheet.js new file mode 100644 index 0000000000..c2fdcc0189 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/StyleSheet.js @@ -0,0 +1,325 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Andreas Junghans (lucidcake) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.StyleSheet"); + +/** + * Include a CSS file + * + * @param vHref {String} Href value + */ +qx.html.StyleSheet.includeFile = function(vHref) +{ + var el = document.createElement("link"); + el.type = "text/css"; + el.rel = "stylesheet"; + el.href = vHref; + + var head = document.getElementsByTagName("head")[0]; + head.appendChild(el); +}; + +/** + * create a new Stylesheet node and append it to the document + * + * @param vCssText {String} optional string of css rules + */ +qx.html.StyleSheet.createElement = function(vCssText) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.createElement = function(vCssText) + { + var vSheet = document.createStyleSheet(); + + if (vCssText) { + vSheet.cssText = vCssText; + } + + return vSheet; + }; +} +else // FF, Opera, Safari +{ + qx.html.StyleSheet.createElement = function(vCssText) + { + var vElement = document.createElement("style"); + vElement.type = "text/css"; + + // Safari 2.0 doesn't like empty stylesheets + vElement.appendChild(document.createTextNode(vCssText || "body {}")); + + document.getElementsByTagName("head")[0].appendChild(vElement); + + if (vElement.sheet) { + return vElement.sheet; + } else { + // Safari 2.0 doesn't support element.sheet so we neet a workaround + var styles = document.styleSheets; + for (var i=styles.length-1; i>=0; i--) { + if (styles[i].ownerNode == vElement) { + return styles[i]; + } + } + } + throw "Error: Could not get a reference to the sheet object"; + }; +} + + +/** + * insert a new CSS rule into a given Stylesheet + * + * @param vSheet {Object} the target Stylesheet object + * @param vSelector {String} the selector + * @param vStyle {String} style rule + */ +qx.html.StyleSheet.addRule = function(vSheet, vSelector, vStyle) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.addRule = function(vSheet, vSelector, vStyle) { + vSheet.addRule(vSelector, vStyle); + }; +} +else if (qx.core.Client.getInstance().isSafari2()) // insertRule in Safari 2 doesn't work +{ + qx.html.StyleSheet.addRule = function(vSheet, vSelector, vStyle) { + if (!vSheet._qxRules) { + vSheet._qxRules = {}; + } + if (!vSheet._qxRules[vSelector]) { + var ruleNode = document.createTextNode(vSelector + "{" + vStyle + "}"); + vSheet.ownerNode.appendChild(ruleNode); + vSheet._qxRules[vSelector] = ruleNode; + } + }; +} +else // FF, Opera +{ + qx.html.StyleSheet.addRule = function(vSheet, vSelector, vStyle) { + vSheet.insertRule(vSelector + "{" + vStyle + "}", vSheet.cssRules.length); + }; +} + + +/** + * remove a CSS rule from a stylesheet + * + * @param vSheet {Object} the Stylesheet + * @param vSelector {String} the Selector of the rule to remove + */ +qx.html.StyleSheet.removeRule = function(vSheet, vSelector) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.removeRule = function(vSheet, vSelector) + { + var vRules = vSheet.rules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) + { + if (vRules[i].selectorText == vSelector) { + vSheet.removeRule(i); + } + } + }; +} +else if (qx.core.Client.getInstance().isSafari2()) // removeRule in Safari 2 doesn't work +{ + qx.html.StyleSheet.removeRule = function(vSheet, vSelector) + { + var warn = function() { + qx.log.Logger.ROOT_LOGGER.warn("In Safari/Webkit you can only remove rules that are created using qx.html.StyleSheet.addRule"); + } + if (!vSheet._qxRules) { + warn(); + } + var ruleNode = vSheet._qxRules[vSelector]; + if (ruleNode) { + vSheet.ownerNode.removeChild(ruleNode); + vSheet._qxRules[vSelector] = null; + } else { + warn(); + } + }; +} +else +{ + qx.html.StyleSheet.removeRule = function(vSheet, vSelector) + { + var vRules = vSheet.cssRules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) + { + if (vRules[i].selectorText == vSelector) { + vSheet.deleteRule(i); + } + } + }; +} + + +/** + * remove all CSS rules from a stylesheet + * + * @param vSheet {Object} the stylesheet object + */ +qx.html.StyleSheet.removeAllRules = function(vSheet) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.removeAllRules = function(vSheet) + { + var vRules = vSheet.rules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) { + vSheet.removeRule(i); + } + }; +} +else if (qx.core.Client.getInstance().isSafari2()) // removeRule in Safari 2 doesn't work +{ + qx.html.StyleSheet.removeAllRules = function(vSheet) + { + var node = vSheet.ownerNode; + var rules = node.childNodes; + while (rules.length > 0) { + node.removeChild(rules[0]); + } + }; +} +else // FF, etc +{ + qx.html.StyleSheet.removeAllRules = function(vSheet) + { + var vRules = vSheet.cssRules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) { + vSheet.deleteRule(i); + } + }; +} + + + +// TODO import functions are not working crossbrowser (Safari) !! +// see CSS_1.html test + +/** + * add an import of an external CSS file to a stylesheet + * @param vSheet {Object} the stylesheet object + * @param vUrl {String} URL of the external stylesheet file + */ +qx.html.StyleSheet.addImport = function(vSheet, vUrl) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.addImport = function(vSheet, vUrl) { + vSheet.addImport(vUrl); + }; +} +else if (qx.core.Client.getInstance().isSafari2()) // insertRule in Safari 2 doesn't work +{ + qx.html.StyleSheet.addImport = function(vSheet, vUrl) { + vSheet.ownerNode.appendChild(document.createTextNode('@import "' + vUrl + '";')); + }; +} +else // FF, etc +{ + qx.html.StyleSheet.addImport = function(vSheet, vUrl) { + vSheet.insertRule('@import "' + vUrl + '";', vSheet.cssRules.length); + }; +} + + +/** + * removes an import from a stylesheet + * + * @param vSheet {Object} the stylesheet object + * @param vUrl {String} URL of the importet CSS file + */ +qx.html.StyleSheet.removeImport = function(vSheet, vUrl) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.removeImport = function(vSheet, vUrl) { + var vImports = vSheet.imports; + var vLength = vImports.length; + + for (var i=vLength-1; i>=0; i--) { + if (vImports[i].href == vUrl) { + vSheet.removeImport(i); + } + } + }; +} +else // FF, etc +{ + qx.html.StyleSheet.removeImport = function(vSheet, vUrl) { + var vRules = vSheet.cssRules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) { + if (vRules[i].href == vUrl) { + vSheet.deleteRule(i); + } + } + }; +} + + +/** + * remove all imports from a stylesheet + * + * @param vSheet {Object} the stylesheet object + */ +qx.html.StyleSheet.removeAllImports = function(vSheet) {}; +if (document.createStyleSheet) // IE 4+ +{ + qx.html.StyleSheet.removeAllImports = function(vSheet) { + var vImports = vSheet.imports; + var vLength = vImports.length; + + for (var i=vLength-1; i>=0; i--) { + vSheet.removeImport(i); + } + }; +} +else // FF, etc +{ + qx.html.StyleSheet.removeAllImports = function(vSheet) { + var vRules = vSheet.cssRules; + var vLength = vRules.length; + + for (var i=vLength-1; i>=0; i--) { + if (vRules[i].type == vRules[i].IMPORT_RULE) { + vSheet.deleteRule(i); + } + } + }; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Textile.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Textile.js new file mode 100644 index 0000000000..ceaccd3ed0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Textile.js @@ -0,0 +1,178 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Optimized version of SuperTextile + */ +qx.OO.defineClass("qx.html.Textile"); + +/** + * Textilizes a string + * http://www.creatimation.net/journal/textile-live-preview (offline) + * + * @param s {String} Text to be textilized. + * @return {String} The textilized text. + */ +qx.html.Textile.textilize = function(s) +{ + var r = s; + + // quick tags first + var qtags = [ + ["\\*", "strong"], + ["\\?\\?", "cite"], + ["\\+", "ins"], + ["~", "sub"], + ["\\^", "sup"], + ["@", "code"] + ]; + + var ttag, htag, re, line, lines, nr, changed, inlist, listtype; + + for (var i=0;i<qtags.length;i++) { + ttag = qtags[i][0]; htag = qtags[i][1]; + re = new RegExp(ttag+"\\b(.+?)\\b"+ttag,"g"); + r = r.replace(re,"<"+htag+">"+"$1"+"</"+htag+">"); + } + + // underscores count as part of a word, so do them separately + re = new RegExp("\\b_(.+?)_\\b","g"); + r = r.replace(re,"<em>$1</em>"); + + // jeff: so do dashes + re = new RegExp("[\s\n]-(.+?)-[\s\n]","g"); + r = r.replace(re,"<del>$1</del>"); + + // links + re = new RegExp('"\\b(.+?)\\(\\b(.+?)\\b\\)":([^\\s]+)','g'); + r = r.replace(re,'<a href="$3" title="$2">$1</a>'); + re = new RegExp('"\\b(.+?)\\b":([^\\s]+)','g'); + r = r.replace(re,'<a href="$2">$1</a>'); + + // images + re = new RegExp("!\\b(.+?)\\(\\b(.+?)\\b\\)!","g"); + r = r.replace(re,'<img src="$1" alt="$2">'); + re = new RegExp("!\\b(.+?)\\b!","g"); + r = r.replace(re,'<img src="$1">'); + + // block level formatting + + // Jeff's hack to show single line breaks as they should. + // insert breaks - but you get some....stupid ones + re = new RegExp("(.*)\n([^#\*\n].*)","g"); + r = r.replace(re,"$1<br />$2"); + + // remove the stupid breaks. + re = new RegExp("\n<br />","g"); + r = r.replace(re,"\n"); + + lines = r.split("\n"); + nr = ""; + + for (var i=0;i<lines.length;i++) + { + line = lines[i].replace(/\s*$/,""); + changed = 0; + + if (line.search(/^\s*bq\.\s+/) != -1) + { + line = line.replace(/^\s*bq\.\s+/,"\t<blockquote>")+"</blockquote>"; + changed = 1; + } + + // jeff adds h#. + if (line.search(/^\s*h[1-6]\.\s+/) != -1) + { + re = new RegExp("h([1-6])\.(.+)","g"); + line = line.replace(re,"<h$1>$2</h$1>"); + changed = 1; + } + + if (line.search(/^\s*\*\s+/) != -1) + { + // for bullet list; make up an liu tag to be fixed later + line = line.replace(/^\s*\*\s+/,"\t<liu>") + "</liu>"; + changed = 1; + } + + if (line.search(/^\s*#\s+/) != -1) + { + // # for numeric list; make up an lio tag to be fixed later + line = line.replace(/^\s*#\s+/,"\t<lio>") + "</lio>"; + changed = 1; + } + + if (!changed && (line.replace(/\s/g,"").length > 0)) + { + line = "<p>"+line+"</p>"; + } + + lines[i] = line + "\n"; + } + + // Second pass to do lists + inlist = 0; + listtype = ""; + + for (var i=0;i<lines.length;i++) + { + line = lines[i]; + + if (inlist && listtype == "ul" && !line.match(/^\t<liu/)) + { + line = "</ul>\n" + line; + inlist = 0; + } + + if (inlist && listtype == "ol" && !line.match(/^\t<lio/)) + { + line = "</ol>\n" + line; + inlist = 0; + } + + if (!inlist && line.match(/^\t<liu/)) + { + line = "<ul>" + line; + inlist = 1; + listtype = "ul"; + } + + if (!inlist && line.match(/^\t<lio/)) + { + line = "<ol>" + line; + inlist = 1; + listtype = "ol"; + } + + lines[i] = line; + } + + r = lines.join("\n"); + + // jeff added : will correctly replace <li(o|u)> AND </li(o|u)> + r = r.replace(/li[o|u]>/g, "li>"); + + return r; +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Window.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Window.js new file mode 100644 index 0000000000..71f6520da9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/html/Window.js @@ -0,0 +1,138 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.core.Client) + +************************************************************************ */ + +qx.OO.defineClass("qx.html.Window"); + + +/** + * Get the inner width of the given browser window + * + * @param window {window} browser window + * @return {Integer} the window's inner width + */ +qx.html.Window.getInnerWidth = function(window) {}; + +/** + * Get the inner height of the given browser window + * + * @param window {window} browser window + * @return {Integer} the window's inner height + */ +qx.html.Window.getInnerHeight = function(window) {}; + +/** + * Get the left scroll position of the given browser window + * + * @param window {window} browser window + * @return {Integer} the window's left scroll position + */ +qx.html.Window.getScrollLeft = function(window) {}; + +/** + * Get the top scroll position of the given browser window + * + * @param window {window} browser window + * @return {Integer} the window's top scroll position + */ +qx.html.Window.getScrollTop = function(window) {}; + + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.html.Window.getInnerWidth = function(w) + { + if (w.document.documentElement && w.document.documentElement.clientWidth) + { + return w.document.documentElement.clientWidth; + } + else if (w.document.body) + { + return w.document.body.clientWidth; + } + + return 0; + } + + qx.html.Window.getInnerHeight = function(w) + { + if (w.document.documentElement && w.document.documentElement.clientHeight) + { + return w.document.documentElement.clientHeight; + } + else if (w.document.body) + { + return w.document.body.clientHeight; + } + + return 0; + } + + qx.html.Window.getScrollLeft = function(w) + { + if (w.document.documentElement && w.document.documentElement.scrollLeft) + { + return w.document.documentElement.scrollLeft; + } + else if (w.document.body) + { + return w.document.body.scrollTop; + } + + return 0; + } + + qx.html.Window.getScrollTop = function(w) + { + if (w.document.documentElement && w.document.documentElement.scrollTop) + { + return w.document.documentElement.scrollTop; + } + else if (w.document.body) + { + return w.document.body.scrollTop; + } + + return 0; + } +} +else +{ + qx.html.Window.getInnerWidth = function(w) { + return w.innerWidth; + } + + qx.html.Window.getInnerHeight = function(w) { + return w.innerHeight; + } + + qx.html.Window.getScrollLeft = function(w) { + return w.document.body.scrollLeft; + } + + qx.html.Window.getScrollTop = function(w) { + return w.document.body.scrollTop; + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/Json.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/Json.js new file mode 100644 index 0000000000..1a966defe5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/Json.js @@ -0,0 +1,404 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 STZ-IDA, Germany, http://www.stz-ida.de + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Andreas Junghans (lucidcake) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + + +/* +Copyright (c) 2005 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + + +/** + * This is a slightly modified JSON implementation that supports Dates and + * treats undefined like null. + */ + +qx.OO.defineClass("qx.io.Json"); + +/** + * Stringify a JavaScript value, producing a JSON text. + * + * @param v {var} the object to serialize. + * @param beautify {Boolean ? false} whether to beautify the serialized string + * by adding some white space that indents objects and arrays. + * @return {String} the serialized object. + */ +qx.Class.stringify = function (v, beautify) {}; + +/** + * Parse a JSON text, producing a JavaScript value. + * It returns false if there is a syntax error. + * + * @param text {String} JSON string + * @return {var} evaluated JSON string. + */ +qx.Class.parse = function (text) {}; + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("encodeUndefined", true); +qx.Settings.setDefault("enableDebug", false); + + + + + +/* +--------------------------------------------------------------------------- + IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.io.Json = function () +{ + var m = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + s = { + 'boolean': function (x) { + return String(x); + }, + + number: function (x) { + return isFinite(x) ? String(x) : 'null'; + }, + + string: function (x) { + if (/["\\\x00-\x1f]/.test(x)) { + x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) { + var c = m[b]; + if (c) { + return c; + } + c = b.charCodeAt(); + return '\\u00' + + Math.floor(c / 16).toString(16) + + (c % 16).toString(16); + }); + } + return '"' + x + '"'; + }, + + object: function (x) { + if (x) { + var a = [], b, f, i, l, v; + if (x instanceof Array) { + var beautify = qx.io.Json._beautify; + a[0] = '['; + if (beautify) { + qx.io.Json._indent += qx.io.Json.BEAUTIFYING_INDENT; + a.push(qx.io.Json._indent); + } + l = x.length; + for (i = 0; i < l; i += 1) { + v = x[i]; + f = s[typeof v]; + if (f) { + v = f(v); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + if (beautify) { + a.push(qx.io.Json._indent); + } + } + a[a.length] = v; + b = true; + } + } + } + if (beautify) { + qx.io.Json._indent = qx.io.Json._indent.substring(0, qx.io.Json._indent.length - qx.io.Json.BEAUTIFYING_INDENT.length); + a.push(qx.io.Json._indent); + } + a[a.length] = ']'; + // AJ, DJL -- + } else if (x instanceof Date) { + /* + * The Date object is a primitive type in Javascript, + * but the Javascript specification neglects to provide + * a literal form for it. The only way to generate a + * Date object is with "new Date()". For fast + * processing by Javascript, we want to be able to + * eval() a JSON response. If Date objects are to be + * passed to the client using JSON, about the only + * reasonable way to do it is to have "new Date()" + * in the JSON message. See this page for a proposal to + * add a Date literal syntax to Javascript which, + * if/when implemented in Javascript, would eliminate + * the need to pass "new Date() in JSON": + * + * http://www.hikhilk.net/DateSyntaxForJSON.aspx + * + * Sending a JSON message from client to server, we have + * no idea what language the server will be written in, + * what size integers it supports, etc. We do want to + * be able to represent as large a range of dates as + * possible, though. If we were to send the number of + * milliseconds since the beginning of the epoch, the + * value would exceed, in many cases, what can fit in a + * 32-bit integer. Even if one were to simply strip off + * the last three digits (milliseconds), the number of + * seconds could exceed a 32-bit signed integer's range + * with very distant past or distant future dates. To + * make it easier for any generic server to handle a + * date without risk of loss of precision due to + * automatic type casting, we'll send a UTC date with + * separated fields, in the form: + * + * new Date(Date.UTC(year,month,day,hour,min,sec,ms)) + * + * The server can fairly easily parse this in its JSON + * implementation by stripping off "new Date(Date.UTC(" + * from the beginning of the string, and "))" from the + * end of the string. What remains is the set of + * comma-separated date components, which are also very + * easy to parse. + * + * The server should send this same format to the + * client, which can simply eval() it just as with the + * remainder of JSON. + * + * A requirement of the implementation of the server is + * that after a date has been sent from the client to + * the server, converted by the server into whatever + * native type the date will be stored or manipulated + * in, convered back to JSON, and received back at the + * client, a comparison of the sent and received Date + * object should yield identity. This means that even + * if the server does not natively operate on + * milliseconds, it must maintain milliseconds in dates + * sent to it by the client. + */ + var dateParams = + x.getUTCFullYear() + "," + + x.getUTCMonth() + "," + + x.getUTCDate() + "," + + x.getUTCHours() + "," + + x.getUTCMinutes() + "," + + x.getUTCSeconds() + "," + + x.getUTCMilliseconds(); + return "new Date(Date.UTC(" + dateParams + "))"; + // -- AJ, DJL + } else if (x instanceof Object) { + var beautify = qx.io.Json._beautify; + a[0] = '{'; + if (beautify) { + qx.io.Json._indent += qx.io.Json.BEAUTIFYING_INDENT; + a.push(qx.io.Json._indent); + } + for (i in x) { + v = x[i]; + f = s[typeof v]; + if (f) { + v = f(v); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + if (beautify) { + a.push(qx.io.Json._indent); + } + } + a.push(s.string(i), ':', v); + b = true; + } + } + } + if (beautify) { + qx.io.Json._indent = qx.io.Json._indent.substring(0, qx.io.Json._indent.length - qx.io.Json.BEAUTIFYING_INDENT.length); + a.push(qx.io.Json._indent); + } + a[a.length] = '}'; + } else { + return; + } + return a.join(''); + } + return 'null'; + }, + + // AJ, DJL -- + undefined: function(x) { + if (qx.Settings.getValueOfClass("qx.io.Json", "encodeUndefined")) + return 'null'; + } + // -- AJ, DJL + } + + return { + copyright: '(c)2005 JSON.org', + license: 'http://www.JSON.org/license.html', + + /** + * Stringify a JavaScript value, producing a JSON text. + * + * @param v {var} the object to serialize. + * @param beautify {Boolean ? false} whether to beautify the serialized string + * by adding some white space that indents objects and arrays. + * @return {String} the serialized object. + */ + stringify: function (v, beautify) { + this._beautify = beautify; + this._indent = this.BEAUTIFYING_LINE_END; + + var f = s[typeof v]; + // AJ, DJL -- + var ret = null; + // -- AJ, DJL + if (f) { + v = f(v); + if (typeof v == 'string') { + // DJL -- + ret = v; + // -- DJL + } + } + + // DJL -- + if (qx.Settings.getValueOfClass("qx.io.Json", "enableDebug")) { + var logger = qx.log.Logger.getClassLogger(qx.core.Object); + logger.debug("JSON request: " + ret); + } + + return ret; + // -- DJL + }, +/* + Parse a JSON text, producing a JavaScript value. + It returns false if there is a syntax error. +*/ + parse: function (text) { + try { + return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( + text.replace(/"(\\.|[^"\\])*"/g, ''))) && + eval('(' + text + ')'); + } catch (e) { + return false; + } + } + } +}(); + + +///* +// * Recursively descend through an object looking for any class hints. Right +// * now, the only class hint we support is 'Date' which can not be easily sent +// * from javascript to an arbitrary (e.g. PHP) JSON-RPC server and back again +// * without truncation or modification. +// */ +//qx.io.Json._fixObj = function(obj) { +// /* If there's a class hint... */ +// if (obj.__jsonclass__) +// { +// /* ... then check for supported classes. We support only Date. */ +// if (obj.__jsonclass__ == "Date" && obj.secSinceEpoch && obj.msAdditional) +// { +// /* Found a Date. Replace class hint object with a Date object. */ +// obj = new Date((obj.secSinceEpoch * 1000) + obj.msAdditional); +// return obj; +// } +// } +// +// /* +// * It wasn't something with a supported class hint, so recursively descend +// */ +// for (var member in obj) { +// thisObj = obj[member]; +// if (typeof thisObj == 'object' && thisObj !== null) { +// obj[member] = qx.io.Json._fixObj(thisObj); +// } +// } +// +// return obj; +//} + + +/** + * Parse a JSON text, producing a JavaScript value. + * It triggers an exception if there is a syntax error. + * + * @param text {String} JSON string + * @return {var} evaluated JSON string. + */ +qx.io.Json.parseQx = function(text) { + /* Convert the result text into a result primitive or object */ + + if (qx.Settings.getValueOfClass("qx.io.Json", "enableDebug")) { + var logger = qx.log.Logger.getClassLogger(qx.core.Object); + logger.debug("JSON response: " + text); + } + + var obj = (text && text.length > 0) ? eval('(' + text + ')') : null; + +// /* +// * Something like this fixObj() call may be used later when we want to +// * support class hints. For now, ignore that code +// */ +// +// /* If it's an object, not null, and contains a "result" field.. */ +// if (typeof obj == 'object' && obj !== null && obj.result) { +// /* ... then 'fix' the result by handling any supported class hints */ +// obj.result = qx.io.Json._fixObj(obj.result); +// } + + return obj; +} + +/** indent string for JSON pretty printing */ +qx.io.Json.BEAUTIFYING_INDENT = " "; + +/** new line string for JSON pretty printing */ +qx.io.Json.BEAUTIFYING_LINE_END = "\n"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/Preloader.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/Preloader.js new file mode 100644 index 0000000000..1a3a450fca --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/Preloader.js @@ -0,0 +1,199 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/** + * This is the preloader used from qx.ui.basic.Image instances. + * + * @event load {qx.event.type.Event} + * @event error {qx.event.type.Event} + */ +qx.OO.defineClass("qx.io.image.Preloader", qx.core.Target, +function(vSource) +{ + if(qx.manager.object.ImagePreloaderManager.getInstance().has(vSource)) + { + this.debug("Reuse qx.io.image.Preloader in old-style!"); + this.debug("Please use qx.manager.object.ImagePreloaderManager.getInstance().create(source) instead!"); + + return qx.manager.object.ImagePreloaderManager.getInstance().get(vSource); + } + + qx.core.Target.call(this); + + // Create Image-Node + // Does not work with document.createElement("img") in Webkit. Interesting. + // Compare this to the bug in qx.ui.basic.Image. + this._element = new Image; + + // This is needed for wrapping event to the object + this._element.qx_ImagePreloader = this; + + // Define handler if image events occurs + if (qx.core.Client.getInstance().isWebkit()) + { + // Webkit as of version 41xxx + // does not get the target right. We need to help out a bit + // ugly closure! + var self = this; + this._element.onload = function(e) { + return self._onload(e); + }; + this._element.onerror = function(e) { + return self._onerror(e); + }; + } + else + { + this._element.onload = qx.io.image.Preloader.__onload; + this._element.onerror = qx.io.image.Preloader.__onerror; + } + + // Set Source + this._source = vSource; + this._element.src = vSource; + + // Set PNG State + if (qx.core.Client.getInstance().isMshtml()) { + this._isPng = /\.png$/i.test(this._element.nameProp); + } + + qx.manager.object.ImagePreloaderManager.getInstance().add(this); +}); + + + + +/* +--------------------------------------------------------------------------- + STATE MANAGERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._source = null; +qx.Proto._isLoaded = false; +qx.Proto._isErroneous = false; + + + + + +/* +--------------------------------------------------------------------------- + CROSSBROWSER GETTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getUri = function() { return this._source; }; +qx.Proto.getSource = function() { return this._source; }; +qx.Proto.isLoaded = function() { return this._isLoaded; }; +qx.Proto.isErroneous = function() { return this._isErroneous; }; + +// only used in mshtml: true when the image format is in png +qx.Proto._isPng = false; +qx.Proto.getIsPng = function() { return this._isPng; }; + +if(qx.core.Client.getInstance().isGecko()) +{ + qx.Proto.getWidth = function() { return this._element.naturalWidth; }; + qx.Proto.getHeight = function() { return this._element.naturalHeight; }; +} +else +{ + qx.Proto.getWidth = function() { return this._element.width; }; + qx.Proto.getHeight = function() { return this._element.height; }; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT MAPPING +--------------------------------------------------------------------------- +*/ + +qx.io.image.Preloader.__onload = function(e) { this.qx_ImagePreloader._onload(); }; +qx.io.image.Preloader.__onerror = function(e) { this.qx_ImagePreloader._onerror(); }; + +qx.Proto._onload = function() +{ + if (this._isLoaded || this._isErroneous) { + return; + } + + this._isLoaded = true; + this._isErroneous = false; + + if (this.hasEventListeners("load")) { + this.dispatchEvent(new qx.event.type.Event("load"), true); + } +} + +qx.Proto._onerror = function() +{ + if (this._isLoaded || this._isErroneous) { + return; + } + + this.debug("Could not load: " + this._source); + + this._isLoaded = false; + this._isErroneous = true; + + if (this.hasEventListeners("error")) { + this.dispatchEvent(new qx.event.type.Event("error"), true); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + if (this._element) + { + this._element.onload = this._element.onerror = null; + this._element.qx_ImagePreloader = null; + this._element = null; + } + + this._isLoaded = this._isErroneous = this._isPng = false; + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/PreloaderSystem.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/PreloaderSystem.js new file mode 100755 index 0000000000..bf18ceb259 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/image/PreloaderSystem.js @@ -0,0 +1,189 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/** + * @event completed {qx.event.type.Event} + */ +qx.OO.defineClass("qx.io.image.PreloaderSystem", qx.core.Target, +function(vPreloadList, vCallBack, vCallBackScope) +{ + qx.core.Target.call(this); + + this._list = vPreloadList; + + // Create timer + this._timer = new qx.client.Timer(this.getSetting("timeout")); + this._timer.addEventListener("interval", this._oninterval, this); + + // If we use the compact syntax, automatically add an event listeners and start the loading process + if (vCallBack) + { + this.addEventListener("completed", vCallBack, vCallBackScope || null); + this.start(); + } +}); + +qx.Proto._stopped = false; + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("timeout", 3000); + + + + + +/* +--------------------------------------------------------------------------- + USER ACCESS +--------------------------------------------------------------------------- +*/ + +qx.Proto.start = function() +{ + if (qx.lang.Object.isEmpty(this._list)) + { + this.createDispatchEvent("completed"); + return; + } + + for (var vSource in this._list) + { + var vPreloader = qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(vSource)); + + if (vPreloader.isErroneous() || vPreloader.isLoaded()) + { + delete this._list[vSource]; + } + else + { + vPreloader._origSource = vSource; + + vPreloader.addEventListener("load", this._onload, this); + vPreloader.addEventListener("error", this._onerror, this); + } + } + + // Initial check + this._check(); +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onload = function(e) +{ + delete this._list[e.getTarget()._origSource]; + this._check(); +} + +qx.Proto._onerror = function(e) +{ + delete this._list[e.getTarget()._origSource]; + this._check(); +} + +qx.Proto._oninterval = function(e) +{ + this.error("Could not preload: " + qx.lang.Object.getKeysAsString(this._list)); + + this._stopped = true; + this._timer.stop(); + + this.createDispatchEvent("completed"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CHECK +--------------------------------------------------------------------------- +*/ + +qx.Proto._check = function() +{ + if (this._stopped) { + return; + } + + // this.debug("Check: " + qx.lang.Object.getKeysAsString(this._list)); + + if (qx.lang.Object.isEmpty(this._list)) + { + this._timer.stop(); + this.createDispatchEvent("completed"); + } + else + { + // Restart timer for timeout + this._timer.restart(); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + this._list = null; + + if (this._timer) + { + this._timer.dispose(); + this._timer = null; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieApi.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieApi.js new file mode 100755 index 0000000000..c5ebad3f04 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieApi.js @@ -0,0 +1,141 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.io.local.CookieApi", +{ + STR_EXPIRES : "expires", + STR_PATH : "path", + STR_DOMAIN : "domain", + STR_SECURE : "secure", + STR_DELDATA : "Thu, 01-Jan-1970 00:00:01 GMT" +}); + + + + + +/* +--------------------------------------------------------------------------- + USER APPLICATION METHODS +--------------------------------------------------------------------------- +*/ + +qx.Class.get = function(vName) +{ + var start = document.cookie.indexOf(vName + "="); + var len = start + vName.length + 1; + + if ((!start) && (vName != document.cookie.substring(0, vName.length))) { + return null; + } + + if (start == -1) { + return null; + } + + var end = document.cookie.indexOf(";", len); + + if (end == -1) { + end = document.cookie.length; + } + + return unescape(document.cookie.substring(len, end)); +} + +qx.Class.set = function(vName, vValue, vExpires, vPath, vDomain, vSecure) +{ + var today = new Date(); + today.setTime(today.getTime()); + + // Generate cookie + var vCookie = [ vName, "=", escape(vValue) ]; + + if (vExpires) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_EXPIRES); + vCookie.push("="); + vCookie.push(new Date(today.getTime() + (vExpires * 1000 * 60 * 60 * 24)).toGMTString()); + } + + if (vPath) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_PATH); + vCookie.push("="); + vCookie.push(vPath); + } + + if (vDomain) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_DOMAIN); + vCookie.push("="); + vCookie.push(vDomain); + } + + if (vSecure) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_SECURE); + } + + // Store cookie + document.cookie = vCookie.join(""); +} + +qx.Class.del = function(vName, vPath, vDomain) +{ + if (!qx.io.local.CookieApi.get(vName)) { + return; + } + + // Generate cookie + var vCookie = [ vName, "=" ]; + + if (vPath) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_PATH); + vCookie.push("="); + vCookie.push(vPath); + } + + if (vDomain) + { + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_DOMAIN); + vCookie.push("="); + vCookie.push(vDomain); + } + + vCookie.push(";"); + vCookie.push(qx.io.local.CookieApi.STR_EXPIRES); + vCookie.push("="); + vCookie.push(qx.io.local.CookieApi.STR_DELDATA); + + // Store cookie + document.cookie = vCookie.join(""); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieTransport.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieTransport.js new file mode 100755 index 0000000000..46a07cfa02 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/local/CookieTransport.js @@ -0,0 +1,178 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.io.local.CookieTransport", +{ + BASENAME : "qx", + ITEMSEPARATOR : "&", + KEYVALUESEPARATOR : "=", + MAXCOOKIES : 20, + MAXSIZE : 4096 +}); + + + + + +/* +--------------------------------------------------------------------------- + USER APPLICATION METHODS +--------------------------------------------------------------------------- +*/ + +qx.Class.set = function(vName, vValue) +{ + if (vValue === undefined) { + return qx.io.local.CookieTransport.del(vName); + } + + var vAll = qx.io.local.CookieTransport._getAll(); + vAll[vName] = vValue; + this._setAll(vAll); +} + +qx.Class.get = function(vName) +{ + var vAll = qx.io.local.CookieTransport._getAll(); + + return vAll[vName] || ""; +} + +qx.Class.del = function(vName) +{ + var vAll = qx.io.local.CookieTransport._getAll(); + delete vAll[vName]; + this._setAll(vAll); +} + +qx.Class.setAll = function(vHash) +{ + var vAll = qx.io.local.CookieTransport._getAll(); + vAll = qx.lang.Object.mergeWith(vAll, vHash); + qx.io.local.CookieTransport._setAll(vAll); +} + +qx.Class.getAll = function() { + return qx.io.local.CookieTransport._getAll(); +} + +qx.Class.replaceAll = function(vHash) { + qx.io.local.CookieTransport._setAll(vHash); +} + +qx.Class.delAll = function() { + qx.io.local.CookieTransport.replaceAll({}); +} + + + + + +/* +--------------------------------------------------------------------------- + LOW LEVEL INTERNAL METHODS +--------------------------------------------------------------------------- +*/ + +qx.Class._getAll = function() +{ + var vHash = {}; + var vCookie, vItems, vItem; + + for (var i=0; i<qx.io.local.CookieTransport.MAXCOOKIES; i++) + { + vCookie = qx.io.local.CookieApi.get(qx.io.local.CookieTransport.BASENAME + i); + if (vCookie) + { + vItems = vCookie.split(qx.io.local.CookieTransport.ITEMSEPARATOR); + for (var j=0, l=vItems.length; j<l; j++) + { + vItem = vItems[j].split(qx.io.local.CookieTransport.KEYVALUESEPARATOR); + vHash[vItem[0]] = vItem[1]; + } + } + } + + return vHash; +} + +qx.Class._setAll = function(vHash) +{ + var vString = ""; + var vTemp; + var vIndex = 0; + + for (var vName in vHash) + { + vTemp = vName + qx.io.local.CookieTransport.KEYVALUESEPARATOR + vHash[vName]; + + if (vTemp.length > qx.io.local.CookieTransport.MAXSIZE) + { + qx.log.Logger.getClassLogger(qx.io.local.CookieTransport).debug("Could not store value of name '" + vName + "': Maximum size of " + qx.io.local.CookieTransport.MAXSIZE + "reached!"); + continue; + } + + if ((qx.io.local.CookieTransport.ITEMSEPARATOR.length + vString.length + vTemp.length) > qx.io.local.CookieTransport.MAXSIZE) + { + qx.io.local.CookieTransport._setCookie(vIndex++, vString); + + if (vIndex == qx.io.local.CookieTransport.MAXCOOKIES) + { + qx.log.Logger.getClassLogger(qx.io.local.CookieTransport).debug("Failed to store cookie. Max cookie amount reached!", "error"); + return false; + } + + vString = vTemp; + } + else + { + if (vString != "") { + vString += qx.io.local.CookieTransport.ITEMSEPARATOR; + } + + vString += vTemp; + } + } + + if (vString != "") { + qx.io.local.CookieTransport._setCookie(vIndex++, vString); + } + + while (vIndex < qx.io.local.CookieTransport.MAXCOOKIES) { + qx.io.local.CookieTransport._delCookie(vIndex++); + } +} + +qx.Class._setCookie = function(vIndex, vString) +{ + // qx.log.Logger.getClassLogger(qx.io.local.CookieTransport).debug("Store: " + vIndex + " = " + vString); + qx.io.local.CookieApi.set(qx.io.local.CookieTransport.BASENAME + vIndex, vString); +} + +qx.Class._delCookie = function(vIndex) +{ + // qx.log.Logger.getClassLogger(qx.io.local.CookieTransport).debug("Delete: " + vIndex); + qx.io.local.CookieApi.del(qx.io.local.CookieTransport.BASENAME + vIndex); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/AbstractRemoteTransport.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/AbstractRemoteTransport.js new file mode 100644 index 0000000000..00be49a5dd --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/AbstractRemoteTransport.js @@ -0,0 +1,330 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + +/** + * @event created {qx.event.type.Event} + * @event configured {qx.event.type.Event} + * @event sending {qx.event.type.Event} + * @event receiving {qx.event.type.Event} + * @event completed {qx.event.type.Event} + * @event aborted {qx.event.type.Event} + * @event failed {qx.event.type.Event} + * @event timeout {qx.event.type.Event} + */ +qx.OO.defineClass("qx.io.remote.AbstractRemoteTransport", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Target url to issue the request to +*/ +qx.OO.addProperty({ name : "url", type : "string" }); + +/*! + Determines what type of request to issue +*/ +qx.OO.addProperty({ name : "method", type : "string" }); + +/*! + Set the request to asynchronous +*/ +qx.OO.addProperty({ name : "asynchronous", type : "boolean" }); + +/*! + Set the data to be sent via this request +*/ +qx.OO.addProperty({ name : "data", type : "string" }); + +/*! + Username to use for HTTP authentication +*/ +qx.OO.addProperty({ name : "username", type : "string" }); + +/*! + Password to use for HTTP authentication +*/ +qx.OO.addProperty({ name : "password", type : "string" }); + +/*! + The state of the current request +*/ +qx.OO.addProperty( +{ + name : "state", + type : "string", + possibleValues : [ + "created", "configured", + "sending", "receiving", + "completed", "aborted", + "timeout", "failed" + ], + defaultValue : "created" +}); + +/*! + Request headers +*/ +qx.OO.addProperty({ name : "requestHeaders", type: "object" }); + +/*! + Request parameters to send. +*/ +qx.OO.addProperty({ name : "parameters", type: "object" }); + +/*! + Response Type +*/ +qx.OO.addProperty({ name : "responseType", type: "string" }); + +/*! + Use Basic HTTP Authentication +*/ +qx.OO.addProperty({ name : "useBasicHttpAuth", type : "boolean" }); + + + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.send = function() { + throw new Error("send is abstract"); +} + +qx.Proto.abort = function() +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Aborting..."); + } + + this.setState("aborted"); +} + +/*! + +*/ +qx.Proto.timeout = function() +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Timeout..."); + } + + this.setState("timeout"); +} + +/*! + + Force the transport into the failed state ("failed"). + + Listeners of the "failed" signal are notified about the event. +*/ +qx.Proto.failed = function() +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Failed..."); + } + + this.setState("failed"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + REQUEST HEADER SUPPORT +--------------------------------------------------------------------------- +*/ +/*! + Add a request header to this transports qx.io.remote.Request. + + This method is virtual and concrete subclasses are supposed to + implement it. +*/ +qx.Proto.setRequestHeader = function(vLabel, vValue) { + throw new Error("setRequestHeader is abstract"); +} + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getResponseHeader = function(vLabel) { + throw new Error("getResponseHeader is abstract"); +} + +/*! + Provides an hash of all response headers. +*/ +qx.Proto.getResponseHeaders = function() { + throw new Error("getResponseHeaders is abstract"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + STATUS SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns the current status code of the request if available or -1 if not. +*/ +qx.Proto.getStatusCode = function() { + throw new Error("getStatusCode is abstract"); +} + +/*! + Provides the status text for the current request if available and null otherwise. +*/ +qx.Proto.getStatusText = function() { + throw new Error("getStatusText is abstract"); +} + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE DATA SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Provides the response text from the request when available and null otherwise. + By passing true as the "partial" parameter of this method, incomplete data will + be made available to the caller. +*/ +qx.Proto.getResponseText = function() { + throw new Error("getResponseText is abstract"); +} + +/*! + Provides the XML provided by the response if any and null otherwise. + By passing true as the "partial" parameter of this method, incomplete data will + be made available to the caller. +*/ +qx.Proto.getResponseXml = function() { + throw new Error("getResponseXml is abstract"); +} + +/*! + Returns the length of the content as fetched thus far +*/ +qx.Proto.getFetchedLength = function() { + throw new Error("getFetchedLength is abstract"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyState = function(propValue, propOldValue, propData) +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("State: " + propValue); + } + + switch(propValue) + { + case "created": + this.createDispatchEvent("created"); + break; + + case "configured": + this.createDispatchEvent("configured"); + break; + + case "sending": + this.createDispatchEvent("sending"); + break; + + case "receiving": + this.createDispatchEvent("receiving"); + break; + + case "completed": + this.createDispatchEvent("completed"); + break; + + case "aborted": + this.createDispatchEvent("aborted"); + break; + + case "failed": + this.createDispatchEvent("failed"); + break; + + case "timeout": + this.createDispatchEvent("timeout"); + break; + } + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Exchange.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Exchange.js new file mode 100644 index 0000000000..4487498b9d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Exchange.js @@ -0,0 +1,706 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + * Andreas Junghans (lucidcake) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + +/** + * @event sending {qx.event.type.Event} + * @event receiving {qx.event.type.Event} + * @event completed {qx.event.type.Event} + * @event aborted {qx.event.type.Event} + * @event timeout {qx.event.type.Event} + * @event failed {qx.event.type.Event} + */ +qx.OO.defineClass("qx.io.remote.Exchange", qx.core.Target, +function(vRequest) +{ + qx.core.Target.call(this); + + this.setRequest(vRequest); + vRequest.setTransport(this); +}); + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableDebug", false); + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + TRANSPORT TYPE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.io.remote.Exchange.typesOrder = [ "qx.io.remote.XmlHttpTransport", "qx.io.remote.IframeTransport", "qx.io.remote.ScriptTransport" ]; + +qx.io.remote.Exchange.typesReady = false; + +qx.io.remote.Exchange.typesAvailable = {}; +qx.io.remote.Exchange.typesSupported = {}; + +qx.io.remote.Exchange.registerType = function(vClass, vId) { + qx.io.remote.Exchange.typesAvailable[vId] = vClass; +} + +qx.io.remote.Exchange.initTypes = function() +{ + if (qx.io.remote.Exchange.typesReady) { + return; + } + + for (var vId in qx.io.remote.Exchange.typesAvailable) + { + var vTransporterImpl = qx.io.remote.Exchange.typesAvailable[vId]; + + if (vTransporterImpl.isSupported()) { + qx.io.remote.Exchange.typesSupported[vId] = vTransporterImpl; + } + } + + qx.io.remote.Exchange.typesReady = true; + + if (qx.lang.Object.isEmpty(qx.io.remote.Exchange.typesSupported)) { + throw new Error("No supported transport types were found!"); + } +} + +qx.io.remote.Exchange.canHandle = function(vImpl, vNeeds, vResponseType) +{ + if (!qx.lang.Array.contains(vImpl.handles.responseTypes, vResponseType)) { + return false; + } + + for (var vKey in vNeeds) + { + if (!vImpl.handles[vKey]) { + return false; + } + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + MAPPING +--------------------------------------------------------------------------- +*/ + +/* +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp + +0: UNINITIALIZED +The object has been created, but not initialized (the open method has not been called). + +1: LOADING +The object has been created, but the send method has not been called. + +2: LOADED +The send method has been called, but the status and headers are not yet available. + +3: INTERACTIVE +Some data has been received. Calling the responseBody and responseText properties at this state to obtain partial results will return an error, because status and response headers are not fully available. + +4: COMPLETED +All the data has been received, and the complete data is available in the +*/ + +qx.io.remote.Exchange._nativeMap = +{ + 0 : "created", + 1 : "configured", + 2 : "sending", + 3 : "receiving", + 4 : "completed" +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILS +--------------------------------------------------------------------------- +*/ + +qx.io.remote.Exchange.wasSuccessful = function(vStatusCode, vReadyState, vIsLocal) +{ + if (vIsLocal) + { + switch(vStatusCode) + { + case null: + case 0: + return true; + + case -1: + // Not Available (OK for readystates: MSXML<4=1-3, MSXML>3=1-2, Gecko=1) + return vReadyState < 4; + + default: + // at least older versions of Safari don't set the status code for local file access + return typeof vStatusCode === "undefined"; + } + } + else + { + switch(vStatusCode) + { + case -1: // Not Available (OK for readystates: MSXML<4=1-3, MSXML>3=1-2, Gecko=1) + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug") && vReadyState > 3) { + qx.log.Logger.getClassLogger(qx.io.remote.Exchange).debug("Failed with statuscode: -1 at readyState " + vReadyState); + } + + return vReadyState < 4; + + + case 200: // OK + case 304: // Not Modified + return true; + + + case 201: // Created + case 202: // Accepted + case 203: // Non-Authoritative Information + case 204: // No Content + case 205: // Reset Content + return true; + + + case 206: // Partial Content + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug") && vReadyState === 4) { + qx.log.Logger.getClassLogger(qx.io.remote.Exchange).debug("Failed with statuscode: 206 (Partial content while being complete!)"); + } + + return vReadyState !== 4; + + + case 300: // Multiple Choices + case 301: // Moved Permanently + case 302: // Moved Temporarily + case 303: // See Other + case 305: // Use Proxy + case 400: // Bad Request + case 401: // Unauthorized + case 402: // Payment Required + case 403: // Forbidden + case 404: // Not Found + case 405: // Method Not Allowed + case 406: // Not Acceptable + case 407: // Proxy Authentication Required + case 408: // Request Time-Out + case 409: // Conflict + case 410: // Gone + case 411: // Length Required + case 412: // Precondition Failed + case 413: // Request Entity Too Large + case 414: // Request-URL Too Large + case 415: // Unsupported Media Type + case 500: // Server Error + case 501: // Not Implemented + case 502: // Bad Gateway + case 503: // Out of Resources + case 504: // Gateway Time-Out + case 505: // HTTP Version not supported + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + qx.log.Logger.getClassLogger(qx.io.remote.Exchange).debug("Failed with typical HTTP statuscode: " + vStatusCode); + } + + return false; + + + // The following case labels are wininet.dll error codes that may be encountered. + // Server timeout + case 12002: + // 12029 to 12031 correspond to dropped connections. + case 12029: + case 12030: + case 12031: + // Connection closed by server. + case 12152: + // See above comments for variable status. + case 13030: + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + qx.log.Logger.getClassLogger(qx.io.remote.Exchange).debug("Failed with MSHTML specific HTTP statuscode: " + vStatusCode); + } + + return false; + + + default: + // Handle all 20x status codes as OK as defined in the corresponding RFC + // http://www.w3.org/Protocols/rfc2616/rfc2616.html + if (vStatusCode > 206 && vStatusCode < 300) { + return true; + } + + qx.log.Logger.getClassLogger(qx.io.remote.Exchange).debug("Unknown status code: " + vStatusCode + " (" + vReadyState + ")"); + throw new Error("Unknown status code: " + vStatusCode); + } + } +} + + +qx.io.remote.Exchange.statusCodeToString = function(vStatusCode) +{ + switch(vStatusCode) + { + case -1: return "Not available"; + case 200: return "Ok"; + case 304: return "Not modified"; + case 206: return "Partial content"; + case 204: return "No content"; + case 300: return "Multiple choices"; + case 301: return "Moved permanently"; + case 302: return "Moved temporarily"; + case 303: return "See other"; + case 305: return "Use proxy"; + case 400: return "Bad request"; + case 401: return "Unauthorized"; + case 402: return "Payment required"; + case 403: return "Forbidden"; + case 404: return "Not found"; + case 405: return "Method not allowed"; + case 406: return "Not acceptable"; + case 407: return "Proxy authentication required"; + case 408: return "Request time-out"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 411: return "Length required"; + case 412: return "Precondition failed"; + case 413: return "Request entity too large"; + case 414: return "Request-URL too large"; + case 415: return "Unsupported media type"; + case 500: return "Server error"; + case 501: return "Not implemented"; + case 502: return "Bad gateway"; + case 503: return "Out of resources"; + case 504: return "Gateway time-out"; + case 505: return "HTTP version not supported"; + case 12002: return "Server timeout"; + case 12029: return "Connection dropped"; + case 12030: return "Connection dropped"; + case 12031: return "Connection dropped"; + case 12152: return "Connection closed by server"; + case 13030: return "MSHTML-specific HTTP status code"; + default: return "Unknown status code"; + } +} + + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Set the request to send with this transport. +*/ +qx.OO.addProperty({ name : "request", type : "object", instance : "qx.io.remote.Request" }); +/*! + Set the implementation to use to send the request with. + + The implementation should be a subclass of qx.io.remote.AbstractRemoteTransport and + must implement all methods in the transport API. +*/ +qx.OO.addProperty({ name : "implementation", type : "object" }); +qx.OO.addProperty( +{ + name : "state", + type : "string", + possibleValues : [ + "configured", "sending", + "receiving", "completed", + "aborted", "timeout", + "failed" + ], + defaultValue : "configured" +}); + + + + + + + + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.send = function() +{ + var vRequest = this.getRequest(); + + if (!vRequest) { + return this.error("Please attach a request object first"); + } + + qx.io.remote.Exchange.initTypes(); + + var vUsage = qx.io.remote.Exchange.typesOrder; + var vSupported = qx.io.remote.Exchange.typesSupported; + + // Mapping settings to contenttype and needs to check later + // if the selected transport implementation can handle + // fulfill these requirements. + var vResponseType = vRequest.getResponseType(); + var vNeeds = {}; + + if (vRequest.getAsynchronous()) { + vNeeds.asynchronous = true; + } else { + vNeeds.synchronous = true; + } + + if (vRequest.getCrossDomain()) { + vNeeds.crossDomain = true; + } + + if (vRequest.getFileUpload()) { + vNeeds.fileUpload = true; + } + + var vTransportImpl, vTransport; + for (var i=0, l=vUsage.length; i<l; i++) + { + vTransportImpl = vSupported[vUsage[i]]; + + if (vTransportImpl) + { + if (!qx.io.remote.Exchange.canHandle(vTransportImpl, vNeeds, vResponseType)) { + continue; + } + + try + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Using implementation: " + vTransportImpl.classname); + } + + vTransport = new vTransportImpl; + this.setImplementation(vTransport); + + vTransport.setUseBasicHttpAuth(vRequest.getUseBasicHttpAuth()); + + vTransport.send(); + return true; + } + catch(ex) + { + return this.error("Request handler throws error", ex); + } + } + } + + this.error("There is no transport implementation available to handle this request: " + vRequest); +} +/*! + Force the transport into the aborted ("aborted") + state. +*/ +qx.Proto.abort = function() +{ + var vImplementation = this.getImplementation(); + + if (vImplementation) + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Abort: implementation " + vImplementation.toHashCode()); + } + vImplementation.abort(); + } + else + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Abort: forcing state to be aborted"); + } + this.setState("aborted"); + } +} +/*! + Force the transport into the timeout state. +*/ +qx.Proto.timeout = function() +{ + var vImplementation = this.getImplementation(); + + if (vImplementation) + { + this.warn("Timeout: implementation " + vImplementation.toHashCode()); + vImplementation.timeout(); + } + else + { + this.warn("Timeout: forcing state to timeout"); + this.setState("timeout"); + } + + // Disable future timeouts in case user handler blocks + if (this.getRequest()) { + this.getRequest().setTimeout(0); + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onsending = function(e) { + this.setState("sending"); +} + +qx.Proto._onreceiving = function(e) { + this.setState("receiving"); +} + +qx.Proto._oncompleted = function(e) { + this.setState("completed"); +} + +qx.Proto._onabort = function(e) { + this.setState("aborted"); +} + +qx.Proto._onfailed = function(e) { + this.setState("failed"); +} + +qx.Proto._ontimeout = function(e) { + this.setState("timeout"); +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyImplementation = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + propOldValue.removeEventListener("sending", this._onsending, this); + propOldValue.removeEventListener("receiving", this._onreceiving, this); + propOldValue.removeEventListener("completed", this._oncompleted, this); + propOldValue.removeEventListener("aborted", this._onabort, this); + propOldValue.removeEventListener("timeout", this._ontimeout, this); + propOldValue.removeEventListener("failed", this._onfailed, this); + } + + if (propValue) + { + var vRequest = this.getRequest(); + + propValue.setUrl(vRequest.getUrl()); + propValue.setMethod(vRequest.getMethod()); + propValue.setAsynchronous(vRequest.getAsynchronous()); + + propValue.setUsername(vRequest.getUsername()); + propValue.setPassword(vRequest.getPassword()); + + propValue.setParameters(vRequest.getParameters()); + propValue.setRequestHeaders(vRequest.getRequestHeaders()); + propValue.setData(vRequest.getData()); + + propValue.setResponseType(vRequest.getResponseType()); + + propValue.addEventListener("sending", this._onsending, this); + propValue.addEventListener("receiving", this._onreceiving, this); + propValue.addEventListener("completed", this._oncompleted, this); + propValue.addEventListener("aborted", this._onabort, this); + propValue.addEventListener("timeout", this._ontimeout, this); + propValue.addEventListener("failed", this._onfailed, this); + } + + return true; +} + +qx.Proto._modifyState = function(propValue, propOldValue, propData) +{ + var vRequest = this.getRequest(); + + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("State: " + propOldValue + " => " + propValue); + } + + switch(propValue) + { + case "sending": + this.createDispatchEvent("sending"); + break; + + case "receiving": + this.createDispatchEvent("receiving"); + break; + + case "completed": + case "aborted": + case "timeout": + case "failed": + var vImpl = this.getImplementation(); + + if (! vImpl) { + // implementation has already been disposed + break; + } + + var vResponse = new qx.io.remote.Response; + + if (propValue == "completed") { + var vContent = vImpl.getResponseContent(); + vResponse.setContent(vContent); + + /* + * Was there acceptable content? This might occur, for example, if + * the web server was shut down unexpectedly and thus the connection + * closed with no data having been sent. + */ + if (vContent === null) { + // Nope. Change COMPLETED to FAILED. + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Altered State: " + propValue + " => failed"); + } + propValue = "failed"; + } + } + + vResponse.setStatusCode(vImpl.getStatusCode()); + vResponse.setResponseHeaders(vImpl.getResponseHeaders()); + + // this.debug("Result Text: " + vResponse.getTextContent()); + + var vEventType; + + switch(propValue) + { + case "completed": + vEventType = "completed"; + break; + + case "aborted": + vEventType = "aborted"; + break; + + case "timeout": + vEventType = "timeout"; + break; + + case "failed": + vEventType = "failed"; + break; + } + + // Disconnect and dispose implementation + this.setImplementation(null); + vImpl.dispose(); + + // Fire event to listeners + this.createDispatchDataEvent(vEventType, vResponse); + break; + } + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + var vImpl = this.getImplementation(); + if (vImpl) + { + this.setImplementation(null); + vImpl.dispose(); + } + + this.setRequest(null); + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/IframeTransport.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/IframeTransport.js new file mode 100644 index 0000000000..9e9d50c588 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/IframeTransport.js @@ -0,0 +1,476 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + * Andreas Junghans (lucidcake) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) +#require(qx.io.remote.Exchange) +#require(qx.util.Mime) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/*! + Transports requests to a server using an IFRAME. + + This class should not be used directly by client programmers. + */ +qx.OO.defineClass("qx.io.remote.IframeTransport", qx.io.remote.AbstractRemoteTransport, +function() +{ + qx.io.remote.AbstractRemoteTransport.call(this); + + var vUniqueId = (new Date).valueOf(); + var vFrameName = "frame_" + vUniqueId; + var vFormName = "form_" + vUniqueId; + + // Mshtml allows us to define a full HTML as a parameter for createElement. + // Using this method is the only (known) working to register the frame + // to the known elements of the Internet Explorer. + if (qx.core.Client.getInstance().isMshtml()) { + this._frame = document.createElement('<iframe name="' + vFrameName + '"></iframe>'); + } else { + this._frame = document.createElement("iframe"); + } + + this._frame.src = "javascript:void(0)"; + this._frame.id = this._frame.name = vFrameName; + this._frame.onload = function(e) { return o._onload(e); } + + this._frame.style.display = "none"; + + document.body.appendChild(this._frame); + + this._form = document.createElement("form"); + this._form.target = vFrameName; + this._form.id = this._form.name = vFormName; + + this._form.style.display = "none"; + + document.body.appendChild(this._form); + + this._data = document.createElement("textarea"); + this._data.id = this._data.name = "_data_"; + this._form.appendChild(this._data); + + var o = this; + this._frame.onreadystatechange = function(e) { return o._onreadystatechange(e); } +}); + +qx.Proto._lastReadyState = 0; + + + + + +/* +--------------------------------------------------------------------------- + CLASS PROPERTIES AND METHODS +--------------------------------------------------------------------------- +*/ + +// basic registration to qx.io.remote.Exchange +// the real availability check (activeX stuff and so on) follows at the first real request +qx.io.remote.Exchange.registerType(qx.io.remote.IframeTransport, "qx.io.remote.IframeTransport"); + +qx.io.remote.IframeTransport.handles = +{ + synchronous : false, + asynchronous : true, + crossDomain : false, + fileUpload: true, + responseTypes : [ qx.util.Mime.TEXT, qx.util.Mime.JAVASCRIPT, qx.util.Mime.JSON, qx.util.Mime.XML, qx.util.Mime.HTML ] +} + +qx.io.remote.IframeTransport.isSupported = function() { + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.send = function() +{ + var vMethod = this.getMethod(); + var vUrl = this.getUrl(); + + + + // -------------------------------------- + // Adding parameters + // -------------------------------------- + + var vParameters = this.getParameters(); + var vParametersList = []; + for (var vId in vParameters) { + var value = vParameters[vId]; + if (value instanceof Array) { + for (var i = 0; i < value.length; i++) { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value[i])); + } + } else { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value)); + } + } + + if (vParametersList.length > 0) { + vUrl += (vUrl.indexOf("?") >= 0 ? + "&" : "?") + vParametersList.join("&"); + } + + + + // -------------------------------------- + // Preparing form + // -------------------------------------- + + this._form.action = vUrl; + this._form.method = vMethod; + + + + // -------------------------------------- + // Sending data + // -------------------------------------- + + this._data.appendChild(document.createTextNode(this.getData())); + this._form.submit(); +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENER +--------------------------------------------------------------------------- +*/ + +// For reference: +// http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readyState_1.asp +qx.io.remote.IframeTransport._numericMap = +{ + "uninitialized" : 1, + "loading" : 2, + "loaded" : 2, + "interactive" : 3, + "complete" : 4 +} + +/*! + Converting complete state to numeric value and update state property +*/ +qx.Proto._onload = function(e) +{ + if (this._form.src) { + return; + } + + this._switchReadyState(qx.io.remote.IframeTransport._numericMap.complete); +} + +/*! + Converting named readyState to numeric value and update state property +*/ +qx.Proto._onreadystatechange = function(e) { + this._switchReadyState(qx.io.remote.IframeTransport._numericMap[this._frame.readyState]); +} + +qx.Proto._switchReadyState = function(vReadyState) +{ + // Ignoring already stopped requests + switch(this.getState()) + { + case "completed": + case "aborted": + case "failed": + case "timeout": + this.warn("Ignore Ready State Change"); + return; + } + + // Updating internal state + while (this._lastReadyState < vReadyState) { + this.setState(qx.io.remote.Exchange._nativeMap[++this._lastReadyState]); + } +} + + + + + +/* +--------------------------------------------------------------------------- + REQUEST HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.setRequestHeader = function(vLabel, vValue) +{ + // TODO + // throw new Error("setRequestHeader is abstract"); +} + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getResponseHeader = function(vLabel) +{ + return null; + + // TODO + // this.error("Need implementation", "getResponseHeader"); +} + +/*! + Provides an hash of all response headers. +*/ +qx.Proto.getResponseHeaders = function() +{ + return {} + + // TODO + // throw new Error("getResponseHeaders is abstract"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + STATUS SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns the current status code of the request if available or -1 if not. +*/ +qx.Proto.getStatusCode = function() +{ + return 200; + + // TODO + // this.error("Need implementation", "getStatusCode"); +} + +/*! + Provides the status text for the current request if available and null otherwise. +*/ +qx.Proto.getStatusText = function() +{ + return ""; + + // TODO + // this.error("Need implementation", "getStatusText"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + FRAME UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIframeWindow = function() { + return qx.html.Iframe.getWindow(this._frame); +} + +qx.Proto.getIframeDocument = function() { + return qx.html.Iframe.getDocument(this._frame); +} + +qx.Proto.getIframeBody = function() { + return qx.html.Iframe.getBody(this._frame); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE DATA SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIframeTextContent = function() +{ + var vBody = this.getIframeBody(); + + if (!vBody) { + return null; + } + + // Mshtml returns the content inside a PRE + // element if we use plain text + if (vBody.firstChild.tagName.toLowerCase() == "pre") + { + return vBody.firstChild.innerHTML; + } + else + { + return vBody.innerHTML; + } +} + +qx.Proto.getIframeHtmlContent = function() +{ + var vBody = this.getIframeBody(); + return vBody ? vBody.innerHTML : null; +} + +/*! + Returns the length of the content as fetched thus far +*/ +qx.Proto.getFetchedLength = function() +{ + return 0; + + // TODO + // throw new Error("getFetchedLength is abstract"); +} + +qx.Proto.getResponseContent = function() +{ + if (this.getState() !== "completed") + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Transfer not complete, ignoring content!"); + } + + return null; + } + + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Returning content for responseType: " + this.getResponseType()); + } + + var vText = this.getIframeTextContent(); + + switch(this.getResponseType()) + { + case qx.util.Mime.TEXT: + return vText; + break; + + case qx.util.Mime.HTML: + return this.getIframeHtmlContent(); + break; + + case qx.util.Mime.JSON: + try { + return vText && vText.length > 0 ? qx.io.Json.parseQx(vText) : null; + } catch(ex) { + return this.error("Could not execute json: (" + vText + ")", ex); + } + + case qx.util.Mime.JAVASCRIPT: + try { + return vText && vText.length > 0 ? window.eval(vText) : null; + } catch(ex) { + return this.error("Could not execute javascript: (" + vText + ")", ex); + } + + case qx.util.Mime.XML: + return this.getIframeDocument(); + + default: + this.warn("No valid responseType specified (" + this.getResponseType() + ")!"); + return null; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._frame) + { + this._frame.onload = null; + this._frame.onreadystatechange = null; + + // Reset source to a blank image for gecko + // Otherwise it will switch into a load-without-end behaviour + if (qx.core.Client.getInstance().isGecko()) { + this._frame.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + } + + // Finally remove element node + document.body.removeChild(this._frame); + + this._frame = null; + } + + if (this._form) + { + document.body.removeChild(this._form); + this._form = null; + } + + return qx.io.remote.AbstractRemoteTransport.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Request.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Request.js new file mode 100644 index 0000000000..0c8640d628 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Request.js @@ -0,0 +1,559 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) +#require(qx.net.Http) +#require(qx.util.Mime) + +************************************************************************ */ + +/** + * This class is used to send HTTP requests to the server. + * + * @event created {qx.event.type.Event} + * @event configured {qx.event.type.Event} + * @event sending {qx.event.type.Event} + * @event receiving {qx.event.type.Event} + * @event completed {qx.event.type.Event} + * @event failed {qx.event.type.Event} + * @event aborted {qx.event.type.Event} + * @event timeout {qx.event.type.Event} + * + * @param vUrl {String} Target url to issue the request to. + * @param vMethod {String} Determines that type of request to issue (GET or POST). Default is GET. + * @param vResponseType {String} The mime type of the response. Default is text/plain {@link qx.util.Mime}. + */ +qx.OO.defineClass("qx.io.remote.Request", qx.core.Target, +function(vUrl, vMethod, vResponseType) +{ + qx.core.Target.call(this); + + this._requestHeaders = {}; + this._parameters = {}; + + this.setUrl(vUrl); + this.setMethod(vMethod || qx.net.Http.METHOD_GET); + this.setResponseType(vResponseType || qx.util.Mime.TEXT); + + this.setProhibitCaching(true); + + // Prototype-Style Request Headers + this.setRequestHeader("X-Requested-With", "qooxdoo"); + this.setRequestHeader("X-Qooxdoo-Version", qx.core.Version.toString()); + + // Get the next sequence number for this request + this._seqNum = ++qx.io.remote.Request._seqNum; +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ +/*! + Target url to issue the request to. +*/ +qx.OO.addProperty({ name : "url", type : "string" }); +/*! + Determines what type of request to issue (GET or POST). +*/ +qx.OO.addProperty( +{ + name : "method", + type : "string", + possibleValues : [ + qx.net.Http.METHOD_GET, qx.net.Http.METHOD_POST, + qx.net.Http.METHOD_PUT, qx.net.Http.METHOD_HEAD, + qx.net.Http.METHOD_DELETE + ] +}); +/*! + Set the request to asynchronous. +*/ +qx.OO.addProperty({ name : "asynchronous", type : "boolean", defaultValue : true, + getAlias: "isAsynchronous" }); +/*! + Set the data to be sent via this request +*/ +qx.OO.addProperty({ name : "data", type : "string" }); +/*! + Username to use for HTTP authentication. Null if HTTP authentication + is not used. +*/ +qx.OO.addProperty({ name : "username", type : "string" }); +/*! + Password to use for HTTP authentication. Null if HTTP authentication + is not used. +*/ +qx.OO.addProperty({ name : "password", type : "string" }); +qx.OO.addProperty( +{ + name : "state", + type : "string", + possibleValues : [ + "configured", "queued", + "sending", "receiving", + "completed", "aborted", + "timeout", "failed" + ], + defaultValue : "configured" +}); +/* + Response type of request. + + The response type is a MIME type, default is text/plain. Other + supported MIME types are text/javascript, text/html, application/json, + application/xml. + + @see qx.util.Mime +*/ +qx.OO.addProperty({ + name : "responseType", + type : "string", + possibleValues : [ + qx.util.Mime.TEXT, + qx.util.Mime.JAVASCRIPT, qx.util.Mime.JSON, + qx.util.Mime.XML, qx.util.Mime.HTML + ] +}); +/*! + Number of millieseconds before the request is being timed out. + + If this property is null, the timeout for the request comes is the + qx.io.remote.RequestQueue's property defaultTimeout. +*/ +qx.OO.addProperty({ name : "timeout", type : "number" }); + +/*! + Prohibit request from being cached. + + Setting the value to true adds a parameter "nocache" to the request + with a value of the current time. Setting the value to false removes + the parameter. +*/ +qx.OO.addProperty({ name : "prohibitCaching", type : "boolean" }); +/*! + Indicate that the request is cross domain. + + A request is cross domain if the request's URL points to a host other + than the local host. This switches the concrete implementation that + is used for sending the request from qx.io.remote.XmlHttpTransport to + qx.io.remote.ScriptTransport, because only the latter can handle cross domain + requests. +*/ +qx.OO.addProperty({ name : "crossDomain", type : "boolean", defaultValue : false }); +/*! + Indicate that the request will be used for a file upload. + + The request will be used for a file upload. This switches the concrete + implementation that is used for sending the request from + qx.io.remote.XmlHttpTransport to qx.io.remote.IFrameTransport, because only + the latter can handle file uploads. +*/ +qx.OO.addProperty({ name : "fileUpload", type : "boolean", defaultValue : false }); +/*! + The transport instance used for the request. + + This is necessary to be able to abort an asynchronous request. +*/ +qx.OO.addProperty({ name : "transport", type : "object", instance : "qx.io.remote.Exchange" }); +/*! + Use Basic HTTP Authentication +*/ +qx.OO.addProperty({ name : "useBasicHttpAuth", type : "boolean" }); + + + + + + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ +/*! + Schedule this request for transport to server. + + The request is added to the singleton class qx.io.remote.RequestQueue's list of + pending requests. +*/ +qx.Proto.send = function() { + qx.io.remote.RequestQueue.getInstance().add(this); +} + +/*! + Abort sending this request. + + The request is removed from the singleton class qx.io.remote.RequestQueue's + list of pending events. If the request haven't been scheduled this + method is a noop. +*/ +qx.Proto.abort = function() { + qx.io.remote.RequestQueue.getInstance().abort(this); +} + +qx.Proto.reset = function() +{ + switch(this.getState()) + { + case "sending": + case "receiving": + this.error("Aborting already sent request!"); + // no break + + case "queued": + this.abort(); + break; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + STATE ALIASES +--------------------------------------------------------------------------- +*/ + +qx.Proto.isConfigured = function() { + return this.getState() === "configured"; +} + +qx.Proto.isQueued = function() { + return this.getState() === "queued"; +} + +qx.Proto.isSending = function() { + return this.getState() === "sending"; +} + +qx.Proto.isReceiving = function() { + return this.getState() === "receiving"; +} + +qx.Proto.isCompleted = function() { + return this.getState() === "completed"; +} + +qx.Proto.isAborted = function() { + return this.getState() === "aborted"; +} + +qx.Proto.isTimeout = function() { + return this.getState() === "timeout"; +} + +/*! + Return true if the request is in the failed state + ("failed"). +*/ +qx.Proto.isFailed = function() { + return this.getState() === "failed"; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onqueued = function(e) +{ + // Modify internal state + this.setState("queued"); + + // Bubbling up + this.dispatchEvent(e); +} + +qx.Proto._onsending = function(e) +{ + // Modify internal state + this.setState("sending"); + + // Bubbling up + this.dispatchEvent(e); +} + +qx.Proto._onreceiving = function(e) +{ + // Modify internal state + this.setState("receiving"); + + // Bubbling up + this.dispatchEvent(e); +} + +qx.Proto._oncompleted = function(e) +{ + // Modify internal state + this.setState("completed"); + + // Bubbling up + this.dispatchEvent(e); + + // Automatically dispose after event completion + this.dispose(); +} + +qx.Proto._onaborted = function(e) +{ + // Modify internal state + this.setState("aborted"); + + // Bubbling up + this.dispatchEvent(e); + + // Automatically dispose after event completion + this.dispose(); +} + +qx.Proto._ontimeout = function(e) +{ +/* + // User's handler can block until timeout. + switch(this.getState()) + { + // If we're no longer running... + case "completed": + case "timeout": + case "aborted": + case "failed": + // then don't bubble up the timeout event + return; + } +*/ + + // Modify internal state + this.setState("timeout"); + + // Bubbling up + this.dispatchEvent(e); + + // Automatically dispose after event completion + this.dispose(); +} + +qx.Proto._onfailed = function(e) +{ + // Modify internal state + this.setState("failed"); + + // Bubbling up + this.dispatchEvent(e); + + // Automatically dispose after event completion + this.dispose(); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyState = function(propValue, propOldValue, propData) +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("State: " + propValue); + } + + return true; +} + +qx.Proto._modifyProhibitCaching = function(propValue, propOldValue, propData) +{ + propValue ? this.setParameter("nocache", new Date().valueOf()) : this.removeParameter("nocache"); + + return true; +} + +qx.Proto._modifyMethod = function(propValue, propOldValue, propData) +{ + if (propValue === qx.net.Http.METHOD_POST) { + this.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + } + + return true; +} + +qx.Proto._modifyResponseType = function(propValue, propOldValue, propData) +{ + this.setRequestHeader("X-Qooxdoo-Response-Type", propValue); + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + REQUEST HEADER +--------------------------------------------------------------------------- +*/ +/*! + Add a request header to the request. + + Example: request.setRequestHeader("Content-Type", qx.util.Mime.HTML) +*/ +qx.Proto.setRequestHeader = function(vId, vValue) { + this._requestHeaders[vId] = vValue; +} + +qx.Proto.removeRequestHeader = function(vId) { + delete this._requestHeaders[vId]; +} + +qx.Proto.getRequestHeader = function(vId) { + return this._requestHeaders[vId] || null; +} + +qx.Proto.getRequestHeaders = function() { + return this._requestHeaders; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + PARAMETERS +--------------------------------------------------------------------------- +*/ +/*! + Add a parameter to the request. + + @param vId String identifier of the parameter to add. + @param vValue Value of parameter. May be a string (for one parameter) or an + array of strings (for setting multiple parameter values with the same + parameter name). +*/ +qx.Proto.setParameter = function(vId, vValue) { + this._parameters[vId] = vValue; +} + +/*! + Remove a parameter from the request. + + @param vId String identifier of the parameter to remove. +*/ +qx.Proto.removeParameter = function(vId) { + delete this._parameters[vId]; +} + +/*! + Get a parameter in the request. + + @param vId String identifier of the parameter to get. +*/ +qx.Proto.getParameter = function(vId) { + return this._parameters[vId] || null; +} + +/*! + Returns an object containg all parameters for the request. +*/ +qx.Proto.getParameters = function() { + return this._parameters; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + SEQUENCE NUMBER +--------------------------------------------------------------------------- +*/ + +/* + * Sequence (id) number of a request, used to associate a response or error + * with its initiating request. + */ +qx.io.remote.Request._seqNum = 0; + +/** + * Obtain the sequence (id) number used for this request + */ +qx.Proto.getSequenceNumber = function() { + return this._seqNum; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._requestHeaders = null; + this._parameters = null; + + this.setTransport(null); + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/RequestQueue.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/RequestQueue.js new file mode 100644 index 0000000000..9cf8dac297 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/RequestQueue.js @@ -0,0 +1,409 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + +/** + * Handles scheduling of requests to be sent to a server. + * + * This class is a singleton and is used by qx.io.remote.Request to schedule its + * requests. It should not be used directly. + */ +qx.OO.defineClass("qx.io.remote.RequestQueue", qx.core.Target, +function() +{ + qx.core.Target.call(this); + + this._queue = []; + this._active = []; + + this._totalRequests = 0; + + // timeout handling + this._timer = new qx.client.Timer(500); + this._timer.addEventListener("interval", this._oninterval, this); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * @deprecated + */ +qx.OO.addProperty({ name : "maxTotalRequests", type : "number" }); + +/** + * Maximum number of parallel requests. + */ +qx.OO.addProperty({ name : "maxConcurrentRequests", type : "number", defaultValue : 3 }); + +/** + * Default timeout for remote requests in milliseconds. + */ +qx.OO.addProperty({ name : "defaultTimeout", type : "number", defaultValue : 5000 }); + + + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._debug = function() +{ + // Debug output + var vText = this._active.length + "/" + (this._queue.length+this._active.length); + + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) + { + this.debug("Progress: " + vText); + window.status = "Request-Queue Progress: " + vText; + } +} + +qx.Proto._check = function() +{ + // Debug output + this._debug(); + + // Check queues and stop timer if not needed anymore + if (this._active.length == 0 && this._queue.length == 0) { + this._timer.stop(); + } + + // Checking if enabled + if (!this.getEnabled()) { + return; + } + + // Checking active queue fill + if (this._active.length >= this.getMaxConcurrentRequests() || this._queue.length == 0) { + return; + } + + // Checking number of total requests + if (this.getMaxTotalRequests() != null && this._totalRequests >= this.getMaxTotalRequests()) { + return; + } + + var vRequest = this._queue.shift(); + var vTransport = new qx.io.remote.Exchange(vRequest); + + // Increment counter + this._totalRequests++; + + // Add to active queue + this._active.push(vTransport); + + // Debug output + this._debug(); + + // Establish event connection between qx.io.remote.Exchange instance and qx.io.remote.Request + vTransport.addEventListener("sending", vRequest._onsending, vRequest); + vTransport.addEventListener("receiving", vRequest._onreceiving, vRequest); + vTransport.addEventListener("completed", vRequest._oncompleted, vRequest); + vTransport.addEventListener("aborted", vRequest._onaborted, vRequest); + vTransport.addEventListener("timeout", vRequest._ontimeout, vRequest); + vTransport.addEventListener("failed", vRequest._onfailed, vRequest); + + // Establish event connection between qx.io.remote.Exchange and me. + vTransport.addEventListener("sending", this._onsending, this); + vTransport.addEventListener("completed", this._oncompleted, this); + vTransport.addEventListener("aborted", this._oncompleted, this); + vTransport.addEventListener("timeout", this._oncompleted, this); + vTransport.addEventListener("failed", this._oncompleted, this); + + // Store send timestamp + vTransport._start = (new Date).valueOf(); + + // Send + vTransport.send(); + + // Retry + if (this._queue.length > 0) { + this._check(); + } +} + +qx.Proto._remove = function(vTransport) +{ + var vRequest = vTransport.getRequest(); + + // Destruct event connection between qx.io.remote.Exchange instance and qx.io.remote.Request + vTransport.removeEventListener("sending", vRequest._onsending, vRequest); + vTransport.removeEventListener("receiving", vRequest._onreceiving, vRequest); + vTransport.removeEventListener("completed", vRequest._oncompleted, vRequest); + vTransport.removeEventListener("aborted", vRequest._onaborted, vRequest); + vTransport.removeEventListener("timeout", vRequest._ontimeout, vRequest); + vTransport.removeEventListener("failed", vRequest._onfailed, vRequest); + + // Destruct event connection between qx.io.remote.Exchange and me. + vTransport.removeEventListener("sending", this._onsending, this); + vTransport.removeEventListener("completed", this._oncompleted, this); + vTransport.removeEventListener("aborted", this._oncompleted, this); + vTransport.removeEventListener("timeout", this._oncompleted, this); + vTransport.removeEventListener("failed", this._oncompleted, this); + + // Remove from active transports + qx.lang.Array.remove(this._active, vTransport); + + // Dispose transport object + vTransport.dispose(); + + // Check again + this._check(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._activeCount = 0; + +qx.Proto._onsending = function(e) +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) + { + this._activeCount++; + e.getTarget()._counted = true; + + this.debug("ActiveCount: " + this._activeCount); + } +} + +qx.Proto._oncompleted = function(e) +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) + { + if (e.getTarget()._counted) + { + this._activeCount--; + this.debug("ActiveCount: " + this._activeCount); + } + } + + this._remove(e.getTarget()); +} + + + + + + + +/* +--------------------------------------------------------------------------- + TIMEOUT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._oninterval = function(e) +{ + var vActive = this._active; + + if (vActive.length == 0) { + return; + } + + var vCurrent = (new Date).valueOf(); + var vTransport; + var vRequest; + var vDefaultTimeout = this.getDefaultTimeout(); + var vTimeout; + var vTime; + + for (var i=vActive.length-1; i>=0; i--) + { + vTransport = vActive[i]; + vRequest = vTransport.getRequest(); + if (vRequest.isAsynchronous()) { + vTimeout = vRequest.getTimeout(); + + // if timer is disabled... + if (vTimeout == 0) { + // then ignore it. + continue; + } + + if (vTimeout == null) { + vTimeout = vDefaultTimeout; + } + + vTime = vCurrent - vTransport._start; + + if (vTime > vTimeout) + { + this.warn("Timeout: transport " + vTransport.toHashCode()); + this.warn(vTime + "ms > " + vTimeout + "ms"); + vTransport.timeout(); + } + } + } +} + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (propValue) { + this._check(); + } + + this._timer.setEnabled(propValue); + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ +/*! + Add the request to the pending requests queue. +*/ +qx.Proto.add = function(vRequest) +{ + vRequest.setState("queued"); + + this._queue.push(vRequest); + this._check(); + + if (this.getEnabled()) { + this._timer.start(); + } +} + +/*! + Remove the request from the pending requests queue. + + The underlying transport of the request is forced into the aborted + state ("aborted") and listeners of the "aborted" + signal are notified about the event. If the request isn't in the + pending requests queue, this method is a noop. +*/ +qx.Proto.abort = function(vRequest) +{ + var vTransport = vRequest.getTransport(); + + if (vTransport) + { + vTransport.abort(); + } + else if (qx.lang.Array.contains(this._queue, vRequest)) + { + qx.lang.Array.remove(this._queue, vRequest); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Disposer + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._active) + { + for (var i=0, a=this._active, l=a.length; i<l; i++) { + this._remove(a[i]); + } + + this._active = null; + } + + if (this._timer) + { + this._timer.removeEventListener("interval", this._oninterval, this); + this._timer = null; + } + + this._queue = null; + + return qx.core.Target.prototype.dispose.call(this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Response.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Response.js new file mode 100644 index 0000000000..7668c921d5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Response.js @@ -0,0 +1,112 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + +qx.OO.defineClass("qx.io.remote.Response", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "state", type : "number" }); +/*! + Status code of the response. +*/ +qx.OO.addProperty({ name : "statusCode", type : "number" }); +qx.OO.addProperty({ name : "content" }); +qx.OO.addProperty({ name : "responseHeaders", type : "object" }); + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +/* +qx.Proto._modifyResponseHeaders = function(propValue, propOldValue, propData) +{ + for (vKey in propValue) { + this.debug("R-Header: " + vKey + "=" + propValue[vKey]); + } + + return true; +} +*/ + + + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getResponseHeader = function(vHeader) +{ + var vAll = this.getResponseHeaders(); + if (vAll) { + return vAll[vHeader] || null; + } + + return null; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Rpc.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Rpc.js new file mode 100644 index 0000000000..88fe2f46a6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/Rpc.js @@ -0,0 +1,581 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Andreas Junghans (lucidcake) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) + +************************************************************************ */ + + +/** + * Provides a Remote Procedure Call (RPC) implementation. + * + * Each instance of this class represents a "Service". These services can + * correspond to various concepts on the server side (depending on the + * programming language/environment being used), but usually, a service means + * a class on the server. + * + * In case multiple instances of the same service are needed, they can be + * distinguished by ids. If such an id is specified, the server routes all + * calls to a service that have the same id to the same server-side instance. + * + * When calling a server-side method, the parameters and return values are + * converted automatically. Supported types are int (and Integer), double + * (and Double), String, Date, Map, and JavaBeans. Beans must habe a default + * constructor on the server side and are represented by simple JavaScript + * objects on the client side (used as associative arrays with keys matching + * the server-side properties). Beans can also be nested, but be careful to not + * create circular references! There are no checks to detect these (which would + * be expensive), so you as the user are responsible for avoiding them. + * + * @param url {String} identifies the url where the service + * is found. Note that if the url is to + * a domain (server) other than where the + * qooxdoo script came from, i.e. it is + * cross-domain, then you must also call + * the setCrossDomain(true) method to + * enable the ScriptTransport instead of + * the XmlHttpTransport, since the latter + * can not handle cross-domain requests. + * + * @param serviceName {String} identifies the service. For the Java + * implementation, this is the fully + * qualified name of the class that offers + * the service methods + * (e.g. "my.pkg.MyService"). + * + * @event completed (qx.event.type.DataEvent) + * @event failed (qx.event.type.DataEvent) + * @event timeout (qx.event.type.DataEvent) + * @event aborted (qx.event.type.DataEvent) + */ + +qx.OO.defineClass("qx.io.remote.Rpc", qx.core.Target, +function(url, serviceName) +{ + qx.core.Target.call(this); + + this.setUrl(url); + if (serviceName != null) { + this.setServiceName(serviceName); + } + this._previousServerSuffix = null; + this._currentServerSuffix = null; + if (qx.core.ServerSettings) { + this._currentServerSuffix = qx.core.ServerSettings.serverPathSuffix; + } +}); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + The timeout for asynchronous calls in milliseconds. + */ +qx.OO.addProperty({ name : "timeout", type : "number" }); + +/** + Indicate that the request is cross domain. + + A request is cross domain if the request's URL points to a host other + than the local host. This switches the concrete implementation that + is used for sending the request from qx.io.remote.XmlHttpTransport to + qx.io.remote.ScriptTransport because only the latter can handle cross domain + requests. +*/ +qx.OO.addProperty({ name : "crossDomain", type : "boolean", defaultValue : false }); + +/** + The URL at which the service is located. +*/ +qx.OO.addProperty({ name : "url", type : "string", defaultValue : null }); + +/** + The service name. +*/ +qx.OO.addProperty({ name : "serviceName", type : "string", defaultValue : null }); + +/** + Data sent as "out of band" data in the request to the server. The format of + the data is opaque to RPC and may be recognized only by particular servers + It is up to the server to decide what to do with it: whether to ignore it, + handle it locally before calling the specified method, or pass it on to the + method. This server data is not sent to the server if it has been set to + 'undefined'. +*/ +qx.OO.addProperty({ name : "serverData", type : "object", defaultValue : undefined }); + +/** + Username to use for HTTP authentication. Null if HTTP authentication + is not used. +*/ +qx.OO.addProperty({ name : "username", type : "string" }); + +/** + Password to use for HTTP authentication. Null if HTTP authentication + is not used. +*/ +qx.OO.addProperty({ name : "password", type : "string" }); + +/** + Use Basic HTTP Authentication +*/ +qx.OO.addProperty({ name : "useBasicHttpAuth", type : "boolean" }); + +/** + Origins of errors +*/ +qx.io.remote.Rpc.origin = +{ + server : 1, + application : 2, + transport : 3, + local : 4 +} + +/** + Locally-detected errors +*/ +qx.io.remote.Rpc.localError = +{ + timeout : 1, + abort : 2 +} + + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ + +/* callType: 0 = sync, 1 = async with handler, 2 = async event listeners */ +/** + * Internal RPC call method + * + * @param args {Array} array of arguments + * @param callType {Integer} 0 = sync, 1 = async with handler, 2 = async event listeners + * @param refreshSession {Boolean} whether a new session should be requested + */ +qx.Proto._callInternal = function(args, callType, refreshSession) { + var self = this; + var offset = (callType == 0 ? 0 : 1) + var whichMethod = (refreshSession ? "refreshSession" : args[offset]); + var handler = args[0]; + var argsArray = []; + var eventTarget = this; + + for (var i = offset + 1; i < args.length; ++i) { + argsArray.push(args[i]); + } + var req = new qx.io.remote.Request(this.getUrl(), + qx.net.Http.METHOD_POST, + qx.util.Mime.JSON); + var requestObject = { + "service": (refreshSession ? null : this.getServiceName()), + "method": whichMethod, + "id": req.getSequenceNumber(), + "params": argsArray + // additional field 'server_data' optionally included, below + } + + // See if there's any out-of-band data to be sent to the server + var serverData = this.getServerData(); + if (serverData !== undefined) { + // There is. Send it. + requestObject.server_data = serverData; + } + + req.setCrossDomain(this.getCrossDomain()); + + if (this.getUsername()) { + req.setUseBasicHttpAuth(this.getUseBasicHttpAuth()); + req.setUsername(this.getUsername()); + req.setPassword(this.getPassword()); + } + + req.setTimeout(this.getTimeout()); + var ex = null; + var id = null; + var result = null; + + var handleRequestFinished = function(eventType, eventTarget) { + switch(callType) + { + case 0: // sync + break; + + case 1: // async with handler function + handler(result, ex, id); + break; + + case 2: // async with event listeners + // Dispatch the event to our listeners. + if (! ex) { + eventTarget.createDispatchDataEvent(eventType, result); + } else { + // Add the id to the exception + ex.id = id; + + if (args[0]) { // coalesce + // They requested that we coalesce all failure types to "failed" + eventTarget.createDispatchDataEvent("failed", ex); + } else { + // No coalese so use original event type + eventTarget.createDispatchDataEvent(eventType, ex); + } + } + } + } + + var addToStringToObject = function(obj) { + obj.toString = function() { + switch(obj.origin) + { + case qx.io.remote.Rpc.origin.server: + return "Server error " + obj.code + ": " + obj.message; + case qx.io.remote.Rpc.origin.application: + return "Application error " + obj.code + ": " + obj.message; + case qx.io.remote.Rpc.origin.transport: + return "Transport error " + obj.code + ": " + obj.message; + case qx.io.remote.Rpc.origin.local: + return "Local error " + obj.code + ": " + obj.message; + default: + return "UNEXPECTED origin " + obj.origin + " error " + obj.code + ": " + obj.message; + } + } + } + + var makeException = function(origin, code, message) { + var ex = new Object(); + + ex.origin = origin; + ex.code = code; + ex.message = message; + addToStringToObject(ex); + + return ex; + } + + req.addEventListener("failed", function(evt) { + var code = evt.getData().getStatusCode(); + ex = makeException(qx.io.remote.Rpc.origin.transport, + code, + qx.io.remote.Exchange.statusCodeToString(code)); + id = this.getSequenceNumber(); + handleRequestFinished("failed", eventTarget); + }); + req.addEventListener("timeout", function(evt) { + ex = makeException(qx.io.remote.Rpc.origin.local, + qx.io.remote.Rpc.localError.timeout, + "Local time-out expired"); + id = this.getSequenceNumber(); + handleRequestFinished("timeout", eventTarget); + }); + req.addEventListener("aborted", function(evt) { + ex = makeException(qx.io.remote.Rpc.origin.local, + qx.io.remote.Rpc.localError.abort, + "Aborted"); + id = this.getSequenceNumber(); + handleRequestFinished("aborted", eventTarget); + }); + req.addEventListener("completed", function(evt) { + result = evt.getData().getContent(); + id = result["id"]; + if (id != this.getSequenceNumber()) { + this.warn("Received id (" + id + ") does not match requested id (" + this.getSequenceNumber() + ")!"); + } + var exTest = result["error"]; + if (exTest != null) { + result = null; + addToStringToObject(exTest); + ex = exTest; + } else { + result = result["result"]; + if (refreshSession) { + result = eval("(" + result + ")"); + var newSuffix = qx.core.ServerSettings.serverPathSuffix; + if (self._currentServerSuffix != newSuffix) { + self._previousServerSuffix = self._currentServerSuffix; + self._currentServerSuffix = newSuffix; + } + self.setUrl(self.fixUrl(self.getUrl())); + } + } + handleRequestFinished("completed", eventTarget); + }); + req.setData(qx.io.Json.stringify(requestObject)); + req.setAsynchronous(callType > 0); + + if (req.getCrossDomain()) { + // Our choice here has no effect anyway. This is purely informational. + req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + } else { + // When not cross-domain, set type to text/json + req.setRequestHeader("Content-Type", qx.util.Mime.JSON); + } + + req.send(); + + if (callType == 0) { + if (ex != null) { + var error = new Error(ex.toString()); + error.rpcdetails = ex; + throw error; + } + return result; + } else { + return req; + } +} + + +/** + * Helper method to rewrite a URL with a stale session id (so that it includes + * the correct session id afterwards). + * + * @param url {String} the URL to examine. + * + * @return {String} the (possibly re-written) URL. + */ + +qx.Proto.fixUrl = function(url) { + if (this._previousServerSuffix == null || this._currentServerSuffix == null || + this._previousServerSuffix == "" || + this._previousServerSuffix == this._currentServerSuffix) { + return url; + } + var index = url.indexOf(this._previousServerSuffix); + if (index == -1) { + return url; + } + return url.substring(0, index) + this._currentServerSuffix + + url.substring(index + this._previousServerSuffix.length); +}; + + +/** + * Makes a synchronous server call. The method arguments (if any) follow + * after the method name (as normal JavaScript arguments, separated by commas, + * not as an array). + * <p> + * If a problem occurs when making the call, an exception is thrown. + * </p> + * <p> + * WARNING. With some browsers, the synchronous interface + * causes the browser to hang while awaiting a response! If the server + * decides to pause for a minute or two, your browser may do nothing + * (including refreshing following window changes) until the response is + * received. Instead, use the asynchronous interface. + * </p> + * <p> + * YOU HAVE BEEN WARNED. + * </p> + * + * @param methodName {String} the name of the method to call. + * + * @return {var} the result returned by the server. + */ + +qx.Proto.callSync = function(methodName) { + return this._callInternal(arguments, 0); +} + + +/** + * Makes an asynchronous server call. The method arguments (if any) follow + * after the method name (as normal JavaScript arguments, separated by commas, + * not as an array). + * <p> + * When an answer from the server arrives, the <code>handler</code> function + * is called with the result of the call as the first, an exception as the + * second parameter, and the id (aka sequence number) of the invoking request + * as the third parameter. If the call was successful, the second parameter is + * <code>null</code>. If there was a problem, the second parameter contains an + * exception, and the first one is <code>null</code>. + * </p> + * <p> + * The return value of this method is a call reference that you can store if + * you want to abort the request later on. This value should be treated as + * opaque and can change completely in the future! The only thing you can rely + * on is that the <code>abort</code> method will accept this reference and + * that you can retrieve the sequence number of the request by invoking the + * getSequenceNumber() method (see below). + * </p> + * <p> + * If a specific method is being called, asynchronously, a number of times in + * succession, the getSequenceNumber() method may be used to disambiguate + * which request a response corresponds to. The sequence number value is a + * value which increments with each request.) + * </p> + * + * @param handler {Function} the callback function. + * + * @param methodName {String} the name of the method to call. + * + * @return {var} the method call reference. + */ + +qx.Proto.callAsync = function(handler, methodName) { + return this._callInternal(arguments, 1); +} + + +/** + * Makes an asynchronous server call and dispatch an event upon completion or + * failure. The method arguments (if any) follow after the method name (as + * normal JavaScript arguments, separated by commas, not as an array). + * <p> + * When an answer from the server arrives (or fails to arrive on time), if an + * exception occurred, a "failed", "timeout" or "aborted" event, as + * appropriate, is dispatched to any waiting event listeners. If no exception + * occurred, a "completed" event is dispatched. + * </p> + * <p> + * When a "failed", "timeout" or "aborted" event is dispatched, the event data + * contains an object with the properties 'origin', 'code', 'message' and + * 'id'. The object has a toString() function which may be called to convert + * the exception to a string. + * </p> + * <p> + * When a "completed" event is dispatched, the event data contains the + * JSON-RPC result. + * </p> + * <p> + * The return value of this method is a call reference that you can store if + * you want to abort the request later on. This value should be treated as + * opaque and can change completely in the future! The only thing you can rely + * on is that the <code>abort</code> method will accept this reference and + * that you can retrieve the sequence number of the request by invoking the + * getSequenceNumber() method (see below). + * </p> + * <p> + * If a specific method is being called, asynchronously, a number of times in + * succession, the getSequenceNumber() method may be used to disambiguate + * which request a response corresponds to. The sequence number value is a + * value which increments with each request.) + * </p> + * + * @param coalesce {Boolean} coalesce all failure types ("failed", + * "timeout", and "aborted") to "failed". + * This is reasonable in many cases, as + * the provided exception contains adequate + * disambiguating information. + * + * @param methodName {String} the name of the method to call. + * + * @return {var} the method call reference. + */ + +qx.Proto.callAsyncListeners = function(coalesce, methodName) { + return this._callInternal(arguments, 2); +} + + +/** + * Refreshes a server session by retrieving the session id again from the + * server. + * <p> + * The specified handler function is called when the refresh is complete. The + * first parameter can be <code>true</code> (indicating that a refresh either + * wasn't necessary at this time or it was successful) or <code>false</code> + * (indicating that a refresh would have been necessary but can't be performed + * because the server backend doesn't support it). If there is a non-null + * second parameter, it's an exception indicating that there was an error when + * refreshing the session. + * </p> + * + * @param handler {Function} a callback function that is called when the + * refresh is complete (or failed). + */ + +qx.Proto.refreshSession = function(handler) { + if (this.getCrossDomain()) { + if (qx.core.ServerSettings && qx.core.ServerSettings.serverPathSuffix) { + var timeDiff = (new Date()).getTime() - qx.core.ServerSettings.lastSessionRefresh; + if (timeDiff/1000 > (qx.core.ServerSettings.sessionTimeoutInSeconds - 30)) { + //this.info("refreshing session"); + this._callInternal([handler], 1, true); + } else { + handler(true); // session refresh was OK (in this case: not needed) + } + } else { + handler(false); // no refresh possible, but would be necessary + } + } else { + handler(true); // session refresh was OK (in this case: not needed) + } +} + + +/** + * Aborts an asynchronous server call. Consequently, the callback function + * provided to <code>callAsync</code> or <code>callAsyncListeners</code> will + * be called with an exception. + * + * @param opaqueCallRef {var} the call reference as returned by + * <code>callAsync</code> or + * <code>callAsyncListeners</code> + */ + +qx.Proto.abort = function(opaqueCallRef) { + opaqueCallRef.abort(); +} + + +/** + * Creates an URL for talking to a local service. A local service is one that + * lives in the same application as the page calling the service. For backends + * that don't support this auto-generation, this method returns null. + * + * @param instanceId {String ? null} an optional identifier for the + * server side instance that should be + * used. All calls to the same service + * with the same instance id are + * routed to the same object instance + * on the server. The instance id can + * also be used to provide additional + * data for the service instantiation + * on the server. + * + * @return {String} the url. + */ + +qx.Class.makeServerURL = function(instanceId) { + var retVal = null; + if (qx.core.ServerSettings) { + retVal = qx.core.ServerSettings.serverPathPrefix + "/.qxrpc" + + qx.core.ServerSettings.serverPathSuffix; + if (instanceId != null) { + retVal += "?instanceId=" + instanceId; + } + } + return retVal; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/ScriptTransport.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/ScriptTransport.js new file mode 100644 index 0000000000..40fe0dc74e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/ScriptTransport.js @@ -0,0 +1,361 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + * Andreas Junghans (lucidcake) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) +#require(qx.io.remote.Exchange) + +************************************************************************ */ + +/*! + Transports requests to a server using dynamic script tags. + + This class should not be used directly by client programmers. + */ +qx.OO.defineClass("qx.io.remote.ScriptTransport", qx.io.remote.AbstractRemoteTransport, +function() +{ + qx.io.remote.AbstractRemoteTransport.call(this); + + var vUniqueId = ++qx.io.remote.ScriptTransport._uniqueId; + if (vUniqueId >= 2000000000) { + qx.io.remote.ScriptTransport._uniqueId = vUniqueId = 1; + } + + this._element = null; + this._uniqueId = vUniqueId; +}); + +qx.Class._uniqueId = 0; +qx.Class._instanceRegistry = {}; +qx.Class.ScriptTransport_PREFIX = "_ScriptTransport_"; +qx.Class.ScriptTransport_ID_PARAM = qx.Class.ScriptTransport_PREFIX + "id"; +qx.Class.ScriptTransport_DATA_PARAM = qx.Class.ScriptTransport_PREFIX + "data"; +qx.Proto._lastReadyState = 0; + + + + + +/* +--------------------------------------------------------------------------- + CLASS PROPERTIES AND METHODS +--------------------------------------------------------------------------- +*/ + +// basic registration to qx.io.remote.Exchange +// the real availability check (activeX stuff and so on) follows at the first real request +qx.io.remote.Exchange.registerType(qx.io.remote.ScriptTransport, "qx.io.remote.ScriptTransport"); + +qx.io.remote.ScriptTransport.handles = +{ + synchronous : false, + asynchronous : true, + crossDomain : true, + fileUpload: false, + responseTypes : [ qx.util.Mime.TEXT, qx.util.Mime.JAVASCRIPT, qx.util.Mime.JSON ] +} + +qx.io.remote.ScriptTransport.isSupported = function() { + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.send = function() +{ + var vUrl = this.getUrl(); + + + + // -------------------------------------- + // Adding parameters + // -------------------------------------- + + vUrl += (vUrl.indexOf("?") >= 0 ? "&" : "?") + qx.io.remote.ScriptTransport.ScriptTransport_ID_PARAM + "=" + this._uniqueId; + + var vParameters = this.getParameters(); + var vParametersList = []; + for (var vId in vParameters) { + if (vId.indexOf(qx.io.remote.ScriptTransport.ScriptTransport_PREFIX) == 0) { + this.error("Illegal parameter name. The following prefix is used internally by qooxdoo): " + + qx.io.remote.ScriptTransport.ScriptTransport_PREFIX); + } + var value = vParameters[vId]; + if (value instanceof Array) { + for (var i = 0; i < value.length; i++) { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value[i])); + } + } else { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value)); + } + } + + if (vParametersList.length > 0) { + vUrl += "&" + vParametersList.join("&"); + } + + + + // -------------------------------------- + // Sending data + // -------------------------------------- + + vData = this.getData(); + if (vData != null) { + vUrl += "&" + qx.io.remote.ScriptTransport.ScriptTransport_DATA_PARAM + "=" + encodeURIComponent(vData); + } + + qx.io.remote.ScriptTransport._instanceRegistry[this._uniqueId] = this; + this._element = document.createElement("script"); + this._element.charset = "utf-8"; // IE needs this (it ignores the + // encoding from the header sent by the + // server for dynamic script tags) + this._element.src = vUrl; + + document.body.appendChild(this._element); +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENER +--------------------------------------------------------------------------- +*/ + +// For reference: +// http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readyState_1.asp +qx.io.remote.ScriptTransport._numericMap = +{ + "uninitialized" : 1, + "loading" : 2, + "loaded" : 2, + "interactive" : 3, + "complete" : 4 +} + +qx.Proto._switchReadyState = function(vReadyState) +{ + // Ignoring already stopped requests + switch(this.getState()) + { + case "completed": + case "aborted": + case "failed": + case "timeout": + this.warn("Ignore Ready State Change"); + return; + } + + // Updating internal state + while (this._lastReadyState < vReadyState) { + this.setState(qx.io.remote.Exchange._nativeMap[++this._lastReadyState]); + } +} +qx.Class._requestFinished = function(id, content) { + var vInstance = qx.io.remote.ScriptTransport._instanceRegistry[id]; + if (vInstance == null) { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Request finished for an unknown instance (probably aborted or timed out before)"); + } + } else { + vInstance._responseContent = content; + vInstance._switchReadyState(qx.io.remote.ScriptTransport._numericMap.complete); + } +} + + + + + +/* +--------------------------------------------------------------------------- + REQUEST HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.setRequestHeader = function(vLabel, vValue) +{ + // TODO + // throw new Error("setRequestHeader is abstract"); +} + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getResponseHeader = function(vLabel) +{ + return null; + + // TODO + // this.error("Need implementation", "getResponseHeader"); +} + +/*! + Provides an hash of all response headers. +*/ +qx.Proto.getResponseHeaders = function() +{ + return {} + + // TODO + // throw new Error("getResponseHeaders is abstract"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + STATUS SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns the current status code of the request if available or -1 if not. +*/ +qx.Proto.getStatusCode = function() +{ + return 200; + + // TODO + // this.error("Need implementation", "getStatusCode"); +} + +/*! + Provides the status text for the current request if available and null otherwise. +*/ +qx.Proto.getStatusText = function() +{ + return ""; + + // TODO + // this.error("Need implementation", "getStatusText"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE DATA SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns the length of the content as fetched thus far +*/ +qx.Proto.getFetchedLength = function() +{ + return 0; + + // TODO + // throw new Error("getFetchedLength is abstract"); +} + +qx.Proto.getResponseContent = function() +{ + if (this.getState() !== "completed") + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Transfer not complete, ignoring content!"); + } + + return null; + } + + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.debug("Returning content for responseType: " + this.getResponseType()); + } + + switch(this.getResponseType()) + { + case qx.util.Mime.TEXT: + // server is responsible for using a string as the response + + case qx.util.Mime.JSON: + case qx.util.Mime.JAVASCRIPT: + return this._responseContent; + + default: + this.warn("No valid responseType specified (" + this.getResponseType() + ")!"); + return null; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._element != null) + { + delete qx.io.remote.ScriptTransport._instanceRegistry[this._uniqueId]; + document.body.removeChild(this._element); + this._element = null; + } + + return qx.io.remote.AbstractRemoteTransport.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/XmlHttpTransport.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/XmlHttpTransport.js new file mode 100644 index 0000000000..6c79e08f93 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/io/remote/XmlHttpTransport.js @@ -0,0 +1,738 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(io_remote) +#require(qx.io.remote.Exchange) +#require(qx.util.Mime) + +************************************************************************ */ + +/** + * @event created {qx.event.type.Event} + * @event configured {qx.event.type.Event} + * @event sending {qx.event.type.Event} + * @event receiving {qx.event.type.Event} + * @event completed {qx.event.type.Event} + * @event failed {qx.event.type.Event} + * @event aborted {qx.event.type.Event} + * @event timeout {qx.event.type.Event} + */ +qx.OO.defineClass("qx.io.remote.XmlHttpTransport", + qx.io.remote.AbstractRemoteTransport, +function() +{ + qx.io.remote.AbstractRemoteTransport.call(this); + + this._req = qx.io.remote.XmlHttpTransport.createRequestObject(); + + var o = this; + this._req.onreadystatechange = + function(e) { return o._onreadystatechange(e); } +}); + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +// basic registration to qx.io.remote.Exchange +// the real availability check (activeX stuff and so on) follows at the first real request +qx.io.remote.Exchange.registerType(qx.io.remote.XmlHttpTransport, + "qx.io.remote.XmlHttpTransport"); + +qx.io.remote.XmlHttpTransport.handles = +{ + synchronous : true, + asynchronous : true, + crossDomain : false, + fileUpload: false, + responseTypes : [ + qx.util.Mime.TEXT, + qx.util.Mime.JAVASCRIPT, + qx.util.Mime.JSON, + qx.util.Mime.XML, + qx.util.Mime.HTML + ] +} + +qx.io.remote.XmlHttpTransport.requestObjects = []; +qx.io.remote.XmlHttpTransport.requestObjectCount = 0; + +qx.io.remote.XmlHttpTransport.isSupported = function() +{ + return qx.net.HttpRequest.create() != null ? true : false; +}; + +qx.io.remote.XmlHttpTransport.createRequestObject = function() { + return qx.net.HttpRequest.create(); +} + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto._localRequest = false; +qx.Proto._lastReadyState = 0; + +qx.Proto.getRequest = function() { + return this._req; +} + + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.send = function() +{ + this._lastReadyState = 0; + + var vRequest = this.getRequest(); + var vMethod = this.getMethod(); + var vAsynchronous = this.getAsynchronous(); + var vUrl = this.getUrl(); + + + + // -------------------------------------- + // Local handling + // -------------------------------------- + + var vLocalRequest = (qx.core.Client.getInstance().getRunsLocally() && + !(/^http(s){0,1}\:/.test(vUrl))); + this._localRequest = vLocalRequest; + + + // -------------------------------------- + // Adding parameters + // -------------------------------------- + + var vParameters = this.getParameters(); + var vParametersList = []; + for (var vId in vParameters) { + var value = vParameters[vId]; + if (value instanceof Array) { + for (var i = 0; i < value.length; i++) { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value[i])); + } + } else { + vParametersList.push(encodeURIComponent(vId) + "=" + + encodeURIComponent(value)); + } + } + + if (vParametersList.length > 0) { + vUrl += (vUrl.indexOf("?") >= 0 + ? "&" : "?") + vParametersList.join("&"); + } + + + var encode64 = function (input) { + var keyStr = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + do { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output += + keyStr.charAt(enc1) + + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + + keyStr.charAt(enc4); + + } while (i < input.length); + + return output; + } + + // -------------------------------------- + // Opening connection + // -------------------------------------- + + if (this.getUsername()) { + if (this.getUseBasicHttpAuth()) { + vRequest.open(vMethod, vUrl, vAsynchronous); + vRequest.setRequestHeader('Authorization', + 'Basic ' + encode64(this.getUsername() + + ':' + + this.getPassword())); + } else { + vRequest.open(vMethod, vUrl, vAsynchronous, + this.getUsername(), this.getPassword()); + } + } else { + vRequest.open(vMethod, vUrl, vAsynchronous); + } + + + + // -------------------------------------- + // Applying request header + // -------------------------------------- + + // Add a Referer header + vRequest.setRequestHeader('Referer', window.location.href); + + var vRequestHeaders = this.getRequestHeaders(); + for (var vId in vRequestHeaders) { + vRequest.setRequestHeader(vId, vRequestHeaders[vId]); + } + + + + // -------------------------------------- + // Sending data + // -------------------------------------- + + try + { + vRequest.send(this.getData()); + } + catch(ex) + { + if (vLocalRequest) + { + this.failedLocally(); + } + else + { + this.error("Failed to send data: " + ex, "send"); + this.failed(); + } + + return; + } + + + + // -------------------------------------- + // Readystate for sync reqeusts + // -------------------------------------- + + if (!vAsynchronous) { + this._onreadystatechange(); + } +} + +/*! + Force the transport into the failed state + ("failed"). + + This method should be used only if the requests URI was local + access. I.e. it started with "file://". +*/ +qx.Proto.failedLocally = function() +{ + if (this.getState() === "failed") { + return; + } + + // should only occur on "file://" access + this.warn("Could not load from file: " + this.getUrl()); + + this.failed(); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onreadystatechange = function(e) +{ + // Ignoring already stopped requests + switch(this.getState()) + { + case "completed": + case "aborted": + case "failed": + case "timeout": + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) { + this.warn("Ignore Ready State Change"); + } + return; + } + + // Checking status code + var vReadyState = this.getReadyState(); + if (vReadyState == 4) { + // The status code is only meaningful when we reach ready state 4. + // (Important for Opera since it goes through other states before + // reaching 4, and the status code is not valid before 4 is reached.) + if (!qx.io.remote.Exchange.wasSuccessful(this.getStatusCode(), vReadyState, this._localRequest)) { + return this.failed(); + } + } + + // Updating internal state + while (this._lastReadyState < vReadyState) { + this.setState(qx.io.remote.Exchange._nativeMap[++this._lastReadyState]); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + READY STATE +--------------------------------------------------------------------------- +*/ +/*! + Get the ready state of this transports request. + + For qx.io.remote.XmlHttpTransports, the ready state is a number between 1 to 4. +*/ +qx.Proto.getReadyState = function() +{ + var vReadyState = null; + + try { + vReadyState = this._req.readyState; + } catch(ex) {} + + return vReadyState; +} + + + + + + + +/* +--------------------------------------------------------------------------- + REQUEST HEADER SUPPORT +--------------------------------------------------------------------------- +*/ +/*! + Add a request header to this transports request. +*/ +qx.Proto.setRequestHeader = function(vLabel, vValue) { + this._req.setRequestHeader(vLabel, vValue); +} + + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE HEADER SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns a specific header provided by the server upon sending a request, + with header name determined by the argument headerName. + + Only available at readyState 3 and 4 universally and in readyState 2 + in Gecko. +*/ +qx.Proto.getResponseHeader = function(vLabel) +{ + var vResponseHeader = null; + + try { + this.getRequest().getResponseHeader(vLabel) || null; + } catch(ex) {} + + return vResponseHeader; +} + +qx.Proto.getStringResponseHeaders = function() +{ + var vSourceHeader = null; + + try + { + var vLoadHeader = this._req.getAllResponseHeaders(); + if (vLoadHeader) { + vSourceHeader = vLoadHeader; + } + } catch(ex) {} + + return vSourceHeader; +} + +/*! + Provides a hash of all response headers. +*/ +qx.Proto.getResponseHeaders = function() +{ + var vSourceHeader = this.getStringResponseHeaders(); + var vHeader = {}; + + if (vSourceHeader) + { + var vValues = vSourceHeader.split(/[\r\n]+/g); + + for(var i=0, l=vValues.length; i<l; i++) + { + var vPair = vValues[i].match(/^([^:]+)\s*:\s*(.+)$/i); + if(vPair) { + vHeader[vPair[1]] = vPair[2]; + } + } + } + + return vHeader; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + STATUS SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Returns the current status code of the request if available or -1 if not. +*/ +qx.Proto.getStatusCode = function() +{ + var vStatusCode = -1; + + try { + vStatusCode = this.getRequest().status; + } catch(ex) {} + + return vStatusCode; +} + +/*! + Provides the status text for the current request if available and null + otherwise. +*/ +qx.Proto.getStatusText = function() +{ + var vStatusText = ""; + + try { + vStatusText = this.getRequest().statusText; + } catch(ex) {} + + return vStatusText; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + RESPONSE DATA SUPPORT +--------------------------------------------------------------------------- +*/ + +/*! + Provides the response text from the request when available and null + otherwise. By passing true as the "partial" parameter of this method, + incomplete data will be made available to the caller. +*/ +qx.Proto.getResponseText = function() +{ + var vResponseText = null; + + var vStatus = this.getStatusCode(); + var vReadyState = this.getReadyState(); + if (qx.io.remote.Exchange.wasSuccessful(vStatus, vReadyState, this._localRequest)) + { + try { + vResponseText = this.getRequest().responseText; + } catch(ex) {} + } + + return vResponseText; +} + +/*! + Provides the XML provided by the response if any and null otherwise. By + passing true as the "partial" parameter of this method, incomplete data will + be made available to the caller. +*/ +qx.Proto.getResponseXml = function() +{ + var vResponseXML = null; + + var vStatus = this.getStatusCode(); + var vReadyState = this.getReadyState(); + if (qx.io.remote.Exchange.wasSuccessful(vStatus, vReadyState, this._localRequest)) + { + try { + vResponseXML = this.getRequest().responseXML; + } catch(ex) {} + } + + // Typical behaviour on file:// on mshtml + // Could we check this with something like: /^file\:/.test(path); ? + // No browser check here, because it doesn't seem to break other browsers + // * test for this.req.responseXML's objecthood added by * + // * FRM, 20050816 * + if (typeof vResponseXML == "object" && vResponseXML != null) + { + if (!vResponseXML.documentElement) + { + // Clear xml file declaration, this breaks non unicode files (like ones with Umlauts) + var s = String(this.getRequest().responseText).replace(/<\?xml[^\?]*\?>/, ""); + vResponseXML.loadXML(s); + }; + // Re-check if fixed... + if (!vResponseXML.documentElement) { + throw new Error("Missing Document Element!"); + }; + + if (vResponseXML.documentElement.tagName == "parseerror") { + throw new Error("XML-File is not well-formed!"); + }; + } + else + { + throw new Error("Response was not a valid xml document [" + this.getRequest().responseText + "]"); + }; + + return vResponseXML; +} + +/*! + Returns the length of the content as fetched thus far +*/ +qx.Proto.getFetchedLength = function() +{ + var vText = this.getResponseText(); + return typeof vText == "string" ? vText.length : 0; +} + +qx.Proto.getResponseContent = function() +{ + if (this.getState() !== "completed") + { + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", + "enableDebug")) { + this.warn("Transfer not complete, ignoring content!"); + } + + return null; + } + + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", + "enableDebug")) { + this.debug("Returning content for responseType: " + this.getResponseType()); + } + + var vText = this.getResponseText(); + + switch(this.getResponseType()) + { + case qx.util.Mime.TEXT: + case qx.util.Mime.HTML: + return vText; + + case qx.util.Mime.JSON: + try { + return vText && vText.length > 0 ? qx.io.Json.parseQx(vText) : null; + } catch(ex) { + this.error("Could not execute json: [" + vText + "]", ex); + return "<pre>Could not execute json: \n" + vText + "\n</pre>" + } + + case qx.util.Mime.JAVASCRIPT: + try { + return vText && vText.length > 0 ? window.eval(vText) : null; + } catch(ex) { + return this.error("Could not execute javascript: [" + vText + "]", ex); + } + + case qx.util.Mime.XML: + return this.getResponseXml(); + + default: + this.warn("No valid responseType specified (" + this.getResponseType() + ")!"); + return null; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyState = function(propValue, propOldValue, propData) +{ + if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", + "enableDebug")) { + this.debug("State: " + propValue); + } + + switch(propValue) + { + case "created": + this.createDispatchEvent("created"); + break; + + case "configured": + this.createDispatchEvent("configured"); + break; + + case "sending": + this.createDispatchEvent("sending"); + break; + + case "receiving": + this.createDispatchEvent("receiving"); + break; + + case "completed": + this.createDispatchEvent("completed"); + break; + + case "failed": + this.createDispatchEvent("failed"); + break; + + case "aborted": + this.getRequest().abort(); + this.createDispatchEvent("aborted"); + break; + + case "timeout": + this.getRequest().abort(); + this.createDispatchEvent("timeout"); + break; + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + var vRequest = this.getRequest(); + + if (vRequest) + { + // Should be right, + // but is not compatible to mshtml (throws an exception) + if (!qx.core.Client.getInstance().isMshtml()) { + vRequest.onreadystatechange = null; + } + + // Aborting + switch(vRequest.readyState) + { + case 1: + case 2: + case 3: + vRequest.abort(); + } + + // Cleanup objects + this._req = null; + } + + return qx.io.remote.AbstractRemoteTransport.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Array.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Array.js new file mode 100644 index 0000000000..9110099ed1 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Array.js @@ -0,0 +1,262 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Helper functions for arrays. + * + * The native JavaScript Array is not modified by this class. However, + * there are modifications to the native Array in {@link qx.lang.Core} for + * browsers that do not support certain JavaScript 1.6 features natively . + * + * The additions implemented here may be added directly to native Array by + * a setting in {@link qx.lang.Prototypes}. This feature is not enabled by + * default. + * + * The string/array generics introduced in JavaScript 1.6 are supported by + * {@link qx.lang.Generics}. + */ +qx.OO.defineClass("qx.lang.Array"); + +/** + * Convert an arguments object into an array + * + * @param args {arguments} arguments object + * @return {Array} + */ +qx.lang.Array.fromArguments = function(args) { + return Array.prototype.slice.call(args, 0); +}; + + +/** + * Expand shorthand definition to a four element list. + * This is an utility function for padding/margin and all other shorthand handling. + * + * @param input {Array} array with one to four elements + * @return {Array} array with four elements + */ +qx.lang.Array.fromShortHand = function(input) +{ + var len = input.length; + + if (len > 4 || len == 0) { + this.error("Invalid number of arguments!"); + } + + var result = qx.lang.Array.copy(input); + + // Copy Values (according to the length) + switch(len) + { + case 1: + result[1] = result[2] = result[3] = result[0]; + break; + + case 2: + result[2] = result[0]; + // no break here + + case 3: + result[3] = result[1]; + } + + // Return list with 4 items + return result; +}; + + +/** + * Return a copy of the given array + * + * @param arr {Array} the array to copy + * @return {Array} copy of the array + */ +qx.lang.Array.copy = function(arr) { + return arr.concat(); +}; + + +/** + * Return a copy of the given array + * The same as {@link qx.lang.Array.copy} + * + * @param arr {Array} the array to copy + * @return {Array} copy of the array + */ +qx.lang.Array.clone = function(arr) { + return arr.concat(); +}; + + +/** + * Return the last element of an array + * + * @param arr {Array} the array + * @return {var} the last element of the array + */ +qx.lang.Array.getLast = function(arr) { + return arr[arr.length-1]; +}; + + +/** + * Return the first element of an array + * + * @param arr {Array} the array + * @return {var} the first element of the array + */ +qx.lang.Array.getFirst = function(arr) { + return arr[0]; +}; + + +/** + * Insert an element at a given position into the array + * + * @param arr {Array} the array + * @param obj {var} the element to insert + * @param i {Integer} position where to insert the element into the array + * @return {Array} the array + */ +qx.lang.Array.insertAt = function(arr, obj, i) +{ + arr.splice(i, 0, obj); + + return arr; +}; + + +/** + * Insert an element into the array before a given second element + * + * @param arr {Array} the array + * @param obj {var} object to be inserted + * @param obj2 {var} insert obj1 before this object + * @return {Array} the array + */ +qx.lang.Array.insertBefore = function(arr, obj, obj2) +{ + var i = arr.indexOf(obj2); + + if (i == -1) + { + arr.push(obj); + } + else + { + arr.splice(i, 0, obj); + } + + return arr; +}; + + +/** + * Insert an element into the array after a given second element + * + * @param arr {Array} the array + * @param obj {var} object to be inserted + * @param obj2 {var} insert obj1 after this object + * @return {Array} the array + */ +qx.lang.Array.insertAfter = function(arr, obj, obj2) +{ + var i = arr.indexOf(obj2); + + if (i == -1 || i == (arr.length-1)) + { + arr.push(obj); + } + else + { + arr.splice(i+1, 0, obj); + } + + return arr; +}; + + +/** + * Remove an element from the array at the given index + * + * @param arr {Array} the array + * @param i {Integer} index of the element to be removed + * @return {Array} the array with the element removed + */ +qx.lang.Array.removeAt = function(arr, i) { + return arr.splice(i, 1); +}; + + +/** + * Remmove all elements from the array + * + * @param arr {Array} the array + * @return {Array} empty array + */ +qx.lang.Array.removeAll = function(arr) { + return arr.splice(0, arr.length); +}; + + +/** + * Append the elements of an array to the array + * + * @param arr {Array} the array + * @param a {Array} the elements of this array will be appended to the array + */ +qx.lang.Array.append = function(arr, a) { + Array.prototype.push.apply(arr, a); +}; + + +/** + * Remove an element from the array + * + * @param arr {Array} the array + * @param obj {var} element to be removed from the array + * @return {Array} array with the element removed + */ +qx.lang.Array.remove = function(arr, obj) +{ + var i = arr.indexOf(obj); + + if (i != -1) { + return arr.splice(i, 1); + } +}; + + +/** + * Whether the array contains the given element + * + * @param arr {Array} the array + * @param obj {var} object to look for + * @return {Boolean} whether the array contains the element + */ +qx.lang.Array.contains = function(arr, obj) { + return arr.indexOf(obj) != -1; +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Core.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Core.js new file mode 100644 index 0000000000..e2e5fb0e88 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Core.js @@ -0,0 +1,430 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * The intention of this class is to add features to native JavaScript + * objects so that all browsers operate on a common JavaScript language level + * (particularly JavaScript 1.6). + * + * For reference: + * + * * http://www.ecma-international.org/publications/standards/Ecma-262.htm + * * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference + * * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6 + * + * The following methods are added if they are not supported natively: + * + * * Error.toString() + * * Array.indexOf() + * * Array.lastIndexOf() + * * Array.forEach() + * * Array.filter() + * * Array.map() + * * Array.some() + * * Array.every() + * * String.quote() + */ +qx.OO.defineClass("qx.lang.Core"); + + +/* +--------------------------------------------------------------------------- + FEATURE EXTENSION OF NATIVE ERROR OBJECT +--------------------------------------------------------------------------- +*/ + +if (!Error.prototype.toString) +{ + /** + * Some browsers (e.g. Internet Explorer) do not support to stringify + * error objects like other browsers usually do. This feature is added to + * those browsers. + */ + Error.prototype.toString = function() { + return this.message; + }; +} + + + + + + + +/* +--------------------------------------------------------------------------- + FEATURE EXTENSION OF NATIVE ARRAY OBJECT +--------------------------------------------------------------------------- +*/ + +if (!Array.prototype.indexOf) +{ + /** + * Returns the first index at which a given element can be found in the array, + * or <code>-1</code> if it is not present. It compares <code>searchElement</code> to elements of the Array + * using strict equality (the same method used by the <code>===</code>, or + * triple-equals, operator). + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf + * + * @param searchElement {var} Element to locate in the array. + * @param fromIndex {Integer} The index at which to begin the search. Defaults to 0, i.e. the whole + * array will be searched. If the index is greater than or equal to the length of the array, + * <code>-1</code> is returned, i.e. the array will not be searched. If negative, it is taken as the + * offset from the end of the array. Note that even when the index is negative, the array is still + * searched from front to back. If the calculated index is less than 0, the whole array will be searched. + */ + Array.prototype.indexOf = function(searchElement, fromIndex) + { + if (fromIndex == null) + { + fromIndex = 0; + } + else if (fromIndex < 0) + { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i=fromIndex; i<this.length; i++) + { + if (this[i] === searchElement) { + return i; + } + } + + return -1; + }; +} + +if (!Array.prototype.lastIndexOf) +{ + /** + * Returns the last index at which a given element can be found in the array, or <code>-1</code> + * if it is not present. The array is searched backwards, starting at <code>fromIndex</code>. + * It compares <code>searchElement</code> to elements of the Array using strict equality + * (the same method used by the <code>===</code>, or triple-equals, operator). + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:lastIndexOf + * + * @param searchElement {var} Element to locate in the array. + * @param fromIndex {Integer} The index at which to start searching backwards. + * Defaults to the array's length, i.e. the whole array will be searched. If + * the index is greater than or equal to the length of the array, the whole array + * will be searched. If negative, it is taken as the offset from the end of the + * array. Note that even when the index is negative, the array is still searched + * from back to front. If the calculated index is less than 0, -1 is returned, + * i.e. the array will not be searched. + */ + Array.prototype.lastIndexOf = function(searchElement, fromIndex) + { + if (fromIndex == null) + { + fromIndex = this.length-1; + } + else if (fromIndex < 0) + { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i=fromIndex; i>=0; i--) + { + if (this[i] === searchElement) { + return i; + } + } + + return -1; + }; +} + +if (!Array.prototype.forEach) +{ + /** + * Executes a provided function once per array element. + * + * <code>forEach</code> executes the provided function (<code>callback</code>) once for each + * element present in the array. <code>callback</code> is invoked only for indexes of the array + * which have assigned values; it is not invoked for indexes which have been deleted or which + * have never been assigned values. + * + * <code>callback</code> is invoked with three arguments: the value of the element, the index + * of the element, and the Array object being traversed. + * + * If a <code>obj</code> parameter is provided to <code>forEach</code>, it will be used + * as the <code>this</code> for each invocation of the <code>callback</code>. If it is not + * provided, or is <code>null</code>, the global object associated with <code>callback</code> + * is used instead. + * + * <code>forEach</code> does not mutate the array on which it is called. + * + * The range of elements processed by <code>forEach</code> is set before the first invocation of + * <code>callback</code>. Elements which are appended to the array after the call to + * <code>forEach</code> begins will not be visited by <code>callback</code>. If existing elements + * of the array are changed, or deleted, their value as passed to <code>callback</code> will be + * the value at the time <code>forEach</code> visits them; elements that are deleted are not visited. + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach + * + * @param callback {Function} Function to execute for each element. + * @param obj {Object} Object to use as this when executing callback. + */ + Array.prototype.forEach = function(callback, obj) + { + // The array length should be fixed, like in the native implementation. + var l = this.length; + + for (var i=0; i<l; i++) { + callback.call(obj, this[i], i, this); + } + }; +} + +if (!Array.prototype.filter) +{ + /** + * Creates a new array with all elements that pass the test implemented by the provided + * function. + * + * <code>filter</code> calls a provided <code>callback</code> function once for each + * element in an array, and constructs a new array of all the values for which + * <code>callback</code> returns a true value. <code>callback</code> is invoked only + * for indexes of the array which have assigned values; it is not invoked for indexes + * which have been deleted or which have never been assigned values. Array elements which + * do not pass the <code>callback</code> test are simply skipped, and are not included + * in the new array. + * + * <code>callback</code> is invoked with three arguments: the value of the element, the + * index of the element, and the Array object being traversed. + * + * If a <code>obj</code> parameter is provided to <code>filter</code>, it will + * be used as the <code>this</code> for each invocation of the <code>callback</code>. + * If it is not provided, or is <code>null</code>, the global object associated with + * <code>callback</code> is used instead. + * + * <code>filter</code> does not mutate the array on which it is called. The range of + * elements processed by <code>filter</code> is set before the first invocation of + * <code>callback</code>. Elements which are appended to the array after the call to + * <code>filter</code> begins will not be visited by <code>callback</code>. If existing + * elements of the array are changed, or deleted, their value as passed to <code>callback</code> + * will be the value at the time <code>filter</code> visits them; elements that are deleted + * are not visited. + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter + * + * @param callback {Function} Function to test each element of the array. + * @param obj {Object} Object to use as <code>this</code> when executing <code>callback</code>. + */ + Array.prototype.filter = function(callback, obj) + { + // The array length should be fixed, like in the native implementation. + var l = this.length; + var res = []; + + for (var i=0; i<l; i++) + { + if (callback.call(obj, this[i], i, this)) { + res.push(this[i]); + } + } + + return res; + }; +} + +if (!Array.prototype.map) +{ + /** + * Creates a new array with the results of calling a provided function on every element in this array. + * + * <code>map</code> calls a provided <code>callback</code> function once for each element in an array, + * in order, and constructs a new array from the results. <code>callback</code> is invoked only for + * indexes of the array which have assigned values; it is not invoked for indexes which have been + * deleted or which have never been assigned values. + * + * <code>callback</code> is invoked with three arguments: the value of the element, the index of the + * element, and the Array object being traversed. + * + * If a <code>obj</code> parameter is provided to <code>map</code>, it will be used as the + * <code>this</code> for each invocation of the <code>callback</code>. If it is not provided, or is + * <code>null</code>, the global object associated with <code>callback</code> is used instead. + * + * <code>map</code> does not mutate the array on which it is called. + * + * The range of elements processed by <code>map</code> is set before the first invocation of + * <code>callback</code>. Elements which are appended to the array after the call to <code>map</code> + * begins will not be visited by <code>callback</code>. If existing elements of the array are changed, + * or deleted, their value as passed to <code>callback</code> will be the value at the time + * <code>map</code> visits them; elements that are deleted are not visited. + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:map + * + * @param callback {Function} Function produce an element of the new Array from an element of the current one. + * @param obj {Object} Object to use as <code>this</code> when executing <code>callback</code>. + */ + Array.prototype.map = function(callback, obj) + { + // The array length should be fixed, like in the native implementation. + var l = this.length; + var res = []; + + for (var i=0; i<l; i++) { + res.push(callback.call(obj, this[i], i, this)); + } + + return res; + }; +} + +if (!Array.prototype.some) +{ + /** + * Tests whether some element in the array passes the test implemented by the provided function. + * + * <code>some</code> executes the <code>callback</code> function once for each element present in + * the array until it finds one where <code>callback</code> returns a true value. If such an element + * is found, <code>some</code> immediately returns <code>true</code>. Otherwise, <code>some</code> + * returns <code>false</code>. <code>callback</code> is invoked only for indexes of the array which + * have assigned values; it is not invoked for indexes which have been deleted or which have never + * been assigned values. + * + * <code>callback</code> is invoked with three arguments: the value of the element, the index of the + * element, and the Array object being traversed. + * + * If a <code>obj</code> parameter is provided to <code>some</code>, it will be used as the + * <code>this</code> for each invocation of the <code>callback</code>. If it is not provided, or is + * <code>null</code>, the global object associated with <code>callback</code> is used instead. + * + * <code>some</code> does not mutate the array on which it is called. + * + * The range of elements processed by <code>some</code> is set before the first invocation of + * <code>callback</code>. Elements that are appended to the array after the call to <code>some</code> + * begins will not be visited by <code>callback</code>. If an existing, unvisited element of the array + * is changed by <code>callback</code>, its value passed to the visiting <code>callback</code> will + * be the value at the time that <code>some</code> visits that element's index; elements that are + * deleted are not visited. + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some + * + * @param callback {Function} Function to test for each element. + * @param obj {Object} Object to use as <code>this</code> when executing <code>callback</code>. + */ + Array.prototype.some = function(callback, obj) + { + // The array length should be fixed, like in the native implementation. + var l = this.length; + + for (var i=0; i<l; i++) + { + if (callback.call(obj, this[i], i, this)) { + return true; + } + } + + return false; + }; +} + +if (!Array.prototype.every) +{ + /** + * Tests whether all elements in the array pass the test implemented by the provided function. + * + * <code>every</code> executes the provided <code>callback</code> function once for each element + * present in the array until it finds one where <code>callback</code> returns a false value. If + * such an element is found, the <code>every</code> method immediately returns <code>false</code>. + * Otherwise, if <code>callback</code> returned a true value for all elements, <code>every</code> + * will return <code>true</code>. <code>callback</code> is invoked only for indexes of the array + * which have assigned values; it is not invoked for indexes which have been deleted or which have + * never been assigned values. + * + * <code>callback</code> is invoked with three arguments: the value of the element, the index of + * the element, and the Array object being traversed. + * + * If a <code>obj</code> parameter is provided to <code>every</code>, it will be used as + * the <code>this</code> for each invocation of the <code>callback</code>. If it is not provided, + * or is <code>null</code>, the global object associated with <code>callback</code> is used instead. + * + * <code>every</code> does not mutate the array on which it is called. The range of elements processed + * by <code>every</code> is set before the first invocation of <code>callback</code>. Elements which + * are appended to the array after the call to <code>every</code> begins will not be visited by + * <code>callback</code>. If existing elements of the array are changed, their value as passed + * to <code>callback</code> will be the value at the time <code>every</code> visits them; elements + * that are deleted are not visited. + * + * Natively supported in Gecko since version 1.8. + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every + * + * @param callback {Function} Function to test for each element. + * @param obj {Object} Object to use as <code>this</code> when executing <code>callback</code>. + */ + Array.prototype.every = function (callback, obj) + { + // The array length should be fixed, like in the native implementation. + var l = this.length; + + for (var i=0; i<l; i++) + { + if (!callback.call(obj, this[i], i, this)) { + return false; + } + } + + return true; + }; +} + + + + + + + +/* +--------------------------------------------------------------------------- + FEATURE EXTENSION OF NATIVE STRING OBJECT +--------------------------------------------------------------------------- +*/ + +if (!String.prototype.quote) +{ + /** + * Surrounds the string with double quotes and escapes all double quotes + * and backslashes within the string. + * + * Note: Not part of ECMAScript Language Specification ECMA-262 + * 3rd edition (December 1999), but implemented by Gecko: + * http://lxr.mozilla.org/seamonkey/source/js/src/jsstr.c + */ + String.prototype.quote = function () { + return '"' + this.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"'; + }; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Function.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Function.js new file mode 100644 index 0000000000..efeccbd592 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Function.js @@ -0,0 +1,126 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + + +/** + * Collection of helper methods operatinf on functions. + */ +qx.OO.defineClass("qx.lang.Function"); + + + + + +/* +--------------------------------------------------------------------------- + SIMPLE RETURN METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Simply return true. + * + * @return {Boolean} Always returns true. + */ +qx.lang.Function.returnTrue = function() { + return true; +}; + + +/** + * Simply return false. + * + * @return {Boolean} Always returns false. + */ + +qx.lang.Function.returnFalse = function() { + return false; +}; + + +/** + * Simply return null. + * + * @return {var} Always returns null. + */ + +qx.lang.Function.returnNull = function() { + return null; +}; + + +/** + * Return "this". + * + * @return {Object} Always returns "this". + */ +qx.lang.Function.returnThis = function() { + return this; +}; + + +/** + * Used to return a refernce to an singleton. Classes which should act as singletons can use this + * function to implement the "getInstance" methods. + * + * @returns {Object} Singleton instance of the class this method is bound to. + */ +qx.lang.Function.returnInstance = function() +{ + if (!this._instance) + { + this._instance = new this; + + /* + if (this._instance.debug) { + this._instance.debug("Created..."); + }*/ + } + + return this._instance; +}; + + +/** + * Simply return 0. + * + * @return {Number} Always returns 0. + */ + +qx.lang.Function.returnZero = function() { + return 0; +}; + + +/** + * Simply return a negative index (-1). + * + * @return {Number} Always returns -1. + */ + +qx.lang.Function.returnNegativeIndex = function() { + return -1; +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Generics.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Generics.js new file mode 100644 index 0000000000..df590dea9f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Generics.js @@ -0,0 +1,138 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#require(qx.lang.Core) + +************************************************************************ */ + +/** + * Support string/array generics as introduced with JavaScript 1.6 for + * all browsers. + * + * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics + * + * *Array* + * + * * join + * * reverse + * * sort + * * push + * * pop + * * shift + * * unshift + * * splice + * * concat + * * slice + * * indexOf + * * lastIndexOf + * * forEach + * * map + * * filter + * * some + * * every + * + * *String* + * + * * quote + * * substring + * * toLowerCase + * * toUpperCase + * * charAt + * * charCodeAt + * * indexOf + * * lastIndexOf + * * toLocaleLowerCase + * * toLocaleUpperCase + * * localeCompare + * * match + * * search + * * replace + * * split + * * substr + * * concat + * * slice + */ +qx.OO.defineClass("qx.lang.Generics", +{ + map : + { + "Array" : [ + "join", "reverse", "sort", "push", "pop", "shift", "unshift", + "splice", "concat", "slice", "indexOf", "lastIndexOf", "forEach", + "map", "filter", "some", "every" + ], + + "String" : [ + "quote", "substring", "toLowerCase", "toUpperCase", "charAt", + "charCodeAt", "indexOf", "lastIndexOf", "toLocaleLowerCase", + "toLocaleUpperCase", "localeCompare", "match", "search", + "replace", "split", "substr", "concat", "slice" + ] + }, + + /** + * Make a method of an object generic and return the generic functions. + * The generic function takes as first parameter the object the method operates on. + * + * TODO: maybe mode this function to qx.lang.Function + * + * @param obj {Object} the object in which prototype the function is defined. + * @param func {String} name of the method to wrap. + * + * @return {Function} wrapped method. This function takes as first argument an + * instance of obj and as following arguments the arguments of the original method. + */ + _wrap : function(obj, func) + { + return function(s) { + return obj.prototype[func].apply(s, Array.prototype.slice.call(arguments, 1)); + } + }, + + /** + * Initialize all gernic function defined in JavaScript 1.6. + */ + init : function() + { + var map = qx.lang.Generics.map; + + + + for (var key in map) + { + var obj = window[key]; + var arr = map[key]; + + for (var i=0, l=arr.length; i<l; i++) + { + var func = arr[i]; + + if (!obj[func]) { + obj[func] = qx.lang.Generics._wrap(obj, func); + } + } + } + } +}); + +qx.lang.Generics.init(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Number.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Number.js new file mode 100644 index 0000000000..b90fce337f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Number.js @@ -0,0 +1,89 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Helper functions for numbers. + * + * The native JavaScript Number is not modified by this class. + * + * The additions implemented here may be added directly to the native Number + * by a setting in {@link qx.lang.Prototypes}. This feature is not enabled by + * default. + */ +qx.OO.defineClass("qx.lang.Number"); + +/** + * Check whether the number is in a given range + * + * @param nr {Number} the number to check + * @param vmin {Integer} lower bound of the range + * @param vmax {Integer} upper bound of the range + * @return {Boolean} whether the number is >= vmin and <= vmax + */ +qx.lang.Number.isInRange = function(nr, vmin, vmax) { + return nr >= vmin && nr <= vmax; +}; + + +/** + * Check whether the number is between a given range + * + * @param nr {Number} the number to check + * @param vmin {Integer} lower bound of the range + * @param vmax {Integer} upper bound of the range + * @return {Boolean} whether the number is > vmin and < vmax + */ +qx.lang.Number.isBetweenRange = function(nr, vmin, vmax) { + return nr > vmin && nr < vmax; +}; + + +/** + * Limit the nuber to a given range + * + * * If the number is greater than the upper bound, the upper bound is returned + * * If the number is smaller than the lower bound, the lower bound is returned + * * If the number is in the range, the number is retuned + * + * @param nr {Number} the number to limit + * @param vmin {Integer} lower bound of the range + * @param vmax {Integer} upper bound of the range + * @return {Integer} the limited number + */ +qx.lang.Number.limit = function(nr, vmin, vmax) +{ + if (typeof vmax === "number" && nr > vmax) + { + return vmax; + } + else if (typeof vmin === "number" && nr < vmin) + { + return vmin; + } + else + { + return nr; + } +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Object.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Object.js new file mode 100644 index 0000000000..7b725b15ce --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Object.js @@ -0,0 +1,219 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Helper functions to handle Object as a Hash map. + */ +qx.OO.defineClass("qx.lang.Object"); + +/** + * Check if the hash has any keys + * + * @param map {Object} the map to check + * @return {Boolean} whether the map has any keys + */ +qx.Class.isEmpty = function(map) +{ + for (var s in map) { + return false; + } + + return true; +}; + + +/** + * Check whether the number of objects in the maps is at least "lenght" + * + * @param map {Object} the map to check + * @param length {Integer} minimum number of objects in the map + * @return {Boolean} whether the map contains at least "lenght" objects. + */ +qx.Class.hasMinLength = function(map, length) +{ + var i=0; + + for (var s in map) + { + if ((++i)>=length) { + return true; + } + } + + return false; +}; + + +/** + * Get the number of objects in the map + * + * @param map {Object} the map + * @return {Integer} number of objects in the map + */ +qx.Class.getLength = function(map) +{ + var i=0; + + for (var s in map) { + i++; + } + + return i; +}; + + +/** + * Get the keys of a map as array + * + * @param map {Object} the map + * @return {Array} array of the keys of the map + */ +qx.Class.getKeys = function(map) +{ + var r = []; + for (var s in map) { + r.push(s); + } + + return r; +}; + + +/** + * Get the keys of a map as string + * + * @param map {Object} the map + * @return {String} String of the keys of the map + * The keys are separated by ", " + */ +qx.Class.getKeysAsString = function(map) { + return qx.lang.Object.getKeys(map).join(", "); +}; + + +/** + * Get the values of a map as array + * + * @param map {Object} the map + * @return {Array} array of the values of the map + */ +qx.Class.getValues = function(map) +{ + var r = []; + for (var s in map) { + r.push(map[s]); + } + + return r; +}; + + +/** + * Merge two objects. + * + * If the Objects both have the same key, the value of the second object is taken. + * + * @param vObjectA {Object} target object + * @param vObjectB {Object} object to be merged + * @return {Object} ObjectA with merged values from ObjectB + */ +qx.Class.mergeWith = function(vObjectA, vObjectB) +{ + for (var vKey in vObjectB) { + vObjectA[vKey] = vObjectB[vKey]; + } + + return vObjectA; +}; + + +/** + * Merge two objects. Existing values will not be overwritten. + * + * If the Objects both have the same key, the value of the first object is taken. + * + * @param vObjectA {Object} target object + * @param vObjectB {Object} object to be merged + * @return {Object} vObjectA with merged values from vObjectB + */ +qx.Class.carefullyMergeWith = function(vObjectA, vObjectB) { + for (var vKey in vObjectB) + { + if (typeof vObjectA[vKey] === "undefined") { + vObjectA[vKey] = vObjectB[vKey]; + } + } + + return vObjectA; +}; + + +/** + * Merge a number of objects. + * + * @param vObjectA {Object} target object + * @param varargs {Object} variable number of objects to merged with vObjectA + * @return {Object} vObjectA with merged values from the other objects + */ +qx.Class.merge = function(vObjectA, varargs) +{ + var vLength = arguments.length; + + for (var i=1; i<vLength; i++) { + qx.lang.Object.mergeWith(vObjectA, arguments[i]); + } + + return vObjectA; +}; + + +/** + * Return a copy of an Object + * + * @param vObject {Object} Object to copy + * @return {Object} copy of vObject + */ +qx.Class.copy = function(vObject) { + return qx.lang.Object.mergeWith({}, vObject); +}; + + +/** + * Inverts a Map by exchanging the keys with the values. + * If the map has the same values for different keys, information will get lost. + * The values will be converted to Strings using the toString methos. + * + * @param vObject {Object} Map to invert + * @return {Object} inverted Map + */ +qx.Class.invert = function(vObject) { + var result = {}; + for (var key in vObject) { + var value = vObject[key].toString(); + result[value] = key; + } + return result; +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Prototypes.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Prototypes.js new file mode 100644 index 0000000000..c16c3aab52 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/Prototypes.js @@ -0,0 +1,91 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Extend the native JavaScript types Number, String and Array with the + * feature additions of {@link qx.lang.Number}, {@link qx.lang.String} and + * {@link qx.lang.Array}, respectively. + * + * Important: It is not recommended to modify the native types, as this + * may lead to incompatibilities with non-qooxdoo code or libraries. + * Therefore this feature is disabled by default (see default setting + * "enable"). All classes and features contributed to qooxdoo + * should work without this feature enabled! + */ +qx.OO.defineClass("qx.lang.Prototypes"); + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enable", false); + + + + + +/* +--------------------------------------------------------------------------- + PROTOTYPES MAPPER +--------------------------------------------------------------------------- +*/ + +/** + * Augment the prototype of the native JavaScript objects "String", + * "Number" and "Array" with the methods defined in the corresponding + * static classes. + * + * @see qx.lang.String + * @see qx.lang.Number + * @see qx.lang.Array + */ +qx.lang.Prototypes.init = function() +{ + var key, obj; + var objs = [ "String", "Number", "Array" ]; + + for (var i=0, len=objs.length; i<len; i++) + { + obj = objs[i]; + + for (key in qx.lang[obj]) + { + window[obj].prototype[key] = (function(key, obj) + { + return function() { + return qx.lang[obj][key].apply(null, Array.prototype.concat.call([this], Array.prototype.slice.call(arguments, 0))); + } + })(key, obj); + } + } +} + +if (qx.Settings.getValueOfClass("qx.lang.Prototypes", "enable")) { + qx.lang.Prototypes.init(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/String.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/String.js new file mode 100644 index 0000000000..c2e9e8872d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/lang/String.js @@ -0,0 +1,279 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * String helper functions + * + * The native JavaScript String is not modified by this class. However, + * there are modifications to the native String in {@link qx.lang.Core} for + * browsers that do not support certain features. + * + * The additions implemented here may be added directly to native String by + * a setting in {@link qx.lang.Prototypes}. This feature is not enabled by + * default. + * + * The string/array generics introduced in JavaScript 1.6 are supported by + * {@link qx.lang.Generics}. + */ +qx.OO.defineClass("qx.lang.String"); + + +/** + * converts a string seperated by '-' to camel case. + * Example: + * <pre>qx.lang.String.toCamelCase("to-camel-case") == "toCamelCase"</pre> + * + * @param str {String} string seperated by '-' + * @return {String} camel case string + */ +qx.Class.toCamelCase = function(str) +{ + var vArr = str.split("-"), vLength = vArr.length; + + if(vLength == 1) { + return vArr[0]; + } + + var vNew = str.indexOf("-") == 0 ? vArr[0].charAt(0).toUpperCase() + vArr[0].substring(1) : vArr[0]; + + for (var vPart, i=1; i<vLength; i++) + { + vPart = vArr[i]; + vNew += vPart.charAt(0).toUpperCase() + vPart.substring(1); + } + + return vNew; +}; + + +/** + * removes white space from the left side of a string + * + * @param str {String} the string to trim + * @return {String} + */ +qx.Class.trimLeft = function(str) { + return str.replace(/^\s+/, ""); +}; + + +/** + * removes white space from the right side of a string + * + * @param str {String} the string to trim + * @return {String} + */ +qx.Class.trimRight = function(str) { + return str.replace(/\s+$/, ""); +}; + + +/** + * removes white space from the left and the right side of a string + * + * @param str {String} the string to trim + * @return {String} + */ +qx.Class.trim = function(str) { + return str.replace(/^\s+|\s+$/g, ""); +}; + + +/** + * Check whether the string starts with the given substring + * + * @param fullstr {String} the string to search in + * @param substr {String} the substring to look for + * @return {Boolean} whether the string starts with the given substring + */ +qx.Class.startsWith = function(fullstr, substr) { + return !fullstr.indexOf(substr); +}; + + +/** + * Check whether the string ends with the given substring + * + * @param fullstr {String} the string to search in + * @param substr {String} the substring to look for + * @return {Boolean} whether the string ends with the given substring + */ +qx.Class.endsWith = function(fullstr, substr) { + return fullstr.lastIndexOf(substr) === fullstr.length-substr.length; +}; + + +/** + * Pad a string up to a given length. Padding characters are added to the left of the string. + * + * @param str {String} the string to pad + * @param length {Integer} the final length of the string + * @param ch {String?"0"} character used to fill up the string + * @return {String} paddded string + */ +qx.Class.pad = function(str, length, ch) +{ + if (typeof ch === "undefined") { + ch = "0"; + } + + var temp = ""; + + for (var i=str.length; i<length; i++) { + temp += ch; + } + + return temp + str; +}; + + +/** + * Convert the first character of the string to upper case. + * + * @param str {String} the string + * @return {String} the string with a upper case first character + */ +qx.Class.toFirstUp = function(str) { + return str.charAt(0).toUpperCase() + str.substr(1); +}; + + +/** + * Add a list item to a serialized list string + * Example: + * <pre>qx.lang.String.addListItem("red, yellow, green", "blue", ", ") == "red, yellow, green, blue"</pre> + * + * @param str {String} serialized list. The items are seperated by "sep" + * @param item {String} list item to be added + * @param sep {String?","} separator + * @return {String} the string with the added item + */ +qx.Class.addListItem = function(str, item, sep) +{ + if (str == item || str == "") + { + return item; + } + + if (sep == null) { + sep = ","; + } + + var a = str.split(sep); + + if (a.indexOf(item) == -1) + { + a.push(item); + return a.join(sep); + } + else + { + return str; + } + +}; + + +/** + * Remove a list item from a serialized list string + * Example: + * <pre>qx.lang.String.removeListItem("red, yellow, green", "yellow", ", ") == "red, green, blue"</pre> + * + * @param str {String} serialized list. The items are seperated by "sep" + * @param item {String} list item to be removed + * @param sep {String?","} separator + * @return {String} the string with the removed item + */ +qx.Class.removeListItem = function(str, item, sep) +{ + if (str == item || str == "") + { + return ""; + } + else + { + if (sep == null) { + sep = ","; + } + + var a = str.split(sep); + var p = a.indexOf(item); + + if (p === -1) { + return str; + } + + do { a.splice(p, 1); } + while((p = a.indexOf(item)) != -1); + + return a.join(sep); + } +}; + + +/** + * Check whether the string contains a given substring + * + * @param str {String} the string + * @param substring {String} substring to search for + * @return {Boolean} whether the string contains the substring + */ +qx.Class.contains = function(str, substring) { + return str.indexOf(substring) != -1; +}; + + +/** + * Print a list of arguments using a format string + * In the format string occurences of %n are replaced by the n'th element of the args list. + * Example: + * <pre>qx.lang.String.format("Hello %1, my name is %2", ["Egon", "Franz"]) == "Hello Egon, my name is Franz"</pre> + * + * @param pattern {String} format string + * @param args {Array} array of arguments to insert into the format string + * @return {String} + */ +qx.Class.format = function(pattern, args) +{ + var str = pattern; + + for (var i=0; i<args.length; i++) { + str = str.replace(new RegExp("%" + (i+1), "g"), args[i]); + } + + return str; +}; + + +/** + * Escapes all chars that have a special meaning in regular expressions + * + * @param str {String} the string where to escape the chars. + * @return {String} the string with the escaped chars. + */ +qx.Class.escapeRegexpChars = function(str) { + return str.replace(/([\\\.\(\)\[\]\{\}\^\$\?\+\*])/g, "\\$1"); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Date.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Date.js new file mode 100644 index 0000000000..7383bd5a17 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Date.js @@ -0,0 +1,429 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/** + * Create a new instance of qx.nls.Date + */ +qx.OO.defineClass("qx.locale.Date"); + + +/** + * Get AM marker for time definitions + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} translated AM marker. + */ +qx.Class.getAmMarker = function(locale) { + return new qx.locale.LocalizedString("cldr_am", [], locale); +}; + + +/** + * Get PM marker for time definitions + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} translated PM marker. + */ +qx.Class.getPmMarker = function(locale) { + return new qx.locale.LocalizedString("cldr_pm", [], locale); +}; + + +/** + * Return localized names of day names + * + * @param length {String} format of the day names. + * Possible values: "abbreviated", "narrow", "wide" + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString[]} array of localized day names starting with sunday. + */ +qx.Class.getDayNames = function(length, locale) { + if ( + length != "abbreviated" && + length != "narrow" && + length != "wide" + ) { + throw new Error('format must be one of "abbreviated", "narrow", "wide"'); + } + var days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]; + var names = []; + for (var i=0; i<days.length; i++) { + var key = "cldr_day_" + length + "_" + days[i]; + names.push(new qx.locale.LocalizedString(key, [], locale)); + } + return names; +}; + + +/** + * Return localized name of a week day name + * + * @param length {String} format of the day name. + * Possible values: "abbreviated", "narrow", "wide" + * @param day {Integer} day number. 0=sunday, 1=monday, ... + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} localized day name + */ +qx.Class.getDayName = function(length, day, locale) { + if ( + length != "abbreviated" && + length != "narrow" && + length != "wide" + ) { + throw new Error('format must be one of "abbreviated", "narrow", "wide"'); + } + var days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]; + var key = "cldr_day_" + length + "_" + days[day]; + return new qx.locale.LocalizedString(key, [], locale); +}; + + +/** + * Return localized names of month names + * + * @param length {String} format of the month names. + * Possible values: "abbreviated", "narrow", "wide" + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString[]} array of localized month names starting with january. + */ +qx.Class.getMonthNames = function(length, locale) { + if ( + length != "abbreviated" && + length != "narrow" && + length != "wide" + ) { + throw new Error('format must be one of "abbreviated", "narrow", "wide"'); + } + var names = []; + for (var i=0; i<12; i++) { + var key = "cldr_month_" + length + "_" + (i+1); + names.push(new qx.locale.LocalizedString(key, [], locale)); + } + return names; +}; + + +/** + * Return localized name of a month + * + * @param length {String} format of the month names. + * Possible values: "abbreviated", "narrow", "wide" + * @param month {Integer} index of the month. 0=january, 1=februrary, ... + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} localized month name + */ +qx.Class.getMonthName = function(length, month, locale) { + if ( + length != "abbreviated" && + length != "narrow" && + length != "wide" + ) { + throw new Error('format must be one of "abbreviated", "narrow", "wide"'); + } + var key = "cldr_month_" + length + "_" + (month+1); + return new qx.locale.LocalizedString(key, [], locale); +}; + + +/** + * Return localized date format string to be used with @{link qx.util.format.DateFormat}. + * + * @param size {String} format of the date format. + * Possible values: "short", "medium", "long", "full" + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} localized date format string + */ +qx.Class.getDateFormat = function(size, locale) { + if ( + size != "short" && + size != "medium" && + size != "long" && + size != "full" + ) { + throw new Error('format must be one of "short", "medium", "long", "full"'); + } + var key = "cldr_date_format_" + size; + return new qx.locale.LocalizedString(key, [], locale) +}; + + +/** + * Try to localize a date/time format string. + * + * If now localization is availible take the fallback format string + * + * @param canonical {String} format string containing only field information, and in a canonical order. + * Examples are "yyyyMMMM" for year + full month, or "MMMd" for abbreviated month + day. + * @param fallback {String} fallback format string if no localized version is found + * @param locale {String} optional locale to be used + * @return {String} best matching format string + */ +qx.Class.getDateTimeFormat = function(canonical, fallback, locale) { + var key = "cldr_date_time_format_" + canonical; + var localizedFormat = qx.locale.Manager.getInstance().translate(key, [], locale); + if (localizedFormat == key) { + localizedFormat = fallback; + } + return localizedFormat; +}; + + +/** + * Return localized time format string to be used with {@link qx.util.format.DateFormat}. + * + * @param size {String} format of the time pattern. + * Possible values: "short", "medium", "long", "full" + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} localized time format string + */ +qx.Class.getTimeFormat = function(size, locale) { + if ( + size != "short" && + size != "medium" && + size != "long" && + size != "full" + ) { + throw new Error('format must be one of "short", "medium", "long", "full"'); + } + switch (size) { + case "short": + case "medium": + return qx.locale.Date.getDateTimeFormat("HHmm", "HH:mm"); + + case "long": + return qx.locale.Date.getDateTimeFormat("HHmmss", "HH:mm:ss"); + + case "full": + return qx.locale.Date.getDateTimeFormat("HHmmsszz", "HH:mm:ss zz"); + + default: + throw new Error("This case should never happen."); + } +}; + + +/** + * Return the day the week starts with + * + * Reference: Common Locale Data Repository (cldr) supplementalData.xml + * + * @param locale {String} optional locale to be used + * @return {Integer} index of the first day of the week. 0=sunday, 1=monday, ... + */ +qx.Class.getWeekStart = function(locale) { + var weekStart = { + // default is monday + + "MV": 5, // friday + + "AE": 6, // saturday + "AF": 6, + "BH": 6, + "DJ": 6, + "DZ": 6, + "EG": 6, + "ER": 6, + "ET": 6, + "IQ": 6, + "IR": 6, + "JO": 6, + "KE": 6, + "KW": 6, + "LB": 6, + "LY": 6, + "MA": 6, + "OM": 6, + "QA": 6, + "SA": 6, + "SD": 6, + "SO": 6, + "TN": 6, + "YE": 6, + + "AS": 0, // sunday + "AU": 0, + "AZ": 0, + "BW": 0, + "CA": 0, + "CN": 0, + "FO": 0, + "GE": 0, + "GL": 0, + "GU": 0, + "HK": 0, + "IE": 0, + "IL": 0, + "IS": 0, + "JM": 0, + "JP": 0, + "KG": 0, + "KR": 0, + "LA": 0, + "MH": 0, + "MN": 0, + "MO": 0, + "MP": 0, + "MT": 0, + "NZ": 0, + "PH": 0, + "PK": 0, + "SG": 0, + "TH": 0, + "TT": 0, + "TW": 0, + "UM": 0, + "US": 0, + "UZ": 0, + "VI": 0, + "ZA": 0, + "ZW": 0, + + "ET": 0, + "MW": 0, + "NG": 0, + "TJ": 0 + }; + var territory = qx.locale.Date._getTerritory(locale); + // default is monday + return weekStart[territory] != null ? weekStart[territory] : 1; +}; + + +/** + * Return the day the weekend starts with + * + * Reference: Common Locale Data Repository (cldr) supplementalData.xml + * + * @param locale {String} optional locale to be used + * @return {Integer} index of the first day of the weekend. 0=sunday, 1=monday, ... + */ +qx.Class.getWeekendStart = function(locale) { + var weekendStart = { + // default is saturday + + "EG": 5, // friday + "IL": 5, + "SY": 5, + + "IN": 0, // sunday + + "AE": 4, // thursday + "BH": 4, + "DZ": 4, + "IQ": 4, + "JO": 4, + "KW": 4, + "LB": 4, + "LY": 4, + "MA": 4, + "OM": 4, + "QA": 4, + "SA": 4, + "SD": 4, + "TN": 4, + "YE": 4 + }; + var territory = qx.locale.Date._getTerritory(locale); + // default is saturday + return weekendStart[territory] != null ? weekendStart[territory] : 6; +}; + + +/** + * Return the day the weekend ends with + * + * Reference: Common Locale Data Repository (cldr) supplementalData.xml + * + * @param locale {String} optional locale to be used + * @return {Integer} index of the last day of the weekend. 0=sunday, 1=monday, ... + */ +qx.Class.getWeekendEnd = function(locale) { + var weekendEnd = { + // default is sunday + + "AE": 5, // friday + "BH": 5, + "DZ": 5, + "IQ": 5, + "JO": 5, + "KW": 5, + "LB": 5, + "LY": 5, + "MA": 5, + "OM": 5, + "QA": 5, + "SA": 5, + "SD": 5, + "TN": 5, + "YE": 5, + "AF": 5, + "IR": 5, + + "EG": 6, // saturday + "IL": 6, + "SY": 6 + } + var territory = qx.locale.Date._getTerritory(locale); + // default is sunday + return weekendEnd[territory] != null ? weekendEnd[territory] : 0; +}; + + +/** + * Returns whether a certain day of week belongs to the week end. + * + * @param day {Integer} index of the day. 0=sunday, 1=monday, ... + * @param locale {String} optional locale to be used + * @return {Boolean} whether the given day is a weekend day + */ +qx.Class.isWeekend = function(day, locale) { + var weekendStart = qx.locale.Date.getWeekendStart(locale); + var weekendEnd = qx.locale.Date.getWeekendEnd(locale); + if (weekendEnd > weekendStart) { + return ( + (day >= weekendStart) && + (day <= weekendEnd) + ); + } else { + return ( + (day >= weekendStart) || + (day <= weekendEnd) + ); + } +}; + + +/** + * Extract the territory part from a locale + * + * @param locale {String} the locale + * @return {String} territory + */ +qx.Class._getTerritory = function(locale) { + if (locale) { + var territory = locale.split("_")[1] || locale; + } else { + territory = + qx.locale.Manager.getInstance().getTerritory() || + qx.locale.Manager.getInstance().getLanguage(); + }; + return territory.toUpperCase(); +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Key.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Key.js new file mode 100644 index 0000000000..beabac08f3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Key.js @@ -0,0 +1,116 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/** + * Create a new instance of qx.nls.Date + */ +qx.OO.defineClass("qx.locale.Key"); + + +/** + * Return localized name of a key identifier + * @{link qx.event.handler.KeyEventHandler} + * + * @param size {String} format of the key identifier. + * Possible values: "short", "full" + * @param keyIdentifier {String} key identifier to translate {@link qx.event.handler.KeyEventHandler} + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} localized key name + */ +qx.Class.getKeyName = function(size, keyIdentifier, locale) { + if ( + size != "short" && + size != "full" + ) { + throw new Error('format must be one of: "short", "full"'); + } + + var key = "key_" + size + "_" + keyIdentifier; + var localizedKey = new qx.locale.LocalizedString(key, [], locale); + if (localizedKey == key) { + return qx.locale.Key._keyNames[key] || keyIdentifier; + } else { + return localizedKey; + } +}; + + +( function() { + var keyNames = {}; + var Manager = qx.locale.Manager; + + // TRANSLATION: short representation of key names + keyNames[Manager.marktr("key_short_Backspace")] = "Backspace"; + keyNames[Manager.marktr("key_short_Tab")] = "Tab"; + keyNames[Manager.marktr("key_short_Space")] = "Space"; + keyNames[Manager.marktr("key_short_Enter")] = "Enter"; + keyNames[Manager.marktr("key_short_Shift")] = "Shift"; + keyNames[Manager.marktr("key_short_Control")] = "Ctrl"; + keyNames[Manager.marktr("key_short_Alt")] = "Alt"; + keyNames[Manager.marktr("key_short_CapsLock")] = "Caps"; + keyNames[Manager.marktr("key_short_Meta")] = "Meta"; + keyNames[Manager.marktr("key_short_Escape")] = "Esc"; + keyNames[Manager.marktr("key_short_Left")] = "Left"; + keyNames[Manager.marktr("key_short_Up")] = "Up"; + keyNames[Manager.marktr("key_short_Right")] = "Right"; + keyNames[Manager.marktr("key_short_Down")] = "Down"; + keyNames[Manager.marktr("key_short_PageUp")] = "PgUp"; + keyNames[Manager.marktr("key_short_PageDown")] = "PgDn"; + keyNames[Manager.marktr("key_short_End")] = "End"; + keyNames[Manager.marktr("key_short_Home")] = "Home"; + keyNames[Manager.marktr("key_short_Insert")] = "Ins"; + keyNames[Manager.marktr("key_short_Delete")] = "Del"; + keyNames[Manager.marktr("key_short_NumLock")] = "Num"; + keyNames[Manager.marktr("key_short_PrintScreen")] = "Print"; + keyNames[Manager.marktr("key_short_Scroll")] = "Scroll"; + keyNames[Manager.marktr("key_short_Pause")] = "Pause"; + keyNames[Manager.marktr("key_short_Win")] = "Win"; + keyNames[Manager.marktr("key_short_Apps")] = "Apps"; + + // TRANSLATION: full/long representation of key names + keyNames[Manager.marktr("key_full_Backspace")] = "Backspace"; + keyNames[Manager.marktr("key_full_Tab")] = "Tabulator"; + keyNames[Manager.marktr("key_full_Space")] = "Space"; + keyNames[Manager.marktr("key_full_Enter")] = "Enter"; + keyNames[Manager.marktr("key_full_Shift")] = "Shift"; + keyNames[Manager.marktr("key_full_Control")] = "Control"; + keyNames[Manager.marktr("key_full_Alt")] = "Alt"; + keyNames[Manager.marktr("key_full_CapsLock")] = "CapsLock"; + keyNames[Manager.marktr("key_full_Meta")] = "Meta"; + keyNames[Manager.marktr("key_full_Escape")] = "Escape"; + keyNames[Manager.marktr("key_full_Left")] = "Left"; + keyNames[Manager.marktr("key_full_Up")] = "Up"; + keyNames[Manager.marktr("key_full_Right")] = "Right"; + keyNames[Manager.marktr("key_full_Down")] = "Down"; + keyNames[Manager.marktr("key_full_PageUp")] = "PageUp"; + keyNames[Manager.marktr("key_full_PageDown")] = "PageDown"; + keyNames[Manager.marktr("key_full_End")] = "End"; + keyNames[Manager.marktr("key_full_Home")] = "Home"; + keyNames[Manager.marktr("key_full_Insert")] = "Insert"; + keyNames[Manager.marktr("key_full_Delete")] = "Delete"; + keyNames[Manager.marktr("key_full_NumLock")] = "NumLock"; + keyNames[Manager.marktr("key_full_PrintScreen")] = "PrintScreen"; + keyNames[Manager.marktr("key_full_Scroll")] = "Scroll"; + keyNames[Manager.marktr("key_full_Pause")] = "Pause"; + keyNames[Manager.marktr("key_full_Win")] = "Win"; + keyNames[Manager.marktr("key_full_Apps")] = "Apps"; + qx.Class._keyNames = keyNames; +}) ();
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/LocalizedString.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/LocalizedString.js new file mode 100644 index 0000000000..a1c350e624 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/LocalizedString.js @@ -0,0 +1,70 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/** + * Create a new instance of qx.locale.LocalizedString + * + * @see qx.lang.String.format + * + * @param messageId {String} message id (may contain format strings) + * @param args {Object[]} array of objects, which are inserted into the format string. + * @param locale {String} optional locale to be used for translation + */ +qx.OO.defineClass("qx.locale.LocalizedString", qx.core.Object, +function(messageId, args, locale) { + qx.core.Object.call(this); + + this.setId(messageId); + this._locale = locale; + + var storedArguments = []; + for (var i=0; i<args.length; i++) + { + var arg = args[i]; + if (arg instanceof qx.locale.LocalizedString) { + // defer conversion to string + storedArguments.push(arg); + } else { + // force conversion to string + storedArguments.push(arg + ""); + } + } + + this.setArgs(storedArguments); +}); + + +/** message id */ +qx.OO.addProperty({ name: "id"}); + +/** list of arguments to be applied to the format string */ +qx.OO.addProperty({ name: "args"}); + + +/** + * Return translation of the string using the current locale + * + * @return {String} translation using the current locale + */ +qx.Proto.toString = function () { + return qx.locale.Manager.getInstance().translate(this.getId(), this.getArgs(), this._locale); +}; + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Manager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Manager.js new file mode 100644 index 0000000000..0b30e9456f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Manager.js @@ -0,0 +1,261 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + + +/** + * Create a new instance of qx.locale.Manager + */ +qx.OO.defineClass("qx.locale.Manager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); + + this._translationCatalog = {}; + this.setLocale(qx.core.Client.getInstance().getLocale() || this._defaultLocale); +}); + + +/** current locale. locale is an language code like de, de_AT, en, en_GB, fr, ... */ +qx.OO.addProperty({ name: "locale"}); + +qx.Proto._defaultLocale = "C"; + + +/** + * Get the language code of the currnt locale + * + * This is the first part of a locale definition. The language for "de_DE" would be "de" + * + * @return {String} language code + */ +qx.Proto.getLanguage = function() { + return this._language; +}; + + +/** + * Get the territory code of the currnt locale + * + * This is the second part of a locale definition. The territory for "de_DE" would be "DE" + * + * @return {String} territory code + */ +qx.Proto.getTerritory = function() { + return this.getLocale().split("_")[1] || ""; +} + + +/** + * Return the available application locales + * + * This corresponds to the Makefile APPLICATION_LOCALES setting + * + * @return {String[]} array of available locales + */ +qx.Proto.getAvailableLocales = function() { + var locales = []; + for (var locale in this._translationCatalog) { + if (locale != this._defaultLocale) { + locales.push(locale); + } + } + return locales; +}; + + +/** + * Extract the language part from a locale. + * + * @param locale {String} locale to be used + * @return {String} language + */ +qx.Proto._extractLanguage = function(locale) { + var language; + var pos = locale.indexOf("_"); + if (pos == -1) { + language = locale; + } else { + language = locale.substring(0, pos); + } + return language; +}; + + +qx.Proto._modifyLocale = function(propValue, propOldValue, propData) { + this._locale = propValue; + + var pos = propValue.indexOf("_"); + this._language = this._extractLanguage(propValue); + + return true; +}; + + +/** + * Add a translation to the translation manager + * + * @param languageCode {String} language code of the translation like de, de_AT, en, en_GB, fr, ... + * @param translationMap {Map} mapping of message identifiers (english text) to the target language + */ +qx.Proto.addTranslation = function(languageCode, translationMap) { + + if (this._translationCatalog[languageCode]) + { + for (var key in translationMap) { + this._translationCatalog[languageCode][key] = translationMap[key]; + } + } + else + { + this._translationCatalog[languageCode] = translationMap; + } +}; + + +/** + * Translate a message + * @see qx.lang.String.format + * + * @param messageId {String} message id (may contain format strings) + * @param varargs {Object} variable number of argumes applied to the format string + * @return {qx.locale.LocalizedString} + */ +qx.Class.tr = function(messageId, varargs) +{ + var args = qx.lang.Array.fromArguments(arguments); + args.splice(0, 1); + + return new qx.locale.LocalizedString(messageId, args); +}; + + +/** + * Translate a plural message + * + * Depending on the third argument the plursl or the singular form is chosen. + * + * @see qx.lang.String.format + * + * @param singularMessageId {String} message id of the singular form (may contain format strings) + * @param pluralMessageId {String} message id of the plural form (may contain format strings) + * @param count {Integer} if greater than 1 the plural form otherwhise the singular form is returned. + * @param varargs {Object} variable number of argumes applied to the format string + * @return {qx.locale.LocalizedString} + */ +qx.Class.trn = function(singularMessageId, pluralMessageId, count, varargs) +{ + var args = qx.lang.Array.fromArguments(arguments); + args.splice(0, 3); + + if (count > 1) + { + return new qx.locale.LocalizedString(pluralMessageId, args); + } + else + { + return new qx.locale.LocalizedString(singularMessageId, args); + } +}; + + +/** + * Translate a message with translation hint + * + * Depending on the third argument the plursl or the singular form is chosen. + * + * @see qx.lang.String.format + * + * @param hint {String} hint for the translator of the message. Will be included in the .pot file. + * @param messageId {String} message id (may contain format strings) + * @param varargs {Object} variable number of argumes applied to the format string + * @return {qx.locale.LocalizedString} + */ +qx.Class.trc = function(hint, messageId, varargs) +{ + var args = qx.lang.Array.fromArguments(arguments); + args.splice(0, 2); + + return new qx.locale.LocalizedString(messageId, args); +} + + +/** + * Mark the message for translation but return the original message. + * + * @param messageId {String} the message ID + * @return {String} messageId + */ +qx.Class.marktr = function(messageId) { + return messageId; +}; + + +/** + * Translate a message using the current locale and apply format string to the arguments. + * + * @param messageId {String} message id (may contain format strings) + * @param args {Object[]} array of objects, which are inserted into the format string. + * @param locale {String} optional locale to be used for translation + * @return {String} translated message. + */ +qx.Proto.translate = function(messageId, args, locale) +{ + var txt; + + if (locale) { + var language = this._extractLanguage(locale); + } else { + locale = this._locale; + language = this._language; + } + + if (!txt && this._translationCatalog[locale]) { + txt = this._translationCatalog[locale][messageId]; + } + + if (!txt && this._translationCatalog[language]) { + txt = this._translationCatalog[language][messageId]; + } + + if (!txt && this._translationCatalog[this._defaultLocale]) { + txt = this._translationCatalog[this._defaultLocale][messageId]; + } + + if (!txt) { + txt = messageId; + } + + if (args.length > 0) { + txt = qx.lang.String.format(txt, args) + } + return txt; +}; + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance;
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Number.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Number.js new file mode 100644 index 0000000000..09b3ed12fe --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/Number.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/** + * Create a new instance of qx.locale.Number + */ +qx.OO.defineClass("qx.locale.Number"); + + +/** + * Get deciaml separator for number formatting + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} deciaml separator. + */ +qx.Class.getDecimalSeparator = function(locale) { + return new qx.locale.LocalizedString("cldr_number_decimal_separator", [], locale); +}; + + +/** + * Get thousand grouping separator for number formatting + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} group separator. + */ +qx.Class.getGroupSeparator = function(locale) { + return new qx.locale.LocalizedString("cldr_number_group_separator", [], locale); +}; + + +/** + * Get percent format string + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} percent format string. + */ +qx.Class.getPercentFormat = function(locale) { + return new qx.locale.LocalizedString("cldr_number_percent_format", [], locale); +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/String.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/String.js new file mode 100644 index 0000000000..0c3725bd04 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/String.js @@ -0,0 +1,69 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/** + * Create a new instance of qx.locale.String + */ +qx.OO.defineClass("qx.locale.String"); + + +/** + * Get quotation start sign + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} quotation start sign + */ +qx.Class.getQuotationStart = function(locale) { + return new qx.locale.LocalizedString("cldr_quotationStart", [], locale); +}; + + +/** + * Get quotation end sign + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} quotation end sign + */ +qx.Class.getQuotationEnd = function(locale) { + return new qx.locale.LocalizedString("cldr_quotationEnd", [], locale); +}; + + +/** + * Get quotation alternative start sign + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} alternative quotation start sign + */ +qx.Class.getQuotationStart = function(locale) { + return new qx.locale.LocalizedString("cldr_alternateQuotationStart", [], locale); +}; + + +/** + * Get quotation alternative end sign + * + * @param locale {String} optional locale to be used + * @return {qx.locale.LocalizedString} alternative quotation end sign + */ +qx.Class.getQuotationEnd = function(locale) { + return new qx.locale.LocalizedString("cldr_alternateQuotationEnd", [], locale); +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/AlertAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/AlertAppender.js new file mode 100644 index 0000000000..4be7b9e9b5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/AlertAppender.js @@ -0,0 +1,67 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Andreas Ecker (ecker) + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(log) + +************************************************************************ */ + +/** + * An appender that writes each message to a native alert(). + * <p> + * This class does not depend on qooxdoo widgets, so it also works when there + * are problems with widgets or when the widgets are not yet initialized. + * <p> + * It allows to go through the log messages step-by-step, since the alert + * window temporarily halts the regular program execution. That way even + * the dispose process can easily be debugged. + */ +qx.OO.defineClass("qx.log.AlertAppender", qx.log.Appender, +function() { + qx.log.Appender.call(this); +}); + + +// overridden +qx.OO.changeProperty({ name:"useLongFormat", type:"boolean", defaultValue:false, allowNull:false }); + +// overridden +qx.Proto.appendLogEvent = function(evt) { + + // Append the message + var text = evt.logger.getName(); + if (evt.instanceId != null) { + text += " (" + evt.instanceId + ")"; + } + + alert("\n" + text + "\n" + this.formatLogEvent(evt)); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.log.Appender.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Appender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Appender.js new file mode 100644 index 0000000000..5df3dd3f5e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Appender.js @@ -0,0 +1,183 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) + +************************************************************************ */ + +/** + * An appender. Does the actual logging. + */ +qx.OO.defineClass("qx.log.Appender", qx.log.LogEventProcessor, +function() { + qx.log.LogEventProcessor.call(this); +}); + + +/** Whether the logger name and log level should be included in the formatted log message. */ +qx.OO.addProperty({ name:"useLongFormat", type:"boolean", defaultValue:true, allowNull:false }); + + +// overridden +qx.Proto.handleLogEvent = function(evt) { + if (this.decideLogEvent(evt) != qx.log.Filter.DENY) { + this.appendLogEvent(evt); + } +} + + +/** + * Appends a log event to the log. + * + * @param evt {Map} The event to append. + */ +qx.Proto.appendLogEvent = function(evt) { + throw new Error("appendLogEvent is abstract"); +} + + +/** + * Formats a log event. + * + * @param evt {Map} The log event to format. + * @return {String} The formatted event. + */ +qx.Proto.formatLogEvent = function(evt) { + var Logger = qx.log.Logger; + + var text = ""; + + // Append the time stamp + var time = new String(new Date().getTime() - qx._LOADSTART); + while (time.length < 6) { + time = "0" + time; + } + text += time; + + // Append the level + if (this.getUseLongFormat()) { + switch (evt.level) { + case Logger.LEVEL_DEBUG: text += " DEBUG: "; break; + case Logger.LEVEL_INFO: text += " INFO: "; break; + case Logger.LEVEL_WARN: text += " WARN: "; break; + case Logger.LEVEL_ERROR: text += " ERROR: "; break; + case Logger.LEVEL_FATAL: text += " FATAL: "; break; + } + } else { + text += ": "; + } + + // Append the indent + var indent = ""; + for (var i = 0; i < evt.indent; i++) { + indent += " "; + } + text += indent; + + // Append the logger name and instance + if (this.getUseLongFormat()) { + text += evt.logger.getName(); + if (evt.instanceId != null) { + text += "[" + evt.instanceId + "]"; + } + text += ": "; + } + + // Append the message + if (typeof evt.message == "string") { + text += evt.message; + } else { + // The message is an object -> Log a dump of the object + var obj = evt.message; + if (obj == null) { + text += "Object is null"; + } else { + text += "--- Object: " + obj + " ---\n"; + var attrArr = new Array(); + try { + for (var attr in obj) { + attrArr.push(attr); + } + } catch (exc) { + text += indent + " [not readable: " + exc + "]\n"; + } + attrArr.sort(); + for (var i = 0; i < attrArr.length; i++) { + try { + text += indent + " " + attrArr[i] + "=" + obj[attrArr[i]] + "\n"; + } + catch (exc) { + text += indent + " " + attrArr[i] + "=[not readable: " + exc + "]\n"; + } + } + text += indent + "--- End of object ---"; + } + } + + // Append the throwable + if (evt.throwable != null) { + var thr = evt.throwable; + + if (thr.name == null) { + text += ": " + thr; + } else { + text += ": " + thr.name; + } + if (thr.message != null) { + text += " - " + thr.message; + } + if (thr.number != null) { + text += " (#" + thr.number + ")"; + } + + if (thr.stack != null) { + text += "\n" + this._beautyStackTrace(thr.stack); + } + } + + return text; +} + + +/** + * Beautifies a stack trace. + * + * @param stack {String} the stack trace to beautify. + * @return {String} the beautified stack trace. + */ +qx.Proto._beautyStackTrace = function(stack) { + // e.g. "()@http://localhost:8080/webcomponent-test-SNAPSHOT/webcomponent/js/com/ptvag/webcomponent/common/log/Logger:253" + var lineRe = /@(.+):(\d+)$/gm; + var hit; + var out = ""; + var scriptDir = "/script/"; + while ((hit = lineRe.exec(stack)) != null) { + var url = hit[1]; + + var jsPos = url.indexOf(scriptDir); + var className = (jsPos == -1) ? url : url.substring(jsPos + scriptDir.length).replace(/\//g, "."); + + var lineNumber = hit[2]; + out += " at " + className + ":" + lineNumber + "\n"; + } + return out; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DefaultFilter.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DefaultFilter.js new file mode 100644 index 0000000000..47c18df4db --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DefaultFilter.js @@ -0,0 +1,59 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) + +************************************************************************ */ + +/** + * The default filter. Has a minimum level and can be enabled or disabled. + */ +qx.OO.defineClass("qx.log.DefaultFilter", qx.log.Filter, +function() { + qx.log.Filter.call(this); +}); + + +/** + * Whether the filter should be enabled. If set to false all log events + * will be denied. + */ +qx.OO.addProperty({ name:"enabled", type:"boolean", defaultValue:true, allowNull:false, getAlias:"isEnabled" }); + +/** + * The minimum log level. If set only log messages with a level greater or equal + * to the set level will be accepted. + */ +qx.OO.addProperty({ name:"minLevel", type:"number", defaultValue:null }); + + +// overridden +qx.Proto.decide = function(evt) { + var Filter = qx.log.Filter; + if (! this.isEnabled()) { + return Filter.DENY; + } else if (this.getMinLevel() == null) { + return Filter.NEUTRAL; + } else { + return (evt.level >= this.getMinLevel()) ? Filter.ACCEPT : Filter.DENY; + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DivAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DivAppender.js new file mode 100644 index 0000000000..506cae32a1 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/DivAppender.js @@ -0,0 +1,166 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(log) + +************************************************************************ */ + +/** + * An appender that writes all messages to a div element. + * + * This class does not depend on qooxdoo widgets, so it also works when there + * are problems with widgets or when the widgets are not yet initialized. + * + * @param divId {String ? "qx_log"} the ID of the div element to write the + * messages to. + */ +qx.OO.defineClass("qx.log.DivAppender", qx.log.Appender, +function(divId) { + qx.log.Appender.call(this); + + this._divId = divId ? divId : "qx_log"; +}); + + +/** + * The maximum number of messages to show. If null the number of messages is not + * limited. + */ +qx.OO.addProperty({ name:"maxMessages", type:"number", defaultValue:500 }); + +// overridden +qx.OO.changeProperty({ name:"useLongFormat", type:"boolean", defaultValue:false, allowNull:false }); + +/** The CSS class name for the head div {containing the clear button}. */ +qx.OO.addProperty({ name:"headClassName", type:"string", defaultValue:"log-head" }); + +/** The CSS class name for the body div {containing the log messages}. */ +qx.OO.addProperty({ name:"bodyClassName", type:"string", defaultValue:"log-body" }); + +/** The CSS class name for a div showing the name of the current group. */ +qx.OO.addProperty({ name:"groupClassName", type:"string", defaultValue:"log-group" }); + +/** The CSS class name for a div showing a debug message. */ +qx.OO.addProperty({ name:"debugClassName", type:"string", defaultValue:"log-debug" }); + +/** The CSS class name for a div showing a info message. */ +qx.OO.addProperty({ name:"infoClassName", type:"string", defaultValue:"log-info" }); + +/** The CSS class name for a div showing a warn message. */ +qx.OO.addProperty({ name:"warnClassName", type:"string", defaultValue:"log-warn" }); + +/** The CSS class name for a div showing a error message. */ +qx.OO.addProperty({ name:"errorClassName", type:"string", defaultValue:"log-error" }); + + +/** + * Creates an onclick handler that clears a div element. This method is used to + * create a minimum closure. + * + * @param logElem {Element} the element to clear when the handler is called. + * @return {Function} the handler. + */ +qx.Proto._createClearButtonHandler = function(logElem) { + return function(evt) { + logElem.innerHTML = ""; + } +} + + +// overridden +qx.Proto.appendLogEvent = function(evt) { + var Logger = qx.log.Logger; + + // Initialize the log element if nessesary + if (this._logElem == null) { + var divElem = document.getElementById(this._divId); + if (divElem == null) { + throw new Error("Logging div with ID " + this._divId + " not found"); + } + divElem.innerHTML = '<div class="' + this.getHeadClassName() + '"><button>Clear</button></div>' + + '<div class="' + this.getBodyClassName() + '"></div>'; + + this._clearBt = divElem.firstChild.firstChild; + this._logElem = divElem.lastChild; + + this._clearBt.onclick = this._createClearButtonHandler(this._logElem); + } + + // Append the group when needed + var group = evt.logger.getName(); + if (evt.instanceId != null) { + group += "[" + evt.instanceId + "]"; + } + + if (group != this._lastGroup) { + var elem = document.createElement("div"); + elem.className = this.getGroupClassName(); + elem.innerHTML = group; + + this._logElem.appendChild(elem); + this._lastGroup = group; + } + + // Append the message + var elem = document.createElement("div"); + switch (evt.level) { + case Logger.LEVEL_DEBUG: elem.className = this.getDebugClassName(); break; + case Logger.LEVEL_INFO: elem.className = this.getInfoClassName(); break; + case Logger.LEVEL_WARN: elem.className = this.getWarnClassName(); break; + case Logger.LEVEL_ERROR: elem.className = this.getErrorClassName(); break; + } + elem.innerHTML = this.formatLogEvent(evt).replace(/&/g, "&") + .replace(/</g, "<").replace(/ /g, "  ").replace(/[\n]/g, "<br>"); + this._logElem.appendChild(elem); + + // Remove superflous messages + while (this._logElem.childNodes.length > this.getMaxMessages()) { + this._logElem.removeChild(this._logElem.firstChild); + + if (this._removedMessageCount == null) { + this._removedMessageCount = 1; + } else { + this._removedMessageCount++; + } + } + + if (this._removedMessageCount != null) { + this._logElem.firstChild.className = ""; + this._logElem.firstChild.innerHTML = "(" + this._removedMessageCount + + " messages removed)"; + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this._clearBt) { + this._clearBt.onclick = null; + this._clearBt = null; + } + this._logElem = null; + + return qx.log.Appender.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Filter.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Filter.js new file mode 100644 index 0000000000..8cfc739307 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Filter.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) + +************************************************************************ */ + +/** + * A filter for log events. + */ +qx.OO.defineClass("qx.log.Filter", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + +/** + * Decidies whether a log event is accepted. + * + * @param evt {Map} The event to check. + * @return {Integer} {@link #ACCEPT}, {@link #DENY} or {@link #NEUTRAL}. + */ +qx.Proto.decide = function(evt) { + throw new Error("decide is abstract"); +} + + +/** {int} Specifies that the log event is accepted. */ +qx.Class.ACCEPT = 1; + +/** {int} Specifies that the log event is denied. */ +qx.Class.DENY = 2; + +/** {int} Specifies that the filter is neutral to the log event. */ +qx.Class.NEUTRAL = 3; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/FireBugAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/FireBugAppender.js new file mode 100644 index 0000000000..6b27588303 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/FireBugAppender.js @@ -0,0 +1,74 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 David Perez + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * David Perez (david-perez) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) + +************************************************************************ */ + +/** + * An appender that writes all messages to FireBug, a nice extension for debugging and developing under Firefox. + * <p> + * This class does not depend on qooxdoo widgets, so it also works when there + * are problems with widgets or when the widgets are not yet initialized. + * </p> + */ +qx.OO.defineClass('qx.log.FireBugAppender', qx.log.Appender, function() { + qx.log.Appender.call(this); +}); + +qx.Proto.appendLogEvent = function(evt) +{ + if (typeof console != 'undefined') + { + var log = qx.log.Logger; + var msg = this.formatLogEvent(evt); + + switch (evt.level) + { + case log.LEVEL_DEBUG: + if (console.debug) { + console.debug(msg); + } + break; + case log.LEVEL_INFO: + if (console.info) { + console.info(msg); + } + break; + case log.LEVEL_WARN: + if (console.warn) { + console.warn(msg); + } + break; + default: + if (console.error) { + console.error(msg); + } + break; + } + // Force a stack dump, for helping locating the error + if (evt.level > log.LEVEL_WARN && (!evt.throwable || !evt.throwable.stack) && console.trace) + { + console.trace(); + } + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/ForwardAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/ForwardAppender.js new file mode 100644 index 0000000000..05cc183a38 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/ForwardAppender.js @@ -0,0 +1,43 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(log) + +************************************************************************ */ + +/** + * An appender that forwards all log events to a log event processor. + * + * @param targetProcessor {LogEventProcessor} The log event processor Where to + * pass the log events. + */ +qx.OO.defineClass("qx.log.ForwardAppender", qx.log.Appender, +function(targetProcessor) { + qx.log.Appender.call(this); + + this._targetProcessor = targetProcessor; +}); + + +// overridden +qx.Proto.appendLogEvent = function(evt) { + this._targetProcessor.handleLogEvent(evt); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/LogEventProcessor.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/LogEventProcessor.js new file mode 100644 index 0000000000..a7ee918035 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/LogEventProcessor.js @@ -0,0 +1,143 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Processes log events. May be configured with filters in order to specify + * which log events should be processed. + */ +qx.OO.defineClass("qx.log.LogEventProcessor", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Appends a filter to the filter chain. + * + * @param filter {Filter} The filter to append. + */ +qx.Proto.addFilter = function(filter) { + if (this._filterArr == null) { + this._filterArr = [] + } + this._filterArr.push(filter); +} + + +/** + * Clears the filter chain. + */ +qx.Proto.clearFilters = function() { + this._filterArr = null; +} + + +/** + * Returns the head filter from the chain. Returns null if there are no filters. + * + * @return {Filter} the head filter from the chain. + */ +qx.Proto.getHeadFilter = function() { + return (this._filterArr == null || this._filterArr.length == 0) ? null : this._filterArr[0]; +} + + +/** + * Returns the default filter from the chain. If the head filter is no default + * filter, the chain will be cleared and a default filter will be created. + * + * @return {Filter} the default filter. + */ +qx.Proto._getDefaultFilter = function() { + var headFilter = this.getHeadFilter(); + if (! (headFilter instanceof qx.log.DefaultFilter)) { + // The head filter of the appender is no DefaultFilter + // (or the appender has no filters at all) + // -> Create a default handler and append it + this.clearFilters(); + headFilter = new qx.log.DefaultFilter(); + this.addFilter(headFilter); + } + + return headFilter; +} + + +/** + * Sets whether event processing should be enabled. + * <p> + * Note: This will clear all custom filters. + * + * @param enabled {Boolean} whether event processing should be enabled. + */ +qx.Proto.setEnabled = function(enabled) { + this._getDefaultFilter().setEnabled(enabled); +} + + +/** + * Sets the min level an event must have in order to be processed. + * <p> + * Note: This will clear all custom filters. + * + * @param minLevel {Integer} the new min level. + */ +qx.Proto.setMinLevel = function(minLevel) { + this._getDefaultFilter().setMinLevel(minLevel); +} + + +/** + * Decides whether a log event is processed. + * + * @param evt {Map} the event to check. + * @return {Integer} {@link Filter#ACCEPT}, {@link Filter#DENY} or + * {@link Filter#NEUTRAL}. + */ +qx.Proto.decideLogEvent = function(evt) { + var NEUTRAL = qx.log.Filter.NEUTRAL; + + if (this._filterArr != null) { + for (var i = 0; i < this._filterArr.length; i++) { + var decision = this._filterArr[i].decide(evt); + if (decision != NEUTRAL) { + return decision; + } + } + } + + // All filters are neutral, so are we + return NEUTRAL; +} + + +/** + * Processes a log event. + * + * @param evt {Map} The log event to process. + */ +qx.Proto.handleLogEvent = function(evt) { + throw new Error("handleLogEvent is abstract"); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Logger.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Logger.js new file mode 100644 index 0000000000..8f16559191 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/Logger.js @@ -0,0 +1,382 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) +#require(qx.log.WindowAppender) +#require(qx.log.FireBugAppender) +* +************************************************************************ */ + +/** + * A logger. Logs messages of one log category. + * + * @param name {String} The category name of this logger. (Normally a class or + * package name) + * @param parentLogger {Logger} The parent logger. + */ +qx.OO.defineClass("qx.log.Logger", qx.log.LogEventProcessor, +function(name, parentLogger) { + qx.log.LogEventProcessor.call(this); + + this._name = name; + this._parentLogger = parentLogger; +}); + + +/** + * Returns the name of this logger. (Normally a class or package name) + * + * @return {String} the name. + */ +qx.Proto.getName = function() { + return this._name; +} + + +/** + * Returns the parent logger. + * + * @return {Logger} the parent logger. + */ +qx.Proto.getParentLogger = function() { + return this._parentLogger; +} + + +/** + * Indents all following log messages by one. + * <p> + * This affects all log messages. Even those of other loggers. + */ +qx.Proto.indent = function() { + qx.log.Logger._indent++; +} + + +/** + * Unindents all following log messages by one. + * <p> + * This affects all log messages. Even those of other loggers. + */ +qx.Proto.unindent = function() { + qx.log.Logger._indent--; +} + + +/** + * Adds an appender. + * <p> + * If a logger has an appender, log events will not be passed to the + * appenders of parent loggers. If you want this behaviour, also append a + * {@link ForwardAppender}. + * + * @param appender {Appender} the appender to add. + */ +qx.Proto.addAppender = function(appender) { + if (this._appenderArr == null) { + this._appenderArr = []; + } + + this._appenderArr.push(appender); +} + + +/** + * Removes an appender. + * + * @param appender {Appender} the appender to remove. + */ +qx.Proto.removeAppender = function(appender) { + if (this._appenderArr != null) { + this._appenderArr.remove(appender); + } +} + + +/** + * Removes all appenders. + */ +qx.Proto.removeAllAppenders = function() { + this._appenderArr = null; +} + + +// overridden +qx.Proto.handleLogEvent = function(evt) { + var Filter = qx.log.Filter; + + var decision = Filter.NEUTRAL; + var logger = this; + while (decision == Filter.NEUTRAL && logger != null) { + decision = logger.decideLogEvent(evt); + logger = logger.getParentLogger(); + } + + if (decision != Filter.DENY) { + this.appendLogEvent(evt); + } +} + + +/** + * Passes a log event to the appenders. If the logger has no appenders the + * event will be passed to the appenders of the parent logger, and so on. + * + * @param evt {Map} The event to append. + */ +qx.Proto.appendLogEvent = function(evt) { + if (this._appenderArr != null && this._appenderArr.length != 0) { + for (var i = 0; i < this._appenderArr.length; i++) { + this._appenderArr[i].handleLogEvent(evt); + } + } else if (this._parentLogger != null) { + this._parentLogger.appendLogEvent(evt); + } +} + + +/** + * Logs a message. + * + * @param level {Integer} the log level. + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.log = function(level, msg, instanceId, exc) { + var evt = { logger:this, level:level, message:msg, throwable:exc, + indent:qx.log.Logger._indent, instanceId:instanceId } + this.handleLogEvent(evt); +} + + +/** + * Logs a debug message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.debug = function(msg, instanceId, exc) { + this.log(qx.log.Logger.LEVEL_DEBUG, msg, instanceId, exc); +} + + +/** + * Logs an info message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.info = function(msg, instanceId, exc) { + this.log(qx.log.Logger.LEVEL_INFO, msg, instanceId, exc); +} + + +/** + * Logs a warning message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.warn = function(msg, instanceId, exc) { + this.log(qx.log.Logger.LEVEL_WARN, msg, instanceId, exc); +} + + +/** + * Logs an error message. + * + * @param msg {var} the message to log. If this is not a string, the + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.error = function(msg, instanceId, exc) { + this.log(qx.log.Logger.LEVEL_ERROR, msg, instanceId, exc); +} + + +/** + * Logs a fatal message. + * + * @param msg {var} the message to log. If this is not a string, its + * object dump will be logged. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.fatal = function(msg, instanceId, exc) { + this.log(qx.log.Logger.LEVEL_FATAL, msg, instanceId, exc); +} + + +/** + * Resets the measure timer. + * + * @see #measure() + */ +qx.Proto.measureReset = function() { + if (this._totalMeasureTime != null) { + this.debug("Measure reset. Total measure time: " + this._totalMeasureTime + " ms"); + } + + this._lastMeasureTime = null; + this._totalMeasureTime = null; +} + + +/** + * Logs a debug message and measures the time since the last call of measure. + * + * @param msg {String} the message to log. + * @param instanceId {var ? null} the ID of the instance the log message comes from. + * @param exc {var ? null} the exception to log. + */ +qx.Proto.measure = function(msg, instanceId, exc) { + if (this._lastMeasureTime == null) { + msg = "(measure start) " + msg; + } else { + var delta = new Date().getTime() - this._lastMeasureTime; + + if (this._totalMeasureTime == null) { + this._totalMeasureTime = 0; + } + + this._totalMeasureTime += delta; + msg = "(passed time: " + delta + " ms) " + msg; + } + + this.debug(msg, instanceId, exc); + + this._lastMeasureTime = new Date().getTime(); +} + + +/** + * Logs the current stack trace as a debug message. + */ +qx.Proto.printStackTrace = function() { + try { + forced_exception.go; + } catch (exc) { + this.debug("Current stack trace", "", exc); + } +} + + +/** + * Returns the logger of a class. + * + * @param clazz {Function} The class of which to return the logger. + */ +qx.Class.getClassLogger = function(clazz) { + var logger = clazz._logger; + if (logger == null) { + // Get the parent logger + var classname = clazz.classname; + var splits = classname.split("."); + var currPackage = window; + var currPackageName = ""; + var parentLogger = qx.log.Logger.ROOT_LOGGER; + for (var i = 0; i < splits.length - 1; i++) { + currPackage = currPackage[splits[i]]; + currPackageName += ((i != 0) ? "." : "") + splits[i]; + + if (currPackage._logger == null) { + // This package has no logger -> Create one + currPackage._logger = new qx.log.Logger(currPackageName, parentLogger); + } + parentLogger = currPackage._logger; + } + + // Create the class logger + logger = new qx.log.Logger(classname, parentLogger); + clazz._logger = logger; + } + return logger; +} + + +/** {Integer} The current indent. */ +qx.Class._indent = 0; + +/** + * {Integer} The ALL level has the lowest possible rank and is intended to turn on + * all logging. + */ +qx.Class.LEVEL_ALL = 0; + +/** + * {Integer} The DEBUG Level designates fine-grained informational events that are + * most useful to debug an application. + */ +qx.Class.LEVEL_DEBUG = 200; + +/** + * {Integer} The INFO level designates informational messages that highlight the + * progress of the application at coarse-grained level. + */ +qx.Class.LEVEL_INFO = 500; + +/** {Integer} The WARN level designates potentially harmful situations. */ +qx.Class.LEVEL_WARN = 600; + +/** + * {Integer} The ERROR level designates error events that might still allow the + * application to continue running. + */ +qx.Class.LEVEL_ERROR = 700; + +/** + * {Integer} The FATAL level designates very severe error events that will + * presumably lead the application to abort. + */ +qx.Class.LEVEL_FATAL = 800; + +/** + * {Integer} The OFF has the highest possible rank and is intended to turn off + * logging. + */ +qx.Class.LEVEL_OFF = 1000; + + +/** + * {Logger} The root logger. This is the root of the logger tree. All loggers + * should be a child or grand child of this root logger. + * <p> + * This logger logs by default everything greater than level INFO to a log + * window. + */ +qx.Class.ROOT_LOGGER = new qx.log.Logger("root", null); +qx.Class.ROOT_LOGGER.setMinLevel(qx.log.Logger.LEVEL_DEBUG); + +if (typeof console != 'undefined' && console.debug) { + qx.Class.ROOT_LOGGER.addAppender(new qx.log.FireBugAppender()); +} else { + qx.Class.ROOT_LOGGER.addAppender(new qx.log.WindowAppender()); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/RingBufferAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/RingBufferAppender.js new file mode 100644 index 0000000000..d7c36f8217 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/RingBufferAppender.js @@ -0,0 +1,124 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(log) + +************************************************************************ */ + +/** + * An appender that writes all messages to a memory container. The messages + * can be retrieved later, f. i. when an error dialog pops up and the question + * arises what actions have caused the error. + * + */ +qx.OO.defineClass("qx.log.RingBufferAppender", qx.log.Appender, +function() { + qx.log.Appender.call(this); + + this._history = []; + this._nextIndexToStoreTo = 0; + this._appenderToFormatStrings = null; +}); + + +/** + * The maximum number of messages to hold. If null the number of messages is not + * limited. Warning: Changing this property will clear the events logged so far. + */ +qx.OO.addProperty({ name:"maxMessages", type:"number", defaultValue:50 }); + +qx.Proto._modifyMaxMessages = function(propValue, propOldValue, propData){ + this._history = []; + this._nextIndexToStoreTo = 0; +}; + +// overridden +qx.Proto.appendLogEvent = function(evt) { + var maxMessages = this.getMaxMessages(); + if (this._history.length < maxMessages){ + this._history.push(evt); + } else { + this._history[this._nextIndexToStoreTo++] = evt; + if (this._nextIndexToStoreTo >= maxMessages){ + this._nextIndexToStoreTo = 0; + } + } +}; + +/** + * Returns log events which have been logged previously. + * + * @param count {Integer} The number of events to retreive. If there are more events than the + * given count, the oldest ones will not be returned. + * @return {array} array of stored log events + */ +qx.Proto.retrieveLogEvents = function(count) { + if (count > this._history.length){ + count = this._history.length; + } + + var indexOfYoungestElementInHistory + = this._history.length == this.getMaxMessages() ? this._nextIndexToStoreTo - 1 + : this._history.length - 1; + var startIndex = indexOfYoungestElementInHistory - count + 1; + if (startIndex < 0){ + startIndex += this._history.length; + } + + var result; + if (startIndex <= indexOfYoungestElementInHistory){ + result = this._history.slice(startIndex, indexOfYoungestElementInHistory + 1); + } else { + result = this._history.slice(startIndex, this._history.length).concat( + this._history.slice(0, indexOfYoungestElementInHistory + 1) + ); + } + return result; +}; + +/** + * Returns a string holding the information of log events which have been logged previously. + * + * @param count {Integer} The number of events to retreive. If there are more events than the + * given count, the oldest ones will not be returned. + * @return {String} string + */ +qx.Proto.formatLogEvents = function(count) { + if (this._appenderToFormatStrings == null){ + this._appenderToFormatStrings = new qx.log.Appender(); + } + + var events = this.retrieveLogEvents(count); + var string = ""; + for(var idx=0; idx < events.length; idx++) { + string += this._appenderToFormatStrings.formatLogEvent(events[idx]) + "\n"; + } + return string; +}; + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.log.Appender.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/WindowAppender.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/WindowAppender.js new file mode 100644 index 0000000000..4bfc5e5bf4 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/log/WindowAppender.js @@ -0,0 +1,286 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) +#module(log) + +************************************************************************ */ + +/** + * An appender that writes all messages to a log window. + * <p> + * This class does not depend on qooxdoo widgets, so it also works when there + * are problems with widgets or when the widgets are not yet initialized. + * + * @param name {String ? "qx_log"} the name of the log window. + */ +qx.OO.defineClass("qx.log.WindowAppender", qx.log.Appender, +function(name) { + qx.log.Appender.call(this); + + this._id = qx.log.WindowAppender.register(this); + this._name = (name == null) ? "qx_log" : name; + + this._errorsPreventingAutoCloseCount = 0; + + this._logWindowOpened = false; +}); + + +/** + * The maximum number of messages to show. If null the number of messages is not + * limited. + */ +qx.OO.addProperty({ name:"maxMessages", type:"number", defaultValue:500 }); + +/** Whether the window should appear under the main window. */ +qx.OO.addProperty({ name:"popUnder", type:"boolean", defaultValue:false, allowNull:false }); + +/** Whether the window should automatically be closed when its creating page is unloaded and + * errors have been logged. Note that errors that have been logged before this property has been + * turned off will be ignored. Warning: Turning this off may create a memory hole because the disposer + * of this class will auto-close the window, i. e. it may stay open after dispose(), still holding + * memory. However, for diagnostics it is often more important to get information about errors + * than to save memory. + */ +qx.OO.addProperty({ name:"autoCloseWithErrors", type:"boolean", defaultValue:true, allowNull:false }); + + +/** + * Creates and opens the log window if it doesn't alread exist. + */ +qx.Proto.openWindow = function() { + if (this._logWindowOpened) { + // The window is already open -> Nothing to do + return; + } + + // Open the logger window + var winWidth = 600; + var winHeight = 350; + var winLeft = window.screen.width - winWidth; + var winTop = window.screen.height - winHeight; + var params = "toolbar=no,scrollbars=yes,resizable=yes," + + "width=" + winWidth + ",height=" + winHeight + + ",left=" + winLeft + ",top=" + winTop; + + // NOTE: In window.open the browser will process the event queue. + // Which means that other log events may arrive during this time. + // The log window is then in an inconsistent state, because the + // this._logElem is not created yet. These events will be added to the + // this._logEventQueue and logged after this._logElem is created. + this._logWindow = window.open("", this._name, params); + + if (!this._logWindow || this._logWindow.closed) + { + if (!this._popupBlockerWarning) { + alert("Couldn't open debug window. Please disable your popup blocker!"); + } + + this._popupBlockerWarning = true; + return; + } + + // Seems to be OK now. + this._popupBlockerWarning = false; + + // Store that window is open + this._logWindowOpened = true; + + if (this.getPopUnder()) { + this._logWindow.blur(); + window.focus(); + } + + var logDocument = this._logWindow.document; + // NOTE: We have to use a static onunload handler, because an onunload + // that is set later using DOM is ignored completely. + // (at least in Firefox, but maybe in IE, too) + logDocument.open(); + logDocument.write("<html><head><title>" + this._name + "</title></head>" + + '<body onload="qx = opener.qx;" onunload="try{qx.log.WindowAppender._registeredAppenders[' + this._id + ']._autoCloseWindow()}catch(e){}">' + + '<pre id="log" wrap="wrap" style="font-size:11"></pre></body></html>'); + logDocument.close(); + + this._logElem = logDocument.getElementById("log"); + + // Log the events from the queue + if (this._logEventQueue != null) { + for (var i = 0; i < this._logEventQueue.length; i++) { + this.appendLogEvent(this._logEventQueue[i]); + } + this._logEventQueue = null; + } +}; + + +/** + * Closes the log window. + */ +qx.Proto.closeWindow = function() { + if (this._logWindow != null) { + this._logWindow.close(); + this._logWindow = null; + this._logElem = null; + this._logWindowOpened = false; + } +}; + +/** + * Called when the window should be automatically closed (because the page that opened + * is is unloaded). Will only close the window if the autoClose***-Properties allow it + */ +qx.Proto._autoCloseWindow = function() { + if (this.getAutoCloseWithErrors() || this._errorsPreventingAutoCloseCount == 0){ + this.closeWindow(); + } else { + //Show message why auto-close has failed + this._showMessageInLog("Log window message: <b>Note: " + this._errorsPreventingAutoCloseCount + + " errors have been recorded, keeping log window open.</b>"); + } +}; + +/** + * Appends a line to the log showing the given text + * @param msg {String} message to show, may be HTML + */ +qx.Proto._showMessageInLog = function(msg) { + //Create dummy log event and use appendLogEvent() + //Reason is that it is rather complicated to get something into the log + //window when it is not already open -> reuse the existing code + //which does event queuing in such a case + var dummyEvent = {message: msg, isDummyEventForMessage : true}; + this.appendLogEvent(dummyEvent); +}; + + +// overridden +qx.Proto.appendLogEvent = function(evt) { + if (!this._logWindowOpened) { + this._logEventQueue = []; + this._logEventQueue.push(evt); + + this.openWindow(); + + // Popup-Blocker was active! + if (!this._logWindowOpened) { + return; + } + } else if (this._logElem == null) { + // The window is currenlty opening, but not yet finished + // -> Put the event in the queue + this._logEventQueue.push(evt); + } else { + var divElem = this._logWindow.document.createElement("div"); + if (evt.level >= qx.log.Logger.LEVEL_ERROR) { + divElem.style.backgroundColor = "#FFEEEE"; + if (!this.getAutoCloseWithErrors()){ + this._errorsPreventingAutoCloseCount += 1; + } + } else if (evt.level == qx.log.Logger.LEVEL_DEBUG) { + divElem.style.color = "gray"; + } + if (evt.isDummyEventForMessage){ + divElem.innerHTML = evt.message; + } else { + divElem.innerHTML = qx.html.String.fromText(this.formatLogEvent(evt)); + } + this._logElem.appendChild(divElem); + + while (this._logElem.childNodes.length > this.getMaxMessages()) { + this._logElem.removeChild(this._logElem.firstChild); + + if (this._removedMessageCount == null) { + this._removedMessageCount = 1; + } else { + this._removedMessageCount++; + } + } + + if (this._removedMessageCount != null) { + this._logElem.firstChild.innerHTML = "(" + this._removedMessageCount + + " messages removed)"; + } + + // Scroll to bottom + this._logWindow.scrollTo(0, this._logElem.offsetHeight); + } +} + +qx.Proto._modifyAutoCloseWithErrors = function(propValue, propOldValue, propData){ + if (!propValue && propOldValue){ + this._errorsPreventingAutoCloseCount = 0; + + //Show message in log so user can see which errors have been counted + this._showMessageInLog("Log window message: Starting error recording, any errors below this line will prevent the log window from closing"); + + } else if (propValue && !propOldValue){ + //Show message in log so user can see which errors have been counted + this._showMessageInLog("Log window message: Stopping error recording, discarding " + this._errorsPreventingAutoCloseCount + " errors."); + } + return true; +} + + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + this._autoCloseWindow(); + + return qx.log.Appender.prototype.dispose.call(this); +} + + +qx.Class._nextId = 1; +qx.Class._registeredAppenders = {}; + + +/** + * Registers a WindowAppender. This is used by the WindowAppender internally. + * You don't have to call this. + * + * @param appender {WindowAppender} the WindowAppender to register. + * @return {Integer} the ID. + */ +qx.Class.register = function(appender) { + var WindowAppender = qx.log.WindowAppender; + + var id = WindowAppender._nextId++; + WindowAppender._registeredAppenders[id] = appender; + + return id; +} + + +/** + * Returns a prviously registered WindowAppender. + * + * @param id {Integer} the ID of the wanted WindowAppender. + * @return {WindowAppender} the WindowAppender or null if no + * WindowAppender with this ID is registered. + */ +qx.Class.getAppender = function(id) { + return qx.log.WindowAppender._registeredAppenders[id]; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AliasManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AliasManager.js new file mode 100644 index 0000000000..e1247d8a81 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AliasManager.js @@ -0,0 +1,239 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * This singleton manage global resource aliases + * + * @event change {qx.event.type.Event} + */ +qx.OO.defineClass("qx.manager.object.AliasManager", qx.core.Target, +function() +{ + qx.core.Target.call(this); + + // Contains defined aliases (like icons/, widgets/, application/, ...) + this._aliases = {}; + + // Containes computed paths + this._uris = {}; + + // Define static alias from setting + this.add("static", this.getSetting("staticUri")); +}); + + + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("resourceUri", "../../resource"); +qx.Settings.setDefault("staticUri", qx.Settings.getValue("resourceUri") + "/static"); + + + + + +/* +--------------------------------------------------------------------------- + ALIAS MANAGMENT +--------------------------------------------------------------------------- +*/ + +/** + * Define an alias to a resource path + * + * @param vAlias {String} alias name for the resource path/url + * @param vUriStart {String} first part of URI for all images which use this alias + */ +qx.Proto.add = function(vAlias, vUriStart) +{ + this._aliases[vAlias] = vUriStart; + + // Cleanup old uris which use this alias + for (var vPath in this._uris) + { + if (vPath.substring(0, vPath.indexOf("/")) == vAlias) { + this._uris[vPath] = null; + } + } + + // Fire change event (for ImageManager, etc.) + this.createDispatchEvent("change"); +} + +/** + * Remove a previously defined alias + * + * @param vAlias {String} alias name for the resource path/url + */ +qx.Proto.remove = function(vAlias) +{ + delete this._aliases[vAlias]; + + // Cleanup old uris which use this alias + for (var vPath in this._uris) + { + if (vPath.substring(0, vPath.indexOf("/")) == vAlias) { + this._uris[vPath] = null; + } + } + + // Fire change event (for ImageManager, etc.) + this.createDispatchEvent("change"); +} + +/** + * Resolve an alias to the actual resource path/url + * + * @param vAlias {String} alias name for the resource path/url + * @return {String} resource path/url + */ +qx.Proto.resolve = function(vAlias) { + return this._aliases[vAlias]; +} + + + + + + +/* +--------------------------------------------------------------------------- + URI HANDLING +--------------------------------------------------------------------------- +*/ + +/** + * Resolve a path name to a resource URI taking the defined aliases into account + * and cache the result. + * + * If the first part of the path is a defined alias, the alias is resolved. + * Otherwhise the path is returned unmodified. + * + * @param vPath {String} path name + * @param vForceUpdate {Boolean} (default=false) wether the cached value should be ignored + * @return {String} reolved path/url + */ +qx.Proto.resolvePath = function(vPath, vForceUpdate) +{ + var vUri = this._uris[vPath]; + + if (vUri == null) { + vUri = this._uris[vPath] = this._computePath(vPath); + } + + // this.debug("URI: " + vPath + " => " + vUri); + + return vUri; +} + + +/** + * Resolve a path name to a resource URI taking the defined aliases into account. + * + * If the first part of the path is a defined alias, the alias is resolved. + * Otherwhise the path is returned unmodified. + * + * @param vPath {String} path name + * @return {String} reolved path/url + */ +qx.Proto._computePath = function(vPath) +{ + switch(vPath.charAt(0)) + { + case "/": + case ".": + return vPath; + + default: + if ( + qx.lang.String.startsWith(vPath, qx.net.Protocol.URI_HTTP) || + qx.lang.String.startsWith(vPath, qx.net.Protocol.URI_HTTPS) || + qx.lang.String.startsWith(vPath, qx.net.Protocol.URI_FILE) + ) { + return vPath; + } + + var vAlias = vPath.substring(0, vPath.indexOf("/")); + var vResolved = this._aliases[vAlias]; + + if (vResolved != null) { + return vResolved + vPath.substring(vAlias.length); + } + + return vPath; + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Disposer + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._aliases = null; + this._uris = null; + + return qx.core.Target.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AppearanceManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AppearanceManager.js new file mode 100644 index 0000000000..cf7ea1edb4 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/AppearanceManager.js @@ -0,0 +1,154 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/** + * This singleton manages the current theme + */ +qx.OO.defineClass("qx.manager.object.AppearanceManager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); + + // Themes + this._appearanceThemes = {}; +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("appearanceTheme", "qx.theme.appearance.Classic"); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** currently used apperance theme */ +qx.OO.addProperty({ name : "appearanceTheme", type : "object", allowNull : false, instance : "qx.renderer.theme.AppearanceTheme" }); + + + + + + +/* +--------------------------------------------------------------------------- + REGISTRATION +--------------------------------------------------------------------------- +*/ + +/** + * Register an theme class. + * The theme is applied if it is the default apperance + * + * @param vThemeClass {qx.renderer.theme.AppearanceTheme} + */ +qx.Proto.registerAppearanceTheme = function(vThemeClass) +{ + this._appearanceThemes[vThemeClass.classname] = vThemeClass; + + if (vThemeClass.classname == this.getSetting("appearanceTheme")) { + this.setAppearanceTheme(vThemeClass.getInstance()); + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyAppearanceTheme = function(propValue, propOldValue, propData) +{ + var vComp = qx.core.Init.getInstance().getComponent(); + + if (vComp && vComp.isUiReady()) { + qx.ui.core.ClientDocument.getInstance()._recursiveAppearanceThemeUpdate(propValue, propOldValue); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Disposer + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Themes + this._appearanceThemes = null; + + return qx.manager.object.ObjectManager.prototype.dispose.call(this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ColorManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ColorManager.js new file mode 100644 index 0000000000..4298aeda0b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ColorManager.js @@ -0,0 +1,230 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#optional(qx.ui.form.Button) +#embed(qx.icontheme/16/actions/format-color.png) + +************************************************************************ */ + +qx.OO.defineClass("qx.manager.object.ColorManager", qx.manager.object.ObjectManager, +function() +{ + qx.manager.object.ObjectManager.call(this); + + // Themes + this._colorThemes = {}; + + // Contains the qx.renderer.color.ColorObjects which + // represent a themed color. + this._dependentObjects = {}; +}); + + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("colorTheme", "qx.theme.color.WindowsRoyale"); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "colorTheme", type : "object", allowNull : false, instance : "qx.renderer.theme.ColorTheme" }); + + + + + + +/* +--------------------------------------------------------------------------- + REGISTRATION +--------------------------------------------------------------------------- +*/ + +qx.Proto.registerColorTheme = function(vThemeClass) +{ + this._colorThemes[vThemeClass.classname] = vThemeClass; + + if (vThemeClass.classname == this.getSetting("colorTheme")) { + this.setColorTheme(vThemeClass.getInstance()); + } +} + +qx.Proto.setColorThemeById = function(vId) { + this.setColorTheme(this._colorThemes[vId].getInstance()); +} + + + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS FOR qx.renderer.color.ColorOBJECTS +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(oObject) +{ + var vValue = oObject.getValue(); + + this._objects[vValue] = oObject; + + if (oObject.isThemedColor()) { + this._dependentObjects[vValue] = oObject; + } +} + +qx.Proto.remove = function(oObject) +{ + var vValue = oObject.getValue(); + + delete this._objects[vValue]; + delete this._dependentObjects[vValue]; +} + +qx.Proto.has = function(vValue) { + return this._objects[vValue] != null; +} + +qx.Proto.get = function(vValue) { + return this._objects[vValue]; +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyColorTheme = function(propValue, propOldValue, propData) +{ + propValue.compile(); + + for (var i in this._dependentObjects) { + this._dependentObjects[i]._updateTheme(propValue); + } + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.createThemeList = function(vParent, xCor, yCor) +{ + var vButton; + var vThemes = this._colorThemes; + var vIcon = "icon/16/actions/format-color.png"; + var vPrefix = "Color Theme: "; + var vEvent = "execute"; + + for (var vId in vThemes) + { + var vObj = vThemes[vId].getInstance(); + var vButton = new qx.ui.form.Button(vPrefix + vObj.getTitle(), vIcon); + + vButton.setLocation(xCor, yCor); + vButton.addEventListener(vEvent, new Function("qx.manager.object.ColorManager.getInstance().setColorThemeById('" + vId + "')")); + + vParent.add(vButton); + + yCor += 30; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Themes + this._colorThemes = null; + + // Cleanup dependent objects + for (var i in this._dependentObjects) { + delete this._dependentObjects[i]; + } + + delete this._dependentObjects; + + return qx.manager.object.ObjectManager.prototype.dispose.call(this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/IframeManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/IframeManager.js new file mode 100644 index 0000000000..f7337f4e6d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/IframeManager.js @@ -0,0 +1,77 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/** + * This singleton manages multiple instances of qx.ui.embed.Iframe. + * <p> + * The problem: When dragging over an iframe then all mouse events will be + * passed to the document of the iframe, not the main document. + * <p> + * The solution: In order to be able to track mouse events over iframes, this + * manager will block all iframes during a drag with a glasspane. + */ +qx.OO.defineClass("qx.manager.object.IframeManager", qx.manager.object.ObjectManager, +function(){ + qx.manager.object.ObjectManager.call(this); +}); + + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.handleMouseDown = function(evt) { + var iframeMap = this.getAll(); + + for (var key in iframeMap) { + var iframe = iframeMap[key]; + iframe.block(); + } +} + +qx.Proto.handleMouseUp = function(evt) { + var iframeMap = this.getAll(); + + for (var key in iframeMap) { + var iframe = iframeMap[key]; + iframe.release(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImageManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImageManager.js new file mode 100644 index 0000000000..a71b43488c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImageManager.js @@ -0,0 +1,315 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#optional(qx.ui.form.Button) +#embed(qx.icontheme/16/apps/preferences-desktop-theme.png) +#require(qx.manager.object.ImagePreloaderManager) + +************************************************************************ */ + +/*! + This singleton manage the global image path (prefix) and allowes themed icons. +*/ +qx.OO.defineClass("qx.manager.object.ImageManager", qx.manager.object.ObjectManager, +function() +{ + qx.manager.object.ObjectManager.call(this); + + // Themes + this._iconThemes = {}; + this._widgetThemes = {}; + + // Contains known image sources (all of them, if loaded or not) + // The value is a number which represents the number of image + // instances which use this source + this._sources = {}; + + // Change event connection to AliasManager + qx.manager.object.AliasManager.getInstance().addEventListener("change", this._onaliaschange, this); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +/* + Make sure to select an icon theme that is compatible to the license you + chose to receive the qooxdoo code under. For more information, please + see the LICENSE file in the project's top-level directory. + */ +qx.Settings.setDefault("iconTheme", "qx.theme.icon.Nuvola"); + +qx.Settings.setDefault("widgetTheme", "qx.theme.widget.Windows"); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "iconTheme", type : "object", instance : "qx.renderer.theme.IconTheme" }); +qx.OO.addProperty({ name : "widgetTheme", type : "object", instance : "qx.renderer.theme.WidgetTheme" }); + + + + + + +/* +--------------------------------------------------------------------------- + REGISTRATION +--------------------------------------------------------------------------- +*/ + +qx.Proto.registerIconTheme = function(vThemeClass) +{ + this._iconThemes[vThemeClass.classname] = vThemeClass; + + if (vThemeClass.classname == this.getSetting("iconTheme")) { + this.setIconTheme(vThemeClass.getInstance()); + } +} + +qx.Proto.registerWidgetTheme = function(vThemeClass) +{ + this._widgetThemes[vThemeClass.classname] = vThemeClass; + + if (vThemeClass.classname == this.getSetting("widgetTheme")) { + this.setWidgetTheme(vThemeClass.getInstance()); + } +} + +qx.Proto.setIconThemeById = function(vId) { + this.setIconTheme(this._iconThemes[vId].getInstance()); +} + +qx.Proto.setWidgetThemeById = function(vId) { + this.setWidgetTheme(this._widgetThemes[vId].getInstance()); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onaliaschange = function() { + this._updateImages(); +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyIconTheme = function(propValue, propOldValue, propData) +{ + propValue ? qx.manager.object.AliasManager.getInstance().add("icon", propValue.getSetting("imageUri")) : qx.manager.object.AliasManager.getInstance().remove("icon"); + return true; +} + +qx.Proto._modifyWidgetTheme = function(propValue, propOldValue, propData) +{ + propValue ? qx.manager.object.AliasManager.getInstance().add("widget", propValue.getSetting("imageUri")) : qx.manager.object.AliasManager.getInstance().remove("widget"); + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + PRELOAD API +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPreloadImageList = function() +{ + var vPreload = {}; + + for (var vSource in this._sources) + { + if (this._sources[vSource]) { + vPreload[vSource] = true; + } + } + + return vPreload; +} + +qx.Proto.getPostPreloadImageList = function() +{ + var vPreload = {}; + + for (var vSource in this._sources) + { + if (!this._sources[vSource]) { + vPreload[vSource] = true; + } + } + + return vPreload; +} + + + + + + + +/* +--------------------------------------------------------------------------- + INTERNAL HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._updateImages = function() +{ + var vAll = this.getAll(); + var vPreMgr = qx.manager.object.ImagePreloaderManager.getInstance(); + var vAliasMgr = qx.manager.object.AliasManager.getInstance(); + var vObject; + + // Recreate preloader of affected images + for (var vHashCode in vAll) + { + vObject = vAll[vHashCode]; + vObject.setPreloader(vPreMgr.create(vAliasMgr.resolvePath(vObject.getSource()))); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +// TODO: rename to createIconThemeList +qx.Proto.createThemeList = function(vParent, xCor, yCor) +{ + var vButton; + var vThemes = this._iconThemes; + var vIcon = "icon/16/apps/preferences-desktop-theme.png"; + var vPrefix = "Icon Theme: "; + var vEvent = "execute"; + + for (var vId in vThemes) + { + var vObj = vThemes[vId].getInstance(); + var vButton = new qx.ui.form.Button(vPrefix + vObj.getTitle(), vIcon); + + vButton.setLocation(xCor, yCor); + vButton.addEventListener(vEvent, new Function("qx.manager.object.ImageManager.getInstance().setIconThemeById('" + vId + "')")); + + vParent.add(vButton); + + yCor += 30; + } +} + +qx.Proto.preload = function(vPath) { + qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(vPath)); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Change event connection to AliasManager + qx.manager.object.AliasManager.getInstance().removeEventListener("change", this._onaliaschange, this); + + // Delete counter field + this._sources = null; + + // Themes + this._iconThemes = null; + this._widgetThemes = null; + + return qx.manager.object.ObjectManager.prototype.dispose.call(this); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImagePreloaderManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImagePreloaderManager.js new file mode 100644 index 0000000000..400e481398 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ImagePreloaderManager.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + This singleton manage all qx.io.image.Preloader instances. +*/ +qx.OO.defineClass("qx.manager.object.ImagePreloaderManager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); +}); + + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(vObject) { + this._objects[vObject.getUri()] = vObject; +} + +qx.Proto.remove = function(vObject) { + delete this._objects[vObject.getUri()]; +} + +qx.Proto.has = function(vSource) { + return this._objects[vSource] != null; +} + +qx.Proto.get = function(vSource) { + return this._objects[vSource]; +} + +qx.Proto.create = function(vSource) +{ + if (this._objects[vSource]) { + return this._objects[vSource]; + } + + return new qx.io.image.Preloader(vSource); +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/MenuManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/MenuManager.js new file mode 100644 index 0000000000..ee34ddfe25 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/MenuManager.js @@ -0,0 +1,111 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +/*! + This singleton manages multiple instances of qx.ui.menu.Menu and their state. +*/ +qx.OO.defineClass("qx.manager.object.MenuManager", qx.manager.object.ObjectManager, +function(){ + qx.manager.object.ObjectManager.call(this); +}); + + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.update = function(vTarget, vEventName) +{ + var vMenu, vHashCode; + var vAll = this.getAll(); + + for (vHashCode in vAll) + { + vMenu = vAll[vHashCode]; + + if(!vMenu.getAutoHide()) { + continue; + } + + if (vTarget && vTarget.getMenu && vTarget.getMenu()) { + continue; + } + + // Hide on global events (mouseup, window focus, window blur, ...) + if (!vTarget) + { + vMenu.hide(); + continue; + } + + // Hide only if the target is not a button inside this + // or any sub menu and is not the opener + var isMouseDown = vEventName == "mousedown"; + var isMouseUp = vEventName == "mouseup"; + + //Close menu if the target is not the opener button... + if (vMenu.getOpener() !== vTarget + + // and + && ( vTarget && + // the event is a mouse down on a non-child of the menu + (!vMenu.isSubElement(vTarget) && isMouseDown) + + // or the event is a mouse up on a child button of the menu + || (vMenu.isSubElement(vTarget, true) && isMouseUp) + + // or the event is a key (esc) event + || (!isMouseDown && !isMouseUp ))) + + + { + vMenu.hide(); + continue; + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ObjectManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ObjectManager.js new file mode 100644 index 0000000000..b53e62b453 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ObjectManager.js @@ -0,0 +1,119 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/*! + This class allows basic managment of assigned objects. +*/ +qx.OO.defineClass("qx.manager.object.ObjectManager", qx.core.Target, +function() +{ + qx.core.Target.call(this); + + this._objects = {}; +}); + + + + + +/* +--------------------------------------------------------------------------- + USER API +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(vObject) +{ + if (this.getDisposed()) { + return; + } + + this._objects[vObject.toHashCode()] = vObject; + return true; +} + +qx.Proto.remove = function(vObject) +{ + if (this.getDisposed()) { + return; + } + + delete this._objects[vObject.toHashCode()]; + return true; +} + +qx.Proto.has = function(vObject) { + return this._objects[vObject.toHashCode()] != null; +} + +qx.Proto.get = function(vObject) { + return this._objects[vObject.toHashCode()]; +} + +qx.Proto.getAll = function() { + return this._objects; +} + +qx.Proto.enableAll = function() +{ + for (var vHashCode in this._objects) { + this._objects[vHashCode].setEnabled(true); + }; +}; + +qx.Proto.disableAll = function() +{ + for (var vHashCode in this._objects) { + this._objects[vHashCode].setEnabled(false); + }; +}; + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + if (this._objects) + { + for (var i in this._objects) { + delete this._objects[i]; + } + + delete this._objects; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/PopupManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/PopupManager.js new file mode 100644 index 0000000000..f81509300b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/PopupManager.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) +#optional(qx.ui.popup.ToolTip) + +************************************************************************ */ + +/*! + This singleton is used to manager multiple instances of popups and their state. +*/ +qx.OO.defineClass("qx.manager.object.PopupManager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); +}); + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.update = function(vTarget) +{ + // be sure that target is correctly set (needed for contains() later) + if (!(vTarget instanceof qx.ui.core.Widget)) { + vTarget = null; + } + + var vPopup, vHashCode; + var vAll = this.getAll(); + + for (vHashCode in vAll) + { + vPopup = vAll[vHashCode]; + + if(!vPopup.getAutoHide() || vTarget == vPopup || vPopup.contains(vTarget)) { + continue; + } + + if (qx.OO.isAvailable("qx.ui.popup.ToolTip") && vTarget instanceof qx.ui.popup.ToolTip && !(vPopup instanceof qx.ui.popup.ToolTip)) { + continue; + } + + vPopup.hide(); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ToolTipManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ToolTipManager.js new file mode 100644 index 0000000000..7cd07e7365 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/ToolTipManager.js @@ -0,0 +1,193 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) + +************************************************************************ */ + +/*! + This manages ToolTip instances +*/ +qx.OO.defineClass("qx.manager.object.ToolTipManager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); +}); + +qx.OO.addProperty({ name : "currentToolTip", type : "object", instance : "qx.ui.popup.ToolTip" }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCurrentToolTip = function(propValue, propOldValue, propData) +{ + // Return if the new tooltip is a child of the old one + if(propOldValue && propOldValue.contains(propValue)) { + return; + } + + // If old tooltip existing, hide it and clear widget binding + if(propOldValue) + { + propOldValue.hide(); + + propOldValue._stopShowTimer(); + propOldValue._stopHideTimer(); + } + + // If new tooltip is not null, set it up and start the timer + if(propValue) { + propValue._startShowTimer(); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT INTERFACE: MOUSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.handleMouseOver = function(e) +{ + var vTarget = e.getTarget(); + var vToolTip; + + // Allows us to use DOM Nodes as tooltip target :) + if (!(vTarget instanceof qx.ui.core.Widget) && vTarget.nodeType == 1) { + vTarget = qx.event.handler.EventHandler.getTargetObject(vTarget); + } + + //Search first parent which has a tooltip + while(vTarget != null && !(vToolTip = vTarget.getToolTip())) { + vTarget = vTarget.getParent(); + } + + // Bind tooltip to widget + if (vToolTip != null) { + vToolTip.setBoundToWidget(vTarget); + } + + // Set Property + this.setCurrentToolTip(vToolTip); +} + +qx.Proto.handleMouseOut = function(e) +{ + var vTarget = e.getTarget(); + var vRelatedTarget = e.getRelatedTarget(); + + var vToolTip = this.getCurrentToolTip(); + + // If there was a tooltip and + // - the destination target is the current tooltip + // or + // - the current tooltip contains the destination target + if(vToolTip && (vRelatedTarget == vToolTip || vToolTip.contains(vRelatedTarget))) { + return; + } + + // If the destination target exists and the target contains it + if(vRelatedTarget && vTarget && vTarget.contains(vRelatedTarget)) { + return; + } + + // If there was a tooltip and there is no new one + if(vToolTip && !vRelatedTarget) { + this.setCurrentToolTip(null); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT INTERFACE: FOCUS +--------------------------------------------------------------------------- +*/ + +qx.Proto.handleFocus = function(e) +{ + var vTarget = e.getTarget(); + var vToolTip = vTarget.getToolTip(); + + // Only set new tooltip if focus widget + // has one + if(vToolTip != null) + { + // Bind tooltip to widget + vToolTip.setBoundToWidget(vTarget); + + // Set Property + this.setCurrentToolTip(vToolTip); + } +} + +qx.Proto.handleBlur = function(e) +{ + var vTarget = e.getTarget(); + + if(!vTarget) { + return; + } + + var vToolTip = this.getCurrentToolTip(); + + // Only set to null if blured widget is the + // one which has created the current tooltip + if(vToolTip && vToolTip == vTarget.getToolTip()) { + this.setCurrentToolTip(null); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/WindowManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/WindowManager.js new file mode 100644 index 0000000000..c0af466db6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/object/WindowManager.js @@ -0,0 +1,160 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_window) + +************************************************************************ */ + +/*! + This singleton manages qx.ui.window.Windows +*/ +qx.OO.defineClass("qx.manager.object.WindowManager", qx.manager.object.ObjectManager, +function() { + qx.manager.object.ObjectManager.call(this); +}); + +qx.OO.addProperty({ name : "activeWindow", type : "object" }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyActiveWindow = function(propValue, propOldValue, propData) +{ + qx.manager.object.PopupManager.getInstance().update(); + + if (propOldValue) { + propOldValue.setActive(false); + } + + if (propValue) { + propValue.setActive(true); + } + + if (propOldValue && propOldValue.getModal()) { + propOldValue.getTopLevelWidget().release(propOldValue); + } + + if (propValue && propValue.getModal()) { + propValue.getTopLevelWidget().block(propValue); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.update = function(oTarget) +{ + var vWindow, vHashCode; + var vAll = this.getAll(); + + for (var vHashCode in vAll) + { + vWindow = vAll[vHashCode]; + + if(!vWindow.getAutoHide()) { + continue; + } + + vWindow.hide(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + MANAGER INTERFACE +--------------------------------------------------------------------------- +*/ + +qx.Proto.compareWindows = function(w1, w2) +{ + switch(w1.getWindowManager().getActiveWindow()) + { + case w1: + return 1; + + case w2: + return -1; + } + + return w1.getZIndex() - w2.getZIndex(); +} + +qx.Proto.add = function(vWindow) +{ + qx.manager.object.ObjectManager.prototype.add.call(this, vWindow); + + // this.debug("Add: " + vWindow); + this.setActiveWindow(vWindow); +} + +qx.Proto.remove = function(vWindow) +{ + qx.manager.object.ObjectManager.prototype.remove.call(this, vWindow); + + // this.debug("Remove: " + vWindow); + + if (this.getActiveWindow() == vWindow) + { + var a = []; + for (var i in this._objects) { + a.push(this._objects[i]); + } + + var l = a.length; + + if (l==0) + { + this.setActiveWindow(null); + } + else if (l==1) + { + this.setActiveWindow(a[0]); + } + else if (l>1) + { + a.sort(this.compareWindows); + this.setActiveWindow(a[l-1]); + } + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/DomSelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/DomSelectionManager.js new file mode 100644 index 0000000000..63ac9ed78e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/DomSelectionManager.js @@ -0,0 +1,244 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.manager.selection.DomSelectionManager", qx.manager.selection.SelectionManager, +function(vBoundedWidget) +{ + qx.manager.selection.SelectionManager.call(this, vBoundedWidget); + + // the children does not fire onmouseover events so we could + // not enable this and make it functional + this.setDragSelection(false); + + this._selectedItems.getItemHashCode = this.getItemHashCode; +}); + + + +/* +--------------------------------------------------------------------------- + MAPPING TO BOUNDED WIDGET (DOM NODES) +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemEnabled = function(oItem) { + return true; +} + +qx.Proto.getItemClassName = function(vItem) { + return vItem.className || ""; +} + +qx.Proto.setItemClassName = function(vItem, vClassName) { + return vItem.className = vClassName; +} + +qx.Proto.getItemBaseClassName = function(vItem) +{ + var p = vItem.className.split(" ")[0]; + return p ? p : "Status"; +} + +qx.Proto.getNextSibling = function(vItem) { + return vItem.nextSibling; +} + +qx.Proto.getPreviousSibling = function(vItem) { + return vItem.previousSibling; +} + +qx.Proto.getFirst = function() { + return this.getItems()[0]; +} + +qx.Proto.getLast = function() +{ + var vItems = this.getItems(); + return vItems[vItems.length-1]; +} + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemLeft = function(vItem) { + return vItem.offsetLeft; +} + +qx.Proto.getItemTop = function(vItem) { + return vItem.offsetTop; +} + +qx.Proto.getItemWidth = function(vItem) { + return vItem.offsetWidth; +} + +qx.Proto.getItemHeight = function(vItem) { + return vItem.offsetHeight; +} + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemHashCode = function(oItem) +{ + if (oItem._hash) { + return oItem._hash; + } + + return oItem._hash = qx.core.Object.toHashCode(oItem); +} + +qx.Proto.isBefore = function(vItem1, vItem2) +{ + var pa = vItem1.parentNode; + + for (var i=0, l=pa.childNodes.length; i<l; i++) + { + switch(pa.childNodes[i]) + { + case vItem2: + return false; + + case vItem1: + return true; + } + } +} + +qx.Proto.scrollItemIntoView = function(vItem) { + this.getBoundedWidget().scrollItemIntoView(vItem); +} + +qx.Proto.getItems = function() { + return this.getBoundedWidget().getItems(); +} + +qx.Proto.getAbove = function(vItem) +{ + var vParent = vItem.parentNode; + var vFound = false; + var vLeft = vItem.offsetLeft; + var vChild; + + for (var i=vParent.childNodes.length-1; i>0; i--) + { + vChild = vParent.childNodes[i]; + + if (vFound == false) + { + if (vChild == vItem) { + vFound = true; + } + } + else + { + if (vChild.offsetLeft == vLeft) + { + return vChild; + } + } + } +} + +qx.Proto.getUnder = function(vItem) +{ + var vParent = vItem.parentNode; + var vFound = false; + var vLeft = vItem.offsetLeft; + var vChild; + + for (var i=0, l=vParent.childNodes.length; i<l; i++) + { + vChild = vParent.childNodes[i]; + + if (vFound == false) + { + if (vChild == vItem) { + vFound = true; + } + } + else + { + if (vChild.offsetLeft == vLeft) + { + return vChild; + } + } + } +} + + + + + + + + + + + + + + +/* +--------------------------------------------------------------------------- + ITEM CSS STATE MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._updateState = function(vItem, vState, vIsState) +{ + var c = this.getItemClassName(vItem); + var n = this.getItemBaseClassName(vItem) + "-" + vState; + + this.setItemClassName(vItem, vIsState ? qx.lang.String.addListItem(c, n, " ") : qx.lang.String.removeListItem(c, n, " ")); +} + +qx.Proto.renderItemSelectionState = function(vItem, vIsSelected) { + this._updateState(vItem, "Selected", vIsSelected); +} + +qx.Proto.renderItemAnchorState = function(vItem, vIsAnchor) { + this._updateState(vItem, "Anchor", vIsAnchor); +} + +qx.Proto.renderItemLeadState = function(vItem, vIsLead) { + this._updateState(vItem, "Lead", vIsLead); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/RadioManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/RadioManager.js new file mode 100644 index 0000000000..a8eda53890 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/RadioManager.js @@ -0,0 +1,303 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/*! + Each instance manage vItems set of radio options: qx.ui.form.RadioButton, qx.ui.toolbar.RadioButton, ... +*/ +qx.OO.defineClass("qx.manager.selection.RadioManager", qx.core.Target, +function(vName, vMembers) +{ + // we don't need the manager data structures + qx.core.Target.call(this); + + // create item array + this._items = []; + + // apply name property + this.setName(vName != null ? vName : qx.manager.selection.RadioManager.AUTO_NAME_PREFIX + this._hashCode); + + if (vMembers != null) + { + // add() iterates over arguments, but vMembers is an array + this.add.apply(this, vMembers); + } +}); + +qx.manager.selection.RadioManager.AUTO_NAME_PREFIX = "qx-radio-"; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "selected" }); +qx.OO.addProperty({ name : "name", type : "string" }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItems = function() { + return this._items; +} + +qx.Proto.getEnabledItems = function() +{ + var b = []; + + for (var i=0, a=this._items, l=a.length; i<l; i++) + { + if (a[i].getEnabled()) { + b.push(a[i]); + } + } + + return b; +} + +qx.Proto.handleItemChecked = function(vItem, vChecked) +{ + if (vChecked) + { + this.setSelected(vItem); + } + else if (this.getSelected() == vItem) + { + this.setSelected(null); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + REGISTRY +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(varargs) +{ + var vItems = arguments; + var vLength = vItems.length; + var vItem; + + for (var i=0; i<vLength; i++) + { + vItem = vItems[i]; + + if(qx.lang.Array.contains(this._items, vItem)) { + return; + } + + // Push RadioButton to array + this._items.push(vItem); + + // Inform radio button about new manager + vItem.setManager(this); + + // Need to update internal value? + if(vItem.getChecked()) { + this.setSelected(vItem); + } + + // Make enabled the same status as the the manager has + vItem.setEnabled(this.getEnabled()); + + // Apply Make name the same + vItem.setName(this.getName()); + } +} + +qx.Proto.remove = function(vItem) +{ + // Remove RadioButton from array + qx.lang.Array.remove(this._items, vItem); + + // Inform radio button about new manager + vItem.setManager(null); + + // if the radio was checked, set internal selection to null + if(vItem.getChecked()) { + this.setSelected(null); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySelected = function(propValue, propOldValue, propData) +{ + if (propOldValue && propOldValue.getChecked()) { + propOldValue.setChecked(false); + } + + if (propValue && !propValue.getChecked()) { + propValue.setChecked(true); + } + + return true; +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + for (var i=0, vItems=this._items, vLength=vItems.length; i<vLength; i++) { + vItems[i].setEnabled(propValue); + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propData) +{ + for (var i=0, vItems=this._items, vLength=vItems.length; i<vLength; i++) { + vItems[i].setName(propValue); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + SELECTION +--------------------------------------------------------------------------- +*/ + +qx.Proto.selectNext = function(vItem) +{ + var vIndex = this._items.indexOf(vItem); + + if(vIndex == -1) { + return; + } + + var i = 0; + var vLength = this._items.length; + + // Find next enabled item + vIndex = (vIndex + 1) % vLength; + while(i < vLength && !this._items[vIndex].getEnabled()) + { + vIndex = (vIndex + 1) % vLength; + i++; + } + + this._selectByIndex(vIndex); +} + +qx.Proto.selectPrevious = function(vItem) +{ + var vIndex = this._items.indexOf(vItem); + + if(vIndex == -1) { + return; + } + + var i = 0; + var vLength = this._items.length; + + // Find previous enabled item + vIndex = (vIndex - 1 + vLength) % vLength; + while(i < vLength && !this._items[vIndex].getEnabled()) + { + vIndex = (vIndex - 1 + vLength) % vLength; + i++; + } + + this._selectByIndex(vIndex); +} + +qx.Proto._selectByIndex = function(vIndex) +{ + if(this._items[vIndex].getEnabled()) + { + this.setSelected(this._items[vIndex]); + this._items[vIndex].setFocused(true); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.forceSelected(null); + + if (this._items) + { + for (var i, vItems=this._items, vLength=vItems.length; i<vLength; i++) + { + vItems[i].dispose(); + delete vItems[i]; + } + + vItems=null; + delete this._items; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/SelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/SelectionManager.js new file mode 100644 index 0000000000..132bbdca26 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/SelectionManager.js @@ -0,0 +1,1435 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/** + * This class represents a selection and manage incoming events for widgets + * which need selection support. + * + * @event changeSelection {qx.event.type.DataEvent} sets the data property of the event object to an arryas of selected items. + */ +qx.OO.defineClass("qx.manager.selection.SelectionManager", qx.core.Target, +function(vBoundedWidget) +{ + qx.core.Target.call(this); + + this._selectedItems = new qx.type.Selection(this); + + if (vBoundedWidget != null) { + this.setBoundedWidget(vBoundedWidget); + } +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! +This contains the currently assigned widget (qx.ui.form.List, ...) +*/ +qx.OO.addProperty({ name : "boundedWidget", type : "object" }); + +/*! +Should multiple selection be allowed? +*/ +qx.OO.addProperty({ name : "multiSelection", type : "boolean", defaultValue : true }); + +/*! +Enable drag selection? +*/ +qx.OO.addProperty({ name : "dragSelection", type : "boolean", defaultValue : true }); + +/*! +Should the user be able to select +*/ +qx.OO.addProperty({ name : "canDeselect", type : "boolean", defaultValue : true }); + +/*! +Should a change event be fired? +*/ +qx.OO.addProperty({ name : "fireChange", type : "boolean", defaultValue : true }); + +/*! +The current anchor in range selections. +*/ +qx.OO.addProperty({ name : "anchorItem", type : "object" }); + +/*! +The last selected item +*/ +qx.OO.addProperty({ name : "leadItem", type : "object" }); + +/*! +Grid selection +*/ +qx.OO.addProperty({ name : "multiColumnSupport", type : "boolean", defaultValue : false }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyAnchorItem = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + this.renderItemAnchorState(propOldValue, false); + } + + if (propValue) { + this.renderItemAnchorState(propValue, true); + } + + return true; +} + +qx.Proto._modifyLeadItem = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + this.renderItemLeadState(propOldValue, false); + } + + if (propValue) { + this.renderItemLeadState(propValue, true); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO BOUNDED WIDGET +--------------------------------------------------------------------------- +*/ + +qx.Proto._getFirst = function() { + return this.getBoundedWidget().getFirstVisibleChild(); +} + +qx.Proto._getLast = function() { + return this.getBoundedWidget().getLastVisibleChild(); +} + +qx.Proto.getFirst = function() +{ + var vItem = this._getFirst(); + if (vItem) { + return vItem.isEnabled() ? vItem : this.getNext(vItem); + } +} + +qx.Proto.getLast = function() +{ + var vItem = this._getLast(); + if (vItem) { + return vItem.isEnabled() ? vItem : this.getPrevious(vItem); + } +} + +qx.Proto.getItems = function() { + return this.getBoundedWidget().getChildren(); +} + +qx.Proto.getNextSibling = function(vItem) { + return vItem.getNextSibling(); +} + +qx.Proto.getPreviousSibling = function(vItem) { + return vItem.getPreviousSibling(); +} + +qx.Proto.getNext = function(vItem) +{ + while(vItem) + { + vItem = this.getNextSibling(vItem); + + if (!vItem) { + break; + } + + if (this.getItemEnabled(vItem)) { + return vItem; + } + } + + return null; +} + +qx.Proto.getPrevious = function(vItem) +{ + while(vItem) + { + vItem = this.getPreviousSibling(vItem); + + if (!vItem) { + break; + } + + if (this.getItemEnabled(vItem)) { + return vItem; + } + } + + return null; +} + +qx.Proto.isBefore = function(vItem1, vItem2) +{ + var cs = this.getItems(); + return cs.indexOf(vItem1) < cs.indexOf(vItem2); +} + +qx.Proto.isEqual = function(vItem1, vItem2) { + return vItem1 == vItem2; +} + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemHashCode = function(vItem) { + return vItem.toHashCode(); +} + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.scrollItemIntoView = function(vItem, vTopLeft) { + vItem.scrollIntoView(vTopLeft); +} + +qx.Proto.getItemLeft = function(vItem) { + return vItem.getOffsetLeft(); +} + +qx.Proto.getItemTop = function(vItem) { + return vItem.getOffsetTop(); +} + +qx.Proto.getItemWidth = function(vItem) { + return vItem.getOffsetWidth(); +} + +qx.Proto.getItemHeight = function(vItem) { + return vItem.getOffsetHeight(); +} + +qx.Proto.getItemEnabled = function(vItem) { + return vItem.getEnabled(); +} + + + + + + +/* +--------------------------------------------------------------------------- + ITEM STATE MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto.renderItemSelectionState = function(vItem, vIsSelected) +{ + vIsSelected ? vItem.addState("selected") : vItem.removeState("selected"); + + if (vItem.handleStateChange) { + vItem.handleStateChange(); + } +} + +qx.Proto.renderItemAnchorState = function(vItem, vIsAnchor) +{ + vIsAnchor ? vItem.addState("anchor") : vItem.removeState("anchor"); + + if (vItem.handleStateChange != null) { + vItem.handleStateChange(); + } +} + +qx.Proto.renderItemLeadState = function(vItem, vIsLead) +{ + vIsLead ? vItem.addState("lead") : vItem.removeState("lead"); + + if (vItem.handleStateChange != null) { + vItem.handleStateChange(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + SELECTION HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemSelected = function(vItem) { + return this._selectedItems.contains(vItem); +} + +/*! +Make a single item selected / not selected + +#param vItem[qx.ui.core.Widget]: Item which should be selected / not selected +#param vSelected[Boolean]: Should this item be selected? +*/ +qx.Proto.setItemSelected = function(vItem, vSelected) +{ + var hc = this.getItemHashCode(vItem); + + switch(this.getMultiSelection()) + { + // Multiple item selection is allowed + case true: + if (!this.getItemEnabled(vItem)) { + return; + } + + // If selection state is not to be changed => return + if (this.getItemSelected(vItem) == vSelected) { + return; + } + + // Otherwise render new state + this.renderItemSelectionState(vItem, vSelected); + + // Add item to selection hash / delete it from there + vSelected ? this._selectedItems.add(vItem) : this._selectedItems.remove(vItem); + + // Dispatch change Event + this._dispatchChange(); + + break; + + + + // Multiple item selection is NOT allowed + case false: + var item0 = this.getSelectedItems()[0]; + + + + if (vSelected) + { + // Precheck for any changes + var old = item0; + + if (this.isEqual(vItem, old)) { + return; + } + + // Reset rendering of previous selected item + if (old != null) { + this.renderItemSelectionState(old, false); + } + + // Render new item as selected + this.renderItemSelectionState(vItem, true); + + // Reset current selection hash + this._selectedItems.removeAll(); + + // Add new one + this._selectedItems.add(vItem); + + // Dispatch change Event + this._dispatchChange(); + } + else + { + // Pre-check if item is currently selected + // Do not allow deselection in single selection mode + if (!this.isEqual(item0, vItem)) + { + // Reset rendering as selected item + this.renderItemSelectionState(vItem, false); + + // Reset current selection hash + this._selectedItems.removeAll(); + + // Dispatch change Event + this._dispatchChange(); + } + } + + break; + + } +} + + + + + + + + +/*! + Get the selected items (objects) +*/ +qx.Proto.getSelectedItems = function() { + return this._selectedItems.toArray(); +} + +qx.Proto.getSelectedItem = function() { + return this._selectedItems.getFirst(); +} + +/*! +Select given items + +#param vItems[Array of Widgets]: Items to select +*/ +qx.Proto.setSelectedItems = function(vItems) +{ + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Deselect all currently selected items + this._deselectAll(); + + // Apply new selection + var vItem; + var vItemLength = vItems.length; + + for (var i=0; i<vItemLength; i++) + { + vItem = vItems[i]; + + if (!this.getItemEnabled(vItem)) { + continue; + } + + // Add item to selection + this._selectedItems.add(vItem); + + // Render new state for item + this.renderItemSelectionState(vItem, true); + } + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + + +qx.Proto.setSelectedItem = function(vItem) +{ + if (!vItem) { + return; + } + + if (!this.getItemEnabled(vItem)) { + return; + } + + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Deselect all currently selected items + this._deselectAll(); + + // Add item to selection + this._selectedItems.add(vItem); + + // Render new state for item + this.renderItemSelectionState(vItem, true); + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + + + + + +/*! + Select all items. +*/ +qx.Proto.selectAll = function() +{ + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Call sub method to select all items + this._selectAll(); + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + +/*! + Sub method for selectAll. Handles the real work + to select all items. +*/ +qx.Proto._selectAll = function() +{ + if (!this.getMultiSelection()) { + return; + } + + var vItem; + var vItems = this.getItems(); + var vItemsLength = vItems.length; + + // Reset current selection hash + this._selectedItems.removeAll(); + + for (var i=0; i<vItemsLength; i++) + { + vItem = vItems[i]; + + if (!this.getItemEnabled(vItem)) { + continue; + } + + // Add item to selection + this._selectedItems.add(vItem); + + // Render new state for item + this.renderItemSelectionState(vItem, true); + } + + return true; +} + + + + + +/*! + Deselect all items. +*/ +qx.Proto.deselectAll = function() +{ + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Call sub method to deselect all items + this._deselectAll(); + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) + this._dispatchChange(); + } + +/*! + Sub method for deselectAll. Handles the real work + to deselect all items. +*/ +qx.Proto._deselectAll = function() +{ + // Render new state for items + var items = this._selectedItems.toArray(); + for (var i = 0; i < items.length; i++) { + this.renderItemSelectionState(items[i], false); + } + + // Delete all entries in selectedItems hash + this._selectedItems.removeAll(); + + return true; +} + + + + +/*! +Select a range of items. + +#param vItem1[qx.ui.core.Widget]: Start item +#param vItem2[qx.ui.core.Widget]: Stop item +*/ +qx.Proto.selectItemRange = function(vItem1, vItem2) +{ + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Call sub method to select the range of items + this._selectItemRange(vItem1, vItem2, true); + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + + + + +/*! +Sub method for selectItemRange. Handles the real work +to select a range of items. + +#param vItem1[qx.ui.core.Widget]: Start item +#param vItem2[qx.ui.core.Widget]: Stop item +#param vDelect[Boolean]: Deselect currently selected items first? +*/ +qx.Proto._selectItemRange = function(vItem1, vItem2, vDeselect) +{ + // this.debug("SELECT_RANGE: " + vItem1.toText() + "<->" + vItem2.toText()); + // this.debug("SELECT_RANGE: " + vItem1.pos + "<->" + vItem2.pos); + + // Pre-Check a revert call if vItem2 is before vItem1 + if (this.isBefore(vItem2, vItem1)) { + return this._selectItemRange(vItem2, vItem1, vDeselect); + } + + // Deselect all + if (vDeselect) { + this._deselectAll(); + } + + var vCurrentItem = vItem1; + + while (vCurrentItem != null) + { + if (this.getItemEnabled(vCurrentItem)) + { + // Add item to selection + this._selectedItems.add(vCurrentItem); + + // Render new state for item + this.renderItemSelectionState(vCurrentItem, true); + } + + // Stop here if we reached target item + if (this.isEqual(vCurrentItem, vItem2)) { + break; + } + + // Get next item + vCurrentItem = this.getNext(vCurrentItem); + } + + return true; +} + +/*! +Internal method for deselection of ranges. + +#param vItem1[qx.ui.core.Widget]: Start item +#param vItem2[qx.ui.core.Widget]: Stop item +*/ +qx.Proto._deselectItemRange = function(vItem1, vItem2) +{ + // Pre-Check a revert call if vItem2 is before vItem1 + if (this.isBefore(vItem2, vItem1)) { + return this._deselectItemRange(vItem2, vItem1); + } + + var vCurrentItem = vItem1; + + while (vCurrentItem != null) + { + // Add item to selection + this._selectedItems.remove(vCurrentItem); + + // Render new state for item + this.renderItemSelectionState(vCurrentItem, false); + + // Stop here if we reached target item + if (this.isEqual(vCurrentItem, vItem2)) { + break; + } + + // Get next item + vCurrentItem = this.getNext(vCurrentItem); + } +} + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._activeDragSession = false; + +qx.Proto.handleMouseDown = function(vItem, e) +{ + // Only allow left and right button + if (!e.isLeftButtonPressed() && !e.isRightButtonPressed()) { + return; + } + + // Keep selection on right click on already selected item + if (e.isRightButtonPressed() && this.getItemSelected(vItem)) { + return; + } + + // Shift Key + // or + // Click on an unseleted item (without Strg) + if (e.isShiftPressed() || this.getDragSelection() || (!this.getItemSelected(vItem) && !e.isCtrlPressed())) + { + // Handle event + this._onmouseevent(vItem, e); + } + else + { + // Update lead item + this.setLeadItem(vItem); + } + + + // Handle dragging + this._activeDragSession = this.getDragSelection(); + + if (this._activeDragSession) + { + // Add mouseup listener and register as capture widget + this.getBoundedWidget().addEventListener("mouseup", this._ondragup, this); + this.getBoundedWidget().setCapture(true); + } +} + +qx.Proto._ondragup = function(e) +{ + this.getBoundedWidget().removeEventListener("mouseup", this._ondragup, this); + this.getBoundedWidget().setCapture(false); + this._activeDragSession = false; +} + +qx.Proto.handleMouseUp = function(vItem, e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + if (e.isCtrlPressed() || this.getItemSelected(vItem) && !this._activeDragSession) { + this._onmouseevent(vItem, e); + } + + if (this._activeDragSession) + { + this._activeDragSession = false; + this.getBoundedWidget().setCapture(false); + } +} + +qx.Proto.handleMouseOver = function(oItem, e) +{ + if (! this.getDragSelection() || !this._activeDragSession) { + return; + } + + this._onmouseevent(oItem, e, true); +} + +// currently unused placeholder +qx.Proto.handleClick = function(vItem, e) {} + +// currently unused placeholder +qx.Proto.handleDblClick = function(vItem, e) {} + + +/*! +Internal handler for all mouse events bound to this manager. +*/ +qx.Proto._onmouseevent = function(oItem, e, bOver) +{ + if (!this.getItemEnabled(oItem)) { + return; + } + + // ******************************************************************** + // Init + // ******************************************************************** + + // Cache current (old) values + var oldVal = this._getChangeValue(); + var oldLead = this.getLeadItem(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Cache selection and count + var selectedItems = this.getSelectedItems(); + var selectedCount = selectedItems.length; + + // Update lead item + this.setLeadItem(oItem); + + // Cache current anchor item + var currentAnchorItem = this.getAnchorItem(); + + // Cache keys pressed + var vCtrlKey = e.isCtrlPressed(); + var vShiftKey = e.isShiftPressed(); + + + // ******************************************************************** + // Do we need to update the anchor? + // ******************************************************************** + + if (!currentAnchorItem || selectedCount == 0 || (vCtrlKey && !vShiftKey && this.getMultiSelection() && !this.getDragSelection())) + { + this.setAnchorItem(oItem); + currentAnchorItem = oItem; + } + + + + // ******************************************************************** + // Mode #1: Replace current selection with new one + // ******************************************************************** + if ((!vCtrlKey && !vShiftKey && !this._activeDragSession || !this.getMultiSelection())) + { + if (!this.getItemEnabled(oItem)) { + return; + } + + // Remove current selection + this._deselectAll(); + + // Update anchor item + this.setAnchorItem(oItem); + + if (this._activeDragSession) + { + // a little bit hacky, but seems to be a fast way to detect if we slide to top or to bottom + this.scrollItemIntoView((this.getBoundedWidget().getScrollTop() > (this.getItemTop(oItem)-1) ? this.getPrevious(oItem) : this.getNext(oItem)) || oItem); + } + + if (!this.getItemSelected(oItem)) { + this.renderItemSelectionState(oItem, true); + } + + // Clear up and add new one + //this._selectedItems.removeAll(); + this._selectedItems.add(oItem); + + this._addToCurrentSelection = true; + } + + + // ******************************************************************** + // Mode #2: (De-)Select item range in mouse drag session + // ******************************************************************** + else if (this._activeDragSession && bOver) + { + if (oldLead) { + this._deselectItemRange(currentAnchorItem, oldLead); + } + + // Drag down + if (this.isBefore(currentAnchorItem, oItem)) + { + if (this._addToCurrentSelection) + { + this._selectItemRange(currentAnchorItem, oItem, false); + } + else + { + this._deselectItemRange(currentAnchorItem, oItem); + } + } + + // Drag up + else + { + if (this._addToCurrentSelection) + { + this._selectItemRange(oItem, currentAnchorItem, false); + } + else + { + this._deselectItemRange(oItem, currentAnchorItem); + } + } + + // a little bit hacky, but seems to be a fast way to detect if we slide to top or to bottom + this.scrollItemIntoView((this.getBoundedWidget().getScrollTop() > (this.getItemTop(oItem)-1) ? this.getPrevious(oItem) : this.getNext(oItem)) || oItem); + } + + + // ******************************************************************** + // Mode #3: Add new item to current selection (ctrl pressed) + // ******************************************************************** + else if (this.getMultiSelection() && vCtrlKey && !vShiftKey) + { + if (!this._activeDragSession) { + this._addToCurrentSelection = !(this.getCanDeselect() && this.getItemSelected(oItem)); + } + + this.setItemSelected(oItem, this._addToCurrentSelection); + this.setAnchorItem(oItem); + } + + + // ******************************************************************** + // Mode #4: Add new (or continued) range to selection + // ******************************************************************** + else if (this.getMultiSelection() && vCtrlKey && vShiftKey) + { + if (!this._activeDragSession) { + this._addToCurrentSelection = !(this.getCanDeselect() && this.getItemSelected(oItem)); + } + + if (this._addToCurrentSelection) + { + this._selectItemRange(currentAnchorItem, oItem, false); + } + else + { + this._deselectItemRange(currentAnchorItem, oItem); + } + } + + // ******************************************************************** + // Mode #5: Replace selection with new range selection + // ******************************************************************** + else if (this.getMultiSelection() && !vCtrlKey && vShiftKey) + { + if (this.getCanDeselect()) + { + this._selectItemRange(currentAnchorItem, oItem, true); + } + + else + { + if (oldLead) { + this._deselectItemRange(currentAnchorItem, oldLead); + } + + this._selectItemRange(currentAnchorItem, oItem, false); + } + } + + + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if(oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto.handleKeyDown = function(vDomEvent) { + this.warn( + "qx.manager.selection.SelectionManager.handleKeyDown is deprecated! " + + "Use keypress insted and bind it to the onkeypress event." + ); + this.handleKeyPress(vDomEvent); +} + + +/** + * Handles key event to perform selection and navigation + * + * @param vDomEvent {qx.event.type.KeyEvent} event object + */ +qx.Proto.handleKeyPress = function(vDomEvent) +{ + var oldVal = this._getChangeValue(); + + // Temporary disabling of event fire + var oldFireChange = this.getFireChange(); + this.setFireChange(false); + + // Ctrl+A: Select all + if (vDomEvent.getKeyIdentifier() == "A" && vDomEvent.isCtrlPressed()) + { + if (this.getMultiSelection()) + { + this._selectAll(); + + // Update lead item to this new last + // (or better here: first) selected item + this.setLeadItem(this.getFirst()); + } + } + + // Default operation + else + { + var aIndex = this.getAnchorItem(); + var itemToSelect = this.getItemToSelect(vDomEvent); + + // this.debug("Anchor: " + (aIndex ? aIndex.getLabel() : "null")); + // this.debug("ToSelect: " + (itemToSelect ? itemToSelect.getLabel() : "null")); + + if (itemToSelect && this.getItemEnabled(itemToSelect)) + { + // Update lead item to this new last selected item + this.setLeadItem(itemToSelect); + + // Scroll new item into view + this.scrollItemIntoView(itemToSelect); + + // Stop event handling + vDomEvent.preventDefault(); + + // Select a range + if (vDomEvent.isShiftPressed() && this.getMultiSelection()) + { + // Make it a little bit more failsafe: + // Set anchor if not given already. Allows us to select + // a range without any previous selection. + if (aIndex == null) { + this.setAnchorItem(itemToSelect); + } + + // Select new range (and clear up current selection first) + this._selectItemRange(this.getAnchorItem(), itemToSelect, true); + } + else if (!vDomEvent.isCtrlPressed()) + { + // Clear current selection + this._deselectAll(); + + // Update new item to be selected + this.renderItemSelectionState(itemToSelect, true); + + // Add item to new selection + this._selectedItems.add(itemToSelect); + + // Update anchor to this new item + // (allows following shift range selection) + this.setAnchorItem(itemToSelect); + } + else if (vDomEvent.getKeyIdentifier() == "Space") + { + if (this._selectedItems.contains(itemToSelect)) + { + // Update new item to be selected + this.renderItemSelectionState(itemToSelect, false); + + // Add item to new selection + this._selectedItems.remove(itemToSelect); + + // Fix anchor item + this.setAnchorItem(this._selectedItems.getFirst()); + } + else + { + // Clear current selection + if (!vDomEvent.isCtrlPressed() || !this.getMultiSelection()) { + this._deselectAll(); + } + + // Update new item to be selected + this.renderItemSelectionState(itemToSelect, true); + + // Add item to new selection + this._selectedItems.add(itemToSelect); + + // Update anchor to this new item + // (allows following shift range selection) + this.setAnchorItem(itemToSelect); + } + } + } + } + + // Recover change event status + this.setFireChange(oldFireChange); + + // Dispatch change Event + if (oldFireChange && this._hasChanged(oldVal)) { + this._dispatchChange(); + } +} + +qx.Proto.getItemToSelect = function(vKeyboardEvent) +{ + // Don't handle ALT here + if (vKeyboardEvent.isAltPressed()) { + return null; + } + + // Handle event by keycode + switch (vKeyboardEvent.getKeyIdentifier()) + { + case "Home": + return this.getHome(this.getLeadItem()); + + case "End": + return this.getEnd(this.getLeadItem()); + + + case "Down": + return this.getDown(this.getLeadItem()); + + case "Up": + return this.getUp(this.getLeadItem()); + + + case "Left": + return this.getLeft(this.getLeadItem()); + + case "Right": + return this.getRight(this.getLeadItem()); + + + case "PageUp": + return this.getPageUp(this.getLeadItem()) || this.getHome(this.getLeadItem()); + + case "PageDown": + return this.getPageDown(this.getLeadItem()) || this.getEnd(this.getLeadItem()); + + + case "Space": + if (vKeyboardEvent.isCtrlPressed()) { + return this.getLeadItem(); + } + } + + return null; +} + + + + +/* +--------------------------------------------------------------------------- + CHANGE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._dispatchChange = function() +{ + if (!this.getFireChange()) { + return; + } + + if (this.hasEventListeners("changeSelection")) { + this.dispatchEvent(new qx.event.type.DataEvent("changeSelection", this.getSelectedItems()), true); + } +} + +qx.Proto._hasChanged = function(sOldValue) { + return sOldValue != this._getChangeValue(); +} + +qx.Proto._getChangeValue = function() { + return this._selectedItems.getChangeValue(); +} + + + + + + +/* +--------------------------------------------------------------------------- + POSITION HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getHome = function() { + return this.getFirst(); +} + +qx.Proto.getEnd = function() { + return this.getLast(); +} + +qx.Proto.getDown = function(vItem) +{ + if (!vItem) { + return this.getFirst(); + } + + return this.getMultiColumnSupport() ? (this.getUnder(vItem) || this.getLast()) : this.getNext(vItem); +} + +qx.Proto.getUp = function(vItem) +{ + if (!vItem) { + return this.getLast(); + } + + return this.getMultiColumnSupport() ? (this.getAbove(vItem) || this.getFirst()) : this.getPrevious(vItem); +} + +qx.Proto.getLeft = function(vItem) +{ + if (!this.getMultiColumnSupport()) { + return null; + } + + return !vItem ? this.getLast() : this.getPrevious(vItem); +} + +qx.Proto.getRight = function(vItem) +{ + if (!this.getMultiColumnSupport()) { + return null; + } + + return !vItem ? this.getFirst() : this.getNext(vItem); +} + +qx.Proto.getAbove = function(vItem) +{ + throw new Error("getAbove(): Not implemented yet"); +} + +qx.Proto.getUnder = function(vItem) +{ + throw new Error("getUnder(): Not implemented yet"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + PAGE HANDLING +--------------------------------------------------------------------------- +*/ + +/*! +Jump a "page" up. + +#param vItem[qx.ui.core.Widget]: Relative to this widget +*/ +qx.Proto.getPageUp = function(vItem) +{ + var vBoundedWidget = this.getBoundedWidget(); + var vParentScrollTop = vBoundedWidget.getScrollTop(); + var vParentClientHeight = vBoundedWidget.getClientHeight(); + + // Find next item + var newItem; + var nextItem = this.getLeadItem(); + if (!nextItem) { + nextItem = this.getFirst(); + } + + // Normally we should reach the status "lead" for the + // nextItem after two iterations. + var tryLoops = 0; + while (tryLoops < 2) + { + while (nextItem && (this.getItemTop(nextItem) - this.getItemHeight(nextItem) >= vParentScrollTop)) { + nextItem = this.getUp(nextItem); + } + + // This should never occour after the fix above + if (nextItem == null) { + break; + } + + // If the nextItem is not anymore the leadItem + // Means: There has occured a change. + // We break here. This is normally the second step. + if (nextItem != this.getLeadItem()) + { + // be sure that the top is reached + this.scrollItemIntoView(nextItem, true); + break; + } + + // Update scrolling (this is normally the first step) + // this.debug("Scroll-Up: " + (vParentScrollTop + vParentClientHeight - 2 * this.getItemHeight(nextItem))); + vBoundedWidget.setScrollTop(vParentScrollTop - vParentClientHeight - this.getItemHeight(nextItem)); + + // Use the real applied value instead of the calulated above + vParentScrollTop = vBoundedWidget.getScrollTop(); + + // Increment counter + tryLoops++; + } + + return nextItem; +} + +/*! +Jump a "page" down. + +#param vItem[qx.ui.core.Widget]: Relative to this widget +*/ +qx.Proto.getPageDown = function(vItem) +{ + var vBoundedWidget = this.getBoundedWidget(); + var vParentScrollTop = vBoundedWidget.getScrollTop(); + var vParentClientHeight = vBoundedWidget.getClientHeight(); + + // this.debug("Bound: " + (vBoundedWidget._getTargetNode() != vBoundedWidget.getElement())); + + // this.debug("ClientHeight-1: " + vBoundedWidget._getTargetNode().clientHeight); + // this.debug("ClientHeight-2: " + vBoundedWidget.getElement().clientHeight); + + // Find next item + var newItem; + var nextItem = this.getLeadItem(); + if (!nextItem) { + nextItem = this.getFirst(); + } + + // Normally we should reach the status "lead" for the + // nextItem after two iterations. + var tryLoops = 0; + while (tryLoops < 2) + { + // this.debug("Loop: " + tryLoops); + // this.debug("Info: " + nextItem + " :: " + (this.getItemTop(nextItem) + (2 * this.getItemHeight(nextItem))) + " <> " + (vParentScrollTop + vParentClientHeight)); + // this.debug("Detail: " + vParentScrollTop + ", " + vParentClientHeight); + + // Find next + while (nextItem && ((this.getItemTop(nextItem) + (2 * this.getItemHeight(nextItem))) <= (vParentScrollTop + vParentClientHeight))) { + nextItem = this.getDown(nextItem); + } + + // This should never occour after the fix above + if (nextItem == null) { + break; + } + + // If the nextItem is not anymore the leadItem + // Means: There has occured a change. + // We break here. This is normally the second step. + if (nextItem != this.getLeadItem()) { + break; + } + + // Update scrolling (this is normally the first step) + // this.debug("Scroll-Down: " + (vParentScrollTop + vParentClientHeight - 2 * this.getItemHeight(nextItem))); + vBoundedWidget.setScrollTop(vParentScrollTop + vParentClientHeight - 2 * this.getItemHeight(nextItem)); + + // Use the real applied value instead of the calulated above + vParentScrollTop = vBoundedWidget.getScrollTop(); + + // Increment counter + tryLoops++; + } + + //this.debug("Select: " + nextItem._labelObject.getHtml()); + + return nextItem; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._selectedItems) + { + this._selectedItems.dispose(); + this._selectedItems = null; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeFullControlSelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeFullControlSelectionManager.js new file mode 100644 index 0000000000..268160d20a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeFullControlSelectionManager.js @@ -0,0 +1,208 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +qx.OO.defineClass("qx.manager.selection.TreeFullControlSelectionManager", qx.manager.selection.SelectionManager, +function(vBoundedWidget) { + qx.manager.selection.SelectionManager.call(this, vBoundedWidget); +}); + +/*! +Should multiple selection be allowed? +*/ +qx.OO.changeProperty({ name : "multiSelection", type : "boolean", defaultValue : false }); + +/*! +Enable drag selection? +*/ +qx.OO.changeProperty({ name : "dragSelection", type : "boolean", defaultValue : false }); + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO BOUNDED WIDGET +--------------------------------------------------------------------------- +*/ + +qx.Proto._getFirst = function() { + return qx.lang.Array.getFirst(this.getItems()); +} + +qx.Proto._getLast = function() { + return qx.lang.Array.getLast(this.getItems()); +} + +qx.Proto.getItems = function() { + return this.getBoundedWidget().getItems(); +} + +qx.Proto.getNext = function(vItem) +{ + if (vItem) + { + if (qx.ui.treefullcontrol.Tree.isOpenTreeFolder(vItem)) + { + return vItem.getFirstVisibleChildOfFolder(); + } + else if (vItem.isLastVisibleChild()) + { + var vCurrent = vItem; + + while(vCurrent && vCurrent.isLastVisibleChild()) { + vCurrent = vCurrent.getParentFolder(); + } + + if (vCurrent && + vCurrent instanceof qx.ui.treefullcontrol.AbstractTreeElement && + vCurrent.getNextVisibleSibling() && + vCurrent.getNextVisibleSibling() instanceof qx.ui.treefullcontrol.AbstractTreeElement) { + return vCurrent.getNextVisibleSibling(); + } + } + else + { + return vItem.getNextVisibleSibling(); + } + } + else + { + return this.getBoundedWidget().getFirstTreeChild(); + } +} + +qx.Proto.getPrevious = function(vItem) +{ + if (vItem) + { + if (vItem == this.getBoundedWidget()) + { + return; + } + else if (vItem.isFirstVisibleChild()) + { + if (vItem.getParentFolder() instanceof qx.ui.treefullcontrol.TreeFolder) { + return vItem.getParentFolder(); + } + } + else + { + var vPrev = vItem.getPreviousVisibleSibling(); + + if (vPrev instanceof qx.ui.treefullcontrol.AbstractTreeElement) + { + while (vPrev instanceof qx.ui.treefullcontrol.AbstractTreeElement) + { + if (qx.ui.treefullcontrol.Tree.isOpenTreeFolder(vPrev)) + { + vPrev = vPrev.getLastVisibleChildOfFolder(); + } + else + { + break; + } + } + } + + return vPrev; + } + } + else + { + return this.getBoundedWidget().getLastTreeChild(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemTop = function(vItem) +{ + // Alternate method: + // return qx.html.Location.getPageBoxTop(vItem.getElement()) - qx.html.Location.getPageInnerTop(this.getBoundedWidget().getElement()); + + var vBoundedWidget = this.getBoundedWidget(); + var vElement = vItem.getElement(); + var vOffset = 0; + + while (vElement && vElement.qx_Widget != vBoundedWidget) + { + vOffset += vElement.offsetTop; + vElement = vElement.parentNode; + } + + return vOffset; +} + +qx.Proto.getItemHeight = function(vItem) +{ + if (vItem instanceof qx.ui.treefullcontrol.TreeFolder && + vItem._horizontalLayout) + { + return vItem._horizontalLayout.getOffsetHeight(); + } + else + { + return vItem.getOffsetHeight(); + } +} + +qx.Proto.scrollItemIntoView = function(vItem) +{ + if (vItem instanceof qx.ui.treefullcontrol.TreeFolder && + vItem._horizontalLayout) + { + return vItem._horizontalLayout.scrollIntoView(); + } + else + { + return vItem.scrollIntoView(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + ITEM STATE MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto.renderItemSelectionState = function(vItem, vIsSelected) { + vItem.setSelected(vIsSelected); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeSelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeSelectionManager.js new file mode 100644 index 0000000000..d140a341dc --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/TreeSelectionManager.js @@ -0,0 +1,200 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.manager.selection.TreeSelectionManager", qx.manager.selection.SelectionManager, +function(vBoundedWidget) { + qx.manager.selection.SelectionManager.call(this, vBoundedWidget); +}); + +/*! +Should multiple selection be allowed? +*/ +qx.OO.changeProperty({ name : "multiSelection", type : "boolean", defaultValue : false }); + +/*! +Enable drag selection? +*/ +qx.OO.changeProperty({ name : "dragSelection", type : "boolean", defaultValue : false }); + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO BOUNDED WIDGET +--------------------------------------------------------------------------- +*/ + +qx.Proto._getFirst = function() { + return qx.lang.Array.getFirst(this.getItems()); +} + +qx.Proto._getLast = function() { + return qx.lang.Array.getLast(this.getItems()); +} + +qx.Proto.getItems = function() { + return this.getBoundedWidget().getItems(); +} + +qx.Proto.getNext = function(vItem) +{ + if (vItem) + { + if (qx.ui.tree.Tree.isOpenTreeFolder(vItem)) + { + return vItem.getFirstVisibleChildOfFolder(); + } + else if (vItem.isLastVisibleChild()) + { + var vCurrent = vItem; + + while(vCurrent && vCurrent.isLastVisibleChild()) { + vCurrent = vCurrent.getParentFolder(); + } + + if (vCurrent && vCurrent instanceof qx.ui.tree.AbstractTreeElement && vCurrent.getNextVisibleSibling() && vCurrent.getNextVisibleSibling() instanceof qx.ui.tree.AbstractTreeElement) { + return vCurrent.getNextVisibleSibling(); + } + } + else + { + return vItem.getNextVisibleSibling(); + } + } + else + { + return this.getBoundedWidget().getFirstTreeChild(); + } +} + +qx.Proto.getPrevious = function(vItem) +{ + if (vItem) + { + if (vItem == this.getBoundedWidget()) + { + return; + } + else if (vItem.isFirstVisibleChild()) + { + if (vItem.getParentFolder() instanceof qx.ui.tree.TreeFolder) { + return vItem.getParentFolder(); + } + } + else + { + var vPrev = vItem.getPreviousVisibleSibling(); + + while (vPrev instanceof qx.ui.tree.AbstractTreeElement) + { + if (qx.ui.tree.Tree.isOpenTreeFolder(vPrev)) + { + vPrev = vPrev.getLastVisibleChildOfFolder(); + } + else + { + break; + } + } + + return vPrev; + } + } + else + { + return this.getBoundedWidget().getLastTreeChild(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemTop = function(vItem) +{ + // Alternate method: + // return qx.html.Location.getPageBoxTop(vItem.getElement()) - qx.html.Location.getPageInnerTop(this.getBoundedWidget().getElement()); + + var vBoundedWidget = this.getBoundedWidget(); + var vElement = vItem.getElement(); + var vOffset = 0; + + while (vElement && vElement.qx_Widget != vBoundedWidget) + { + vOffset += vElement.offsetTop; + vElement = vElement.parentNode; + } + + return vOffset; +} + +qx.Proto.getItemHeight = function(vItem) +{ + if (vItem instanceof qx.ui.tree.TreeFolder && vItem._horizontalLayout) + { + return vItem._horizontalLayout.getOffsetHeight(); + } + else + { + return vItem.getOffsetHeight(); + } +} + +qx.Proto.scrollItemIntoView = function(vItem) +{ + if (vItem instanceof qx.ui.tree.TreeFolder && vItem._horizontalLayout) + { + return vItem._horizontalLayout.scrollIntoView(); + } + else + { + return vItem.scrollIntoView(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + ITEM STATE MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto.renderItemSelectionState = function(vItem, vIsSelected) { + vItem.setSelected(vIsSelected); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/VirtualSelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/VirtualSelectionManager.js new file mode 100644 index 0000000000..f50f70c86d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/manager/selection/VirtualSelectionManager.js @@ -0,0 +1,145 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +/*! + This class represents a selection and manage incoming events for widgets which need selection support. +*/ +qx.OO.defineClass("qx.manager.selection.VirtualSelectionManager", qx.manager.selection.SelectionManager, +function(vBoundedWidget) { + qx.manager.selection.SelectionManager.call(this, vBoundedWidget); +}); + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO BOUNDED WIDGET +--------------------------------------------------------------------------- +*/ + +qx.Proto.getFirst = function() { + return qx.lang.Array.getFirst(this.getItems()); +} + +qx.Proto.getLast = function() { + return qx.lang.Array.getLast(this.getItems()); +} + +qx.Proto.getItems = function() { + return this.getBoundedWidget().getData(); +} + +qx.Proto.getNextSibling = function(vItem) +{ + var vData = this.getItems(); + return vData[vData.indexOf(vItem)+1]; +} + +qx.Proto.getPreviousSibling = function(vItem) +{ + var vData = this.getItems(); + return vData[vData.indexOf(vItem)-1]; +} + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItemHashCode = function(oItem) +{ + if (oItem._hash) { + return oItem._hash; + } + + return oItem._hash = qx.core.Object.toHashCode(oItem); +} + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO ITEM DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.scrollItemIntoView = function(vItem, vTopLeft) { + this.getBoundedWidget().scrollItemIntoView(vItem, vTopLeft); +} + +qx.Proto.getItemLeft = function(vItem) { + return this.getBoundedWidget().getItemLeft(vItem); +} + +qx.Proto.getItemTop = function(vItem) { + return this.getBoundedWidget().getItemTop(vItem); +} + +qx.Proto.getItemWidth = function(vItem) { + return this.getBoundedWidget().getItemWidth(vItem); +} + +qx.Proto.getItemHeight = function(vItem) { + return this.getBoundedWidget().getItemHeight(vItem); +} + +/*! + In a qx.ui.listview.ListView there are no disabled entries support currently. +*/ +qx.Proto.getItemEnabled = function(vItem) { + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + ITEM STATE MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto.renderItemSelectionState = function(vItem, vIsSelected) { + this.getBoundedWidget()._updateSelectionState(vItem, vIsSelected); +} + +qx.Proto.renderItemAnchorState = function(vItem, vIsAnchor) { + this.getBoundedWidget()._updateAnchorState(vItem, vIsAnchor); +} + +qx.Proto.renderItemLeadState = function(vItem, vIsLead) { + this.getBoundedWidget()._updateLeadState(vItem, vIsLead); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Http.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Http.js new file mode 100644 index 0000000000..d392aefc39 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Http.js @@ -0,0 +1,33 @@ +/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+************************************************************************ */
+
+/* ************************************************************************
+
+
+************************************************************************ */
+
+qx.OO.defineClass("qx.net.Http",
+{
+ METHOD_GET : "GET",
+ METHOD_POST : "POST",
+ METHOD_PUT : "PUT",
+ METHOD_HEAD : "HEAD",
+ METHOD_DELETE : "DELETE"
+});
diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/HttpRequest.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/HttpRequest.js new file mode 100644 index 0000000000..66849b7cf5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/HttpRequest.js @@ -0,0 +1,88 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.net.HttpRequest"); + +/** + * Return a new XMLHttpRequest object suitable for the client browser. + * + * TODO: extract detection of MSXML version (run once) + * + * @return {HttpRequest} + */ +qx.Class.create = function() { return null }; + +if (window.XMLHttpRequest) +{ + qx.Class.create = function() + { + return new XMLHttpRequest; + }; +} +else if (window.ActiveXObject) +{ + qx.Class.create = function() + { + /* + According to information on the Microsoft XML Team's WebLog + it is recommended to check for availability of MSXML versions 6.0 and 3.0. + Other versions are included for completeness, 5.0 is excluded as it is + "off-by-default" in IE7 (which could trigger a goldbar). + + http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/aabe29a2-bad2-4cea-8387-314174252a74.asp + + MSXML 3 is preferred over MSXML 6 because the IE7 native XMLHttpRequest returns + a MSXML 3 document and so does not properly work with other types of xml documents. + */ + var vServers = + [ + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP.6.0", + "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP", // v3.0 + "Microsoft.XMLHTTP" // v2.x + ]; + + var vObject; + var vServer; + + for (var i=0, l=vServers.length; i<l; i++) + { + vServer = vServers[i]; + + try + { + vObject = new ActiveXObject(vServer); + break; + } + catch(ex) + { + vObject = null; + } + } + return vObject + }; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Protocol.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Protocol.js new file mode 100644 index 0000000000..68b584d8ac --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/net/Protocol.js @@ -0,0 +1,37 @@ +/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+************************************************************************ */
+
+/* ************************************************************************
+
+
+************************************************************************ */
+
+qx.OO.defineClass("qx.net.Protocol",
+{
+ HTTP : "http",
+ HTTPS : "https",
+ FTP : "ftp",
+ FILE : "file",
+
+ URI_HTTP : "http://",
+ URI_HTTPS : "https://",
+ URI_FTP : "ftp://",
+ URI_FILE : "file://"
+});
diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/Border.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/Border.js new file mode 100644 index 0000000000..f5ac249de3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/Border.js @@ -0,0 +1,1187 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.core.Client) +#require(qx.renderer.color.ColorCache) +#load(qx.renderer.border.BorderObject) + +************************************************************************ */ + +/*! + Border implementation for qx.ui.core.Widget instances. +*/ +qx.OO.defineClass("qx.renderer.border.Border", qx.core.Object, +function(vWidth, vStyle, vColor) +{ + qx.core.Object.call(this); + + this._themedEdges = {}; + this._initCache(); + + if (vWidth != null) + { + this.setWidth(vWidth); + + if (vStyle != null) { + this.setStyle(vStyle); + } + + if (vColor != null) { + this.setColor(vColor); + } + } +}); + + +qx.Class.enhancedCrossBrowserMode = true; + +qx.Proto._needsCompilationTop = true; +qx.Proto._needsCompilationRight = true; +qx.Proto._needsCompilationBottom = true; +qx.Proto._needsCompilationLeft = true; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "topWidth", type : "number", defaultValue : 0, impl : "borderTopProperty" }); +qx.OO.addProperty({ name : "rightWidth", type : "number", defaultValue : 0, impl : "borderRightProperty" }); +qx.OO.addProperty({ name : "bottomWidth", type : "number", defaultValue : 0, impl : "borderBottomProperty" }); +qx.OO.addProperty({ name : "leftWidth", type : "number", defaultValue : 0, impl : "borderLeftProperty" }); + +qx.OO.addProperty({ name : "topStyle", type : "string", defaultValue : "none", impl : "borderTopProperty" }); +qx.OO.addProperty({ name : "rightStyle", type : "string", defaultValue : "none", impl : "borderRightProperty" }); +qx.OO.addProperty({ name : "bottomStyle", type : "string", defaultValue : "none", impl : "borderBottomProperty" }); +qx.OO.addProperty({ name : "leftStyle", type : "string", defaultValue : "none", impl : "borderLeftProperty" }); + +qx.OO.addProperty({ name : "topColor", impl : "borderTopProperty", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache }); +qx.OO.addProperty({ name : "rightColor", impl : "borderRightProperty", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache }); +qx.OO.addProperty({ name : "bottomColor", impl : "borderBottomProperty", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache }); +qx.OO.addProperty({ name : "leftColor", impl : "borderLeftProperty", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache }); + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.renderer.border.Border.fromString = function(vDefString) +{ + var vBorder = new qx.renderer.border.Border; + var vAllParts = vDefString.split(/\s+/); + var vPart, vTemp; + + for (var i=0; i<vAllParts.length; i++) + { + switch(vPart = vAllParts[i]) + { + case "groove": + case "ridge": + case "inset": + case "outset": + case "solid": + case "dotted": + case "dashed": + case "double": + case "none": + vBorder.setStyle(vPart); + break; + + default: + vTemp = parseFloat(vPart); + + if(vTemp == vPart || qx.lang.String.contains(vPart, "px")) + { + vBorder.setWidth(vTemp); + } + else + { + vPart = vPart.toLowerCase(); + vBorder.setColor(new qx.renderer.color.Color(vPart)); + } + + break; + } + } + + return vBorder; +} + + + + + +/* +--------------------------------------------------------------------------- + COMPATIBILITY TO qx.renderer.border.BorderOBJECT +--------------------------------------------------------------------------- +*/ + +qx.Proto.addListenerWidget = qx.lang.Function.returnTrue; +qx.Proto.removeListenerWidget = qx.lang.Function.returnTrue; + +qx.Proto._sync = qx.lang.Function.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + COMBINED SETTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto.setWidth = function(vWidth) +{ + this.setTopWidth(vWidth); + this.setRightWidth(vWidth); + this.setBottomWidth(vWidth); + this.setLeftWidth(vWidth); + + return true; +} + +qx.Proto.setStyle = function(vStyle) +{ + this.setTopStyle(vStyle); + this.setRightStyle(vStyle); + this.setBottomStyle(vStyle); + this.setLeftStyle(vStyle); + + return true; +} + +qx.Proto.setColor = function(vColor) +{ + this.setTopColor(vColor); + this.setRightColor(vColor); + this.setBottomColor(vColor); + this.setLeftColor(vColor); + + return true; +} + + + + +qx.Proto.setTop = function(vWidth, vStyle, vColor) +{ + this.setTopWidth(vWidth); + this.setTopStyle(vStyle); + this.setTopColor(vColor); + + return true; +} + +qx.Proto.setRight = function(vWidth, vStyle, vColor) +{ + this.setRightWidth(vWidth); + this.setRightStyle(vStyle); + this.setRightColor(vColor); + + return true; +} + +qx.Proto.setBottom = function(vWidth, vStyle, vColor) +{ + this.setBottomWidth(vWidth); + this.setBottomStyle(vStyle); + this.setBottomColor(vColor); + + return true; +} + +qx.Proto.setLeft = function(vWidth, vStyle, vColor) +{ + this.setLeftWidth(vWidth); + this.setLeftStyle(vStyle); + this.setLeftColor(vColor); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + INITIALISATION OF CACHE +--------------------------------------------------------------------------- +*/ + + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._initCache = function() + { + this._defsX = + { + borderLeft : "", + borderRight : "", + + MozBorderLeftColors : "", + MozBorderRightColors : "" + } + + this._defsY = + { + borderTop : "", + borderBottom : "", + + MozBorderTopColors : "", + MozBorderBottomColors : "" + } + } +} +else +{ + qx.Proto._initCache = function() + { + this._defsX = + { + borderLeft : "", + borderRight : "" + } + + this._defsY = + { + borderTop : "", + borderBottom : "" + } + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + this._enhancedDefsX = + { + borderLeft : "", + borderRight : "" + } + + this._enhancedDefsY = + { + borderTop : "", + borderBottom : "" + } + } + } +} + + +/* +--------------------------------------------------------------------------- + BORDER MODIFIER AND SYNCER +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isGecko() || qx.renderer.border.Border.enhancedCrossBrowserMode) +{ + qx.Proto._addToThemed3DColors = function(vProp) + { + var needRegistering = qx.lang.Object.isEmpty(this._themedEdges); + + this._themedEdges[vProp] = true; + + if (needRegistering) + { + (new qx.renderer.color.ColorObject("ThreeDDarkShadow")).add(this); + (new qx.renderer.color.ColorObject("ThreeDShadow")).add(this); + (new qx.renderer.color.ColorObject("ThreeDLightShadow")).add(this); + (new qx.renderer.color.ColorObject("ThreeDHighlight")).add(this); + } + } + + qx.Proto._removeFromThemed3DColors = function(vProp) + { + delete this._themedEdges[vProp]; + + if (qx.lang.Object.isEmpty(this._themedEdges)) + { + (new qx.renderer.color.ColorObject("ThreeDDarkShadow")).remove(this); + (new qx.renderer.color.ColorObject("ThreeDShadow")).remove(this); + (new qx.renderer.color.ColorObject("ThreeDLightShadow")).remove(this); + (new qx.renderer.color.ColorObject("ThreeDHighlight")).remove(this); + } + } +} +else +{ + qx.Proto._addToThemed3DColors = function(vProp) + { + var needRegistering = qx.lang.Object.isEmpty(this._themedEdges); + + this._themedEdges[vProp] = true; + + if (needRegistering) + { + (new qx.renderer.color.ColorObject("ThreeDLightShadow")).add(this); + } + } + + qx.Proto._removeFromThemed3DColors = function(vProp) + { + delete this._themedEdges[vProp]; + + if (qx.lang.Object.isEmpty(this._themedEdges)) + { + (new qx.renderer.color.ColorObject("ThreeDLightShadow")).remove(this); + } + } +} + + + + + +qx.renderer.border.Border.data = +{ + 1 : + { + outset : + { + top : [ "threedhighlight" ], + right : [ "threedshadow" ], + bottom : [ "threedshadow" ], + left : [ "threedhighlight" ] + }, + + inset : + { + top : [ "threedshadow" ], + right : [ "threedhighlight" ], + bottom : [ "threedhighlight" ], + left : [ "threedshadow" ] + } + }, + + 2 : + { + outset : + { + top : [ "threedlightshadow", "threedhighlight" ], + right : [ "threeddarkshadow", "threedshadow" ], + bottom : [ "threeddarkshadow", "threedshadow" ], + left : [ "threedlightshadow", "threedhighlight" ] + }, + + inset : + { + top : [ "threedshadow", "threeddarkshadow" ], + right : [ "threedhighlight", "threedlightshadow" ], + bottom : [ "threedhighlight", "threedlightshadow" ], + left : [ "threedshadow", "threeddarkshadow" ] + }, + + ridge : + { + top : [ "threedhighlight", "threedshadow" ], + right : [ "threedshadow", "threedhighlight" ], + bottom : [ "threedshadow", "threedhighlight" ], + left : [ "threedhighlight", "threedshadow" ] + }, + + groove : + { + top : [ "threedshadow", "threedhighlight" ], + right : [ "threedhighlight", "threedshadow" ], + bottom : [ "threedhighlight", "threedshadow" ], + left : [ "threedshadow", "threedhighlight" ] + } + } +} + + + + + +qx.Proto._generateDefString = function(vWidth, vStyle, vColor) +{ + if (typeof vWidth !== "number" || vWidth < 0) { + return ""; + } + + var vArr = [ vWidth + "px" ]; + + if (vStyle != null) { + vArr.push(vStyle); + } + + if (vColor instanceof qx.renderer.color.Color) { + vColor = vColor.getStyle(); + } + + if (vColor != null) { + vArr.push(vColor); + } + + return vArr.join(" "); +} + + + + +// TODO: Add more smartness ;) +// Only update the border edges which depends on this color object +qx.Proto._updateColors = function(vColorObject, vNewValue) +{ + this._needsCompilationTop = true; + this._needsCompilationRight = true; + this._needsCompilationBottom = true; + this._needsCompilationLeft = true; + + this._sync("top"); + this._sync("right"); + this._sync("bottom"); + this._sync("left"); +} + + + + + + + +qx.Proto._handleColorRegistration = function(propValue, propOldValue, propData) +{ + if (qx.lang.String.contains(propData.name, "Style")) + { + switch(propValue) + { + case "outset": + case "inset": + case "groove": + case "ridge": + this._addToThemed3DColors(propData.name); + break; + + default: + this._removeFromThemed3DColors(propData.name); + } + } + + if (qx.lang.String.contains(propData.name, "Color")) + { + if (propOldValue instanceof qx.renderer.color.ColorObject) + { + // detect if there are no other deps anymore + switch(propOldValue) + { + case this.getTopColor(): + case this.getRightColor(): + case this.getBottomColor(): + case this.getLeftColor(): + break; + + default: + propOldValue.remove(this); + } + } + + if (propValue instanceof qx.renderer.color.ColorObject) + { + // simply add, internal storage is a hash key so + // this is not a problem also if this is already + // registered there. + propValue.add(this); + } + } +} + + + + + + + + +qx.Proto._modifyBorderTopProperty = function(propValue, propOldValue, propData) +{ + this._handleColorRegistration(propValue, propOldValue, propData); + + this._needsCompilationTop = true; + this._useEnhancedCrossBrowserMode = null; + + this._sync("top"); + + return true; +} + +qx.Proto._modifyBorderRightProperty = function(propValue, propOldValue, propData) +{ + this._handleColorRegistration(propValue, propOldValue, propData); + + this._needsCompilationRight = true; + this._useEnhancedCrossBrowserMode = null; + + this._sync("right"); + + return true; +} + +qx.Proto._modifyBorderBottomProperty = function(propValue, propOldValue, propData) +{ + this._handleColorRegistration(propValue, propOldValue, propData); + + this._needsCompilationBottom = true; + this._useEnhancedCrossBrowserMode = null; + + this._sync("bottom"); + + return true; +} + +qx.Proto._modifyBorderLeftProperty = function(propValue, propOldValue, propData) +{ + this._handleColorRegistration(propValue, propOldValue, propData); + + this._needsCompilationLeft = true; + this._useEnhancedCrossBrowserMode = null; + + this._sync("left"); + + return true; +} + + + + + + + + + +qx.Proto.getUseEnhancedCrossBrowserMode = function() +{ + if (this._useEnhancedCrossBrowserMode == null) { + this._useEnhancedCrossBrowserMode = this._evalUseEnhancedCrossBrowserMode(); + } + + return this._useEnhancedCrossBrowserMode; +} + +qx.Proto._evalUseEnhancedCrossBrowserMode = function() +{ + if (this.getTopWidth() == 2) { + switch(this.getTopStyle()) { + case "outset": case "inset": case "groove": case "ridge": return true; + } + } + + if (this.getRightWidth() == 2) { + switch(this.getRightStyle()) { + case "outset": case "inset": case "groove": case "ridge": return true; + } + } + + if (this.getBottomWidth() == 2) { + switch(this.getBottomStyle()) { + case "outset": case "inset": case "groove": case "ridge": return true; + } + } + + if (this.getLeftWidth() == 2) { + switch(this.getLeftStyle()) { + case "outset": case "inset": case "groove": case "ridge": return true; + } + } + + return false; +} + + + + + + +/* +--------------------------------------------------------------------------- + BORDER APPLY IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyWidget = function(o) +{ + this._applyWidgetX(o); + this._applyWidgetY(o); +} + +qx.Proto._resetWidget = function(o) +{ + this._resetWidgetX(o); + this._resetWidgetY(o); +} + +qx.Proto._resetWidgetX = function(o) { + return qx.renderer.border.Border._resetBorderX(o); +} + +qx.Proto._resetWidgetY = function(o) { + return qx.renderer.border.Border._resetBorderY(o); +} + +qx.Proto._applyWidgetXCommon = function(vObject) +{ + if (this._needsCompilationLeft) { + this._compileLeft(); + } + + if (this._needsCompilationRight) { + this._compileRight(); + } + + for (var i in this._defsX) { + vObject._style[i] = this._defsX[i]; + } + + if (!qx.core.Client.getInstance().isGecko() && qx.renderer.border.Border.enhancedCrossBrowserMode) + { + if (this.getUseEnhancedCrossBrowserMode()) { + vObject._createElementForEnhancedBorder(); + } + + if (vObject._borderStyle) + { + for (var i in this._enhancedDefsX) { + vObject._borderStyle[i] = this._enhancedDefsX[i]; + } + } + } +} + +qx.Proto._applyWidgetYCommon = function(vObject) +{ + if (this._needsCompilationTop) { + this._compileTop(); + } + + if (this._needsCompilationBottom) { + this._compileBottom(); + } + + for (var i in this._defsY) { + vObject._style[i] = this._defsY[i]; + } + + if (!qx.core.Client.getInstance().isGecko() && qx.renderer.border.Border.enhancedCrossBrowserMode) + { + if (this.getUseEnhancedCrossBrowserMode()) { + vObject._createElementForEnhancedBorder(); + } + + if (vObject._borderStyle) + { + for (var i in this._enhancedDefsY) { + vObject._borderStyle[i] = this._enhancedDefsY[i]; + } + } + } +} + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._applyWidgetX = qx.Proto._applyWidgetXCommon; + qx.Proto._applyWidgetY = qx.Proto._applyWidgetYCommon; + + qx.Proto._generateMozColorDefString = function(vWidth, vStyle, vEdge) + { + try + { + try { + var a = qx.renderer.border.Border.data[vWidth][vStyle][vEdge]; + } catch(ex) {} + + if (typeof a === "object") + { + for (var i=0, s=[], l=a.length; i<l; i++) { + s.push((new qx.renderer.color.ColorObject(a[i]).getStyle())); + } + + return s.join(" "); + } + } + catch(ex) { + this.error("Failed to generate Mozilla Color Definition Strings", ex); + } + + return ""; + } + + qx.Proto._compileTop = function() + { + var w=this.getTopWidth(), s=this.getTopStyle(), d=this._defsY; + + d.borderTop = this._generateDefString(w, s, this.getTopColor()); + d.MozBorderTopColors = this._generateMozColorDefString(w, s, "top"); + + this._needsCompilationTop = false; + } + + qx.Proto._compileRight = function() + { + var w=this.getRightWidth(), s=this.getRightStyle(), d=this._defsX; + + d.borderRight = this._generateDefString(w, s, this.getRightColor()); + d.MozBorderRightColors = this._generateMozColorDefString(w, s, "right"); + + this._needsCompilationRight = false; + } + + qx.Proto._compileBottom = function() + { + var w=this.getBottomWidth(), s=this.getBottomStyle(), d=this._defsY; + + d.borderBottom = this._generateDefString(w, s, this.getBottomColor()); + d.MozBorderBottomColors = this._generateMozColorDefString(w, s, "bottom"); + + this._needsCompilationBottom = false; + } + + qx.Proto._compileLeft = function() + { + var w=this.getLeftWidth(), s=this.getLeftStyle(), d=this._defsX; + + d.borderLeft = this._generateDefString(w, s, this.getLeftColor()); + d.MozBorderLeftColors = this._generateMozColorDefString(w, s, "left"); + + this._needsCompilationLeft = false; + } + + qx.renderer.border.Border._resetBorderX = function(o) + { + var s = o._style; + s.borderLeft = s.borderRight = s.MozBorderLeftColors = s.MozBorderRightColors = ""; + } + + qx.renderer.border.Border._resetBorderY = function(o) + { + var s = o._style; + s.borderTop = s.borderBottom = s.MozBorderTopColors = s.MozBorderBottomColors = ""; + } +} +else +{ + qx.Proto._applyWidgetX = function(vObject) + { + this._applyWidgetXCommon(vObject); + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + if (this.getUseEnhancedCrossBrowserMode()) { + vObject._createElementForEnhancedBorder(); + } + + if (vObject._borderStyle) + { + for (var i in this._enhancedDefsX) { + vObject._borderStyle[i] = this._enhancedDefsX[i]; + } + } + } + } + + qx.Proto._applyWidgetY = function(vObject) + { + this._applyWidgetYCommon(vObject); + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + if (this.getUseEnhancedCrossBrowserMode()) { + vObject._createElementForEnhancedBorder(); + } + + if (vObject._borderStyle) + { + for (var i in this._enhancedDefsY) { + vObject._borderStyle[i] = this._enhancedDefsY[i]; + } + } + } + } + + qx.Proto._compileTop = function() + { + var vTopWidth = this.getTopWidth(); + var vTopStyle = this.getTopStyle(); + var vTopColor = this.getTopColor(); + + switch(vTopWidth) + { + case 1: + switch(vTopStyle) + { + case "outset": + case "inset": + vTopColor = (new qx.renderer.color.ColorObject(qx.renderer.border.Border.data[vTopWidth][vTopStyle]["top"][0])); + vTopStyle = "solid"; + } + + break; + + case 2: + switch(vTopStyle) + { + case "outset": + case "inset": + case "groove": + case "ridge": + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + try + { + var c = qx.renderer.border.Border.data[vTopWidth][vTopStyle]["top"]; + + if (typeof c === "object") + { + vTopStyle = "solid"; + vTopWidth = 1; + vTopColor = (new qx.renderer.color.ColorObject(c[1])); + + this._enhancedDefsY.borderTop = this._generateDefString(vTopWidth, vTopStyle, vTopColor); + + vTopColor = (new qx.renderer.color.ColorObject(c[0])); + } + } + catch(ex) + { + this.error("Failed to compile top border", ex); + this.warn("Details: Width=" + vTopWidth + ", Style=" + vTopStyle); + } + } + else + { + vTopColor = (new qx.renderer.color.ColorObject("threedlightshadow")); + } + } + + break; + } + + this._defsY.borderTop = this._generateDefString(vTopWidth, vTopStyle, vTopColor); + this._needsCompilationTop = false; + } + + qx.Proto._compileRight = function() + { + var vRightWidth = this.getRightWidth(); + var vRightStyle = this.getRightStyle(); + var vRightColor = this.getRightColor(); + + switch(vRightWidth) + { + case 1: + switch(vRightStyle) + { + case "outset": + case "inset": + vRightColor = (new qx.renderer.color.ColorObject(qx.renderer.border.Border.data[vRightWidth][vRightStyle]["right"][0])); + vRightStyle = "solid"; + } + + break; + + case 2: + switch(vRightStyle) + { + case "outset": + case "inset": + case "groove": + case "ridge": + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + try + { + var c = qx.renderer.border.Border.data[vRightWidth][vRightStyle]["right"]; + + if (typeof c === "object") + { + vRightStyle = "solid"; + vRightWidth = 1; + vRightColor = (new qx.renderer.color.ColorObject(c[1])); + + this._enhancedDefsX.borderRight = this._generateDefString(vRightWidth, vRightStyle, vRightColor); + + vRightColor = (new qx.renderer.color.ColorObject(c[0])); + } + } + catch(ex) + { + this.error("Failed to compile right border", ex); + this.warn("Details: Width=" + vRightWidth + ", Style=" + vRightStyle); + } + } + else + { + vRightColor = (new qx.renderer.color.ColorObject("threedlightshadow")); + } + } + + break; + } + + this._defsX.borderRight = this._generateDefString(vRightWidth, vRightStyle, vRightColor); + this._needsCompilationRight = false; + } + + qx.Proto._compileBottom = function() + { + var vBottomWidth = this.getBottomWidth(); + var vBottomStyle = this.getBottomStyle(); + var vBottomColor = this.getBottomColor(); + + switch(vBottomWidth) + { + case 1: + switch(vBottomStyle) + { + case "outset": + case "inset": + vBottomColor = (new qx.renderer.color.ColorObject(qx.renderer.border.Border.data[vBottomWidth][vBottomStyle]["bottom"][0])); + vBottomStyle = "solid"; + } + + break; + + case 2: + switch(vBottomStyle) + { + case "outset": + case "inset": + case "groove": + case "ridge": + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + try + { + var c = qx.renderer.border.Border.data[vBottomWidth][vBottomStyle]["bottom"]; + + if (typeof c === "object") + { + vBottomStyle = "solid"; + vBottomWidth = 1; + vBottomColor = (new qx.renderer.color.ColorObject(c[1])); + + this._enhancedDefsY.borderBottom = this._generateDefString(vBottomWidth, vBottomStyle, vBottomColor); + + vBottomColor = (new qx.renderer.color.ColorObject(c[0])); + } + } + catch(ex) { + this.error("Failed to compile bottom border", ex); + this.warn("Details: Width=" + vBottomWidth + ", Style=" + vBottomStyle); + } + } + else + { + vBottomColor = (new qx.renderer.color.ColorObject("threedlightshadow")); + } + } + + break; + } + + this._defsY.borderBottom = this._generateDefString(vBottomWidth, vBottomStyle, vBottomColor); + this._needsCompilationBottom = false; + } + + qx.Proto._compileLeft = function() + { + var vLeftWidth = this.getLeftWidth(); + var vLeftStyle = this.getLeftStyle(); + var vLeftColor = this.getLeftColor(); + + switch(vLeftWidth) + { + case 1: + switch(vLeftStyle) + { + case "outset": + case "inset": + vLeftColor = (new qx.renderer.color.ColorObject(qx.renderer.border.Border.data[vLeftWidth][vLeftStyle]["left"][0])); + vLeftStyle = "solid"; + } + + break; + + case 2: + switch(vLeftStyle) + { + case "outset": + case "inset": + case "groove": + case "ridge": + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + try + { + var c = qx.renderer.border.Border.data[vLeftWidth][vLeftStyle]["left"]; + + if (typeof c === "object") + { + vLeftStyle = "solid"; + vLeftWidth = 1; + vLeftColor = (new qx.renderer.color.ColorObject(c[1])); + + this._enhancedDefsX.borderLeft = this._generateDefString(vLeftWidth, vLeftStyle, vLeftColor); + + vLeftColor = (new qx.renderer.color.ColorObject(c[0])); + } + } + catch(ex) { + this.error("Failed to compile left border", ex); + this.warn("Details: Width=" + vLeftWidth + ", Style=" + vLeftStyle); + } + } + else + { + vLeftColor = (new qx.renderer.color.ColorObject("threedlightshadow")); + } + } + + break; + } + + this._defsX.borderLeft = this._generateDefString(vLeftWidth, vLeftStyle, vLeftColor); + this._needsCompilationLeft = false; + } + + qx.renderer.border.Border._resetBorderX = function(o) + { + var s = o._style; + s.borderLeft = s.borderRight = "0px none"; + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + s = o._borderStyle; + if (s) { + s.borderLeft = s.borderRight = "0px none"; + } + } + } + + qx.renderer.border.Border._resetBorderY = function(o) + { + var s = o._style; + s.borderTop = s.borderBottom = "0px none"; + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + s = o._borderStyle; + if (s) { + s.borderTop = s.borderBottom = "0px none"; + } + } + } +} + + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (typeof this._defsX === "object") { + for (var i in this._defsX) { + delete this._defsX[i]; + } + } + + delete this._defsX; + + if (typeof this._defsY === "object") { + for (var i in this._defsY) { + delete this._defsY[i]; + } + } + + delete this._defsY; + + if (qx.renderer.border.Border.enhancedCrossBrowserMode) + { + if (typeof this._enhancedDefsX === "object") { + for (var i in this._enhancedDefsX) { + delete this._enhancedDefsX[i]; + } + } + + delete this._enhancedDefsX; + + if (typeof this._enhancedDefsY === "object") { + for (var i in this._enhancedDefsY) { + delete this._enhancedDefsY[i]; + } + } + + delete this._enhancedDefsY; + } + + delete this._themedEdges; + + return qx.core.Object.prototype.dispose.call(this); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + PRESETS +--------------------------------------------------------------------------- +*/ + +/* +qx.Class.presets = +{ + black : new qx.Class(1, "solid", "black"), + white : new qx.Class(1, "solid", "white"), + none : new qx.Class(0, "none") +} +*/ diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderCache.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderCache.js new file mode 100644 index 0000000000..d8a9ac9d3d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderCache.js @@ -0,0 +1,64 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.border.BorderCache"); + +qx.renderer.border.BorderCache = function(propValue, propData) +{ + if (qx.util.Validation.isValidArray(propValue) && propValue.length > 1) + { + propString = ""; + + for (var i=0, l=propValue.length, p; i<l; i++) + { + p = propValue[i]; + + propString += p; + + if (typeof p === "number") { + propString += "px"; + } + + if (i<(l-1)) { + propString += " "; + } + } + + propValue = propString; + } + else if (qx.util.Validation.isInvalidString(propValue)) + { + return propValue; + } + + if (qx.renderer.border.BorderCache._data[propValue]) { + return qx.renderer.border.BorderCache._data[propValue]; + } + + return qx.renderer.border.BorderCache._data[propValue] = qx.renderer.border.BorderObject.fromString(propValue); +} + +qx.renderer.border.BorderCache._data = {}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderObject.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderObject.js new file mode 100644 index 0000000000..89a963cf41 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderObject.js @@ -0,0 +1,151 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.border.BorderObject", qx.renderer.border.Border, +function(vWidth, vStyle, vColor) +{ + this._dependentObjects = {}; + + qx.renderer.border.Border.call(this, vWidth, vStyle, vColor); +}); + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.renderer.border.BorderObject.fromString = function(vDefString) +{ + var vBorder = new qx.renderer.border.BorderObject; + var vAllParts = vDefString.split(/\s+/); + var vPart, vTemp; + + for (var i=0; i<vAllParts.length; i++) + { + vPart = vAllParts[i]; + + switch(vPart) + { + case "groove": + case "ridge": + case "inset": + case "outset": + case "solid": + case "dotted": + case "dashed": + case "double": + case "none": + vBorder.setStyle(vPart); + break; + + default: + vTemp = parseFloat(vPart); + + if(vTemp == vPart || qx.lang.String.contains(vPart, "px")) + { + vBorder.setWidth(vTemp); + } + else + { + vPart = vPart.toLowerCase(); + vBorder.setColor(qx.renderer.color.Color.themedNames[vPart] ? new qx.renderer.color.ColorObject(vPart) : new qx.renderer.color.Color(vPart)); + } + + break; + } + } + + return vBorder; +} + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET CONNECTION +--------------------------------------------------------------------------- +*/ + +qx.Proto.addListenerWidget = function(o) { + this._dependentObjects[o.toHashCode()] = o; +} + +qx.Proto.removeListenerWidget = function(o) { + delete this._dependentObjects[o.toHashCode()]; +} + +qx.Proto._sync = function(vEdge) +{ + var vAll = this._dependentObjects; + var vCurrent; + + for (vKey in vAll) + { + vCurrent = vAll[vKey]; + + if (vCurrent.isCreated()) { + vCurrent._updateBorder(vEdge); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (typeof this._dependentObjects === "object") + { + var vAll = this._dependentObjects; + for (vKey in vAll) { + delete vAll[vKey]; + } + + vAll = null; + delete this._dependentObjects; + } + + return qx.renderer.border.Border.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderPresets.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderPresets.js new file mode 100644 index 0000000000..8ac7fbe439 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/border/BorderPresets.js @@ -0,0 +1,73 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + Some common used border styles. +*/ +qx.OO.defineClass("qx.renderer.border.BorderPresets", qx.core.Object, function() +{ + qx.core.Object.call(this); + + this.black = new qx.renderer.border.Border(1, "solid", "black"); + this.white = new qx.renderer.border.Border(1, "solid", "white"); + this.none = new qx.renderer.border.Border(0, "none"); + + this.inset = new qx.renderer.border.BorderObject(2, "inset"); + this.outset = new qx.renderer.border.BorderObject(2, "outset"); + this.groove = new qx.renderer.border.BorderObject(2, "groove"); + this.ridge = new qx.renderer.border.BorderObject(2, "ridge"); + this.thinInset = new qx.renderer.border.BorderObject(1, "inset"); + this.thinOutset = new qx.renderer.border.BorderObject(1, "outset"); + + this.verticalDivider = new qx.renderer.border.BorderObject(1, "inset"); + this.verticalDivider.setLeftWidth(0); + this.verticalDivider.setRightWidth(0); + + this.horizontalDivider = new qx.renderer.border.BorderObject(1, "inset"); + this.horizontalDivider.setTopWidth(0); + this.horizontalDivider.setBottomWidth(0); + + this.shadow = new qx.renderer.border.BorderObject(1, "solid", "threedshadow"); + this.lightShadow = new qx.renderer.border.BorderObject(1, "solid", "threedlightshadow"); + this.info = new qx.renderer.border.BorderObject(1, "solid", "infotext"); +}); + + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/Color.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/Color.js new file mode 100644 index 0000000000..37af8611fb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/Color.js @@ -0,0 +1,669 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.lang.Function) +#load(qx.renderer.color.ColorObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.color.Color", qx.core.Object, +function(vValue) +{ + if (vValue != null) { + this.setValue(vValue); + } + + qx.core.Object.call(this); +}); + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ + +qx.Class.rgb2style = function(r, g, b) { + return "rgb(" + r + "," + g + "," + b + ")"; +} + + + + + +/* +--------------------------------------------------------------------------- + CORE DATA +--------------------------------------------------------------------------- +*/ + +qx.renderer.color.Color.m_hex = [ "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f" ]; +qx.renderer.color.Color.m_rgb = { 0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:11,c:12,d:13,e:14,f:15 } + +qx.renderer.color.Color.r_hex3 = /^#([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})$/; +qx.renderer.color.Color.r_hex6 = /^#([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})$/; +qx.renderer.color.Color.r_cssrgb = /^rgb\(\s*([0-9]{1,3}\.{0,1}[0-9]*)\s*,\s*([0-9]{1,3}\.{0,1}[0-9]*)\s*,\s*([0-9]{1,3}\.{0,1}[0-9]*)\s*\)$/; + +qx.renderer.color.Color.r_rgb = /^[0-9]{1,3},[0-9]{1,3},[0-9]{1,3}$/; +qx.renderer.color.Color.r_number = /^[0-9]{1,3}\.{0,1}[0-9]*$/; +qx.renderer.color.Color.r_percent = /^[0-9]{1,3}\.{0,1}[0-9]*%$/; + +/** + * CSS 3 colors (http://www.w3.org/TR/css3-color/#svg-color) + * + * This includes all classic HTML Color names (http://www.w3.org/TR/css3-color/#html4) and the <code>transparent</code> keyword. + */ +qx.Class.htmlNames = +{ + transparent : [-1,-1,-1], + aliceblue : [ 240,248,255 ], + antiquewhite : [ 250,235,215 ], + aqua : [ 0,255,255 ], + aquamarine : [ 127,255,212 ], + azure : [ 240,255,255 ], + beige : [ 245,245,220 ], + bisque : [ 255,228,196 ], + black : [ 0,0,0 ], + blanchedalmond : [ 255,235,205 ], + blue : [ 0,0,255 ], + blueviolet : [ 138,43,226 ], + brown : [ 165,42,42 ], + burlywood : [ 222,184,135 ], + cadetblue : [ 95,158,160 ], + chartreuse : [ 127,255,0 ], + chocolate : [ 210,105,30 ], + coral : [ 255,127,80 ], + cornflowerblue : [ 100,149,237 ], + cornsilk : [ 255,248,220 ], + crimson : [ 220,20,60 ], + cyan : [ 0,255,255 ], + darkblue : [ 0,0,139 ], + darkcyan : [ 0,139,139 ], + darkgoldenrod : [ 184,134,11 ], + darkgray : [ 169,169,169 ], + darkgreen : [ 0,100,0 ], + darkgrey : [ 169,169,169 ], + darkkhaki : [ 189,183,107 ], + darkmagenta : [ 139,0,139 ], + darkolivegreen : [ 85,107,47 ], + darkorange : [ 255,140,0 ], + darkorchid : [ 153,50,204 ], + darkred : [ 139,0,0 ], + darksalmon : [ 233,150,122 ], + darkseagreen : [ 143,188,143 ], + darkslateblue : [ 72,61,139 ], + darkslategray : [ 47,79,79 ], + darkslategrey : [ 47,79,79 ], + darkturquoise : [ 0,206,209 ], + darkviolet : [ 148,0,211 ], + deeppink : [ 255,20,147 ], + deepskyblue : [ 0,191,255 ], + dimgray : [ 105,105,105 ], + dimgrey : [ 105,105,105 ], + dodgerblue : [ 30,144,255 ], + firebrick : [ 178,34,34 ], + floralwhite : [ 255,250,240 ], + forestgreen : [ 34,139,34 ], + fuchsia : [ 255,0,255 ], + gainsboro : [ 220,220,220 ], + ghostwhite : [ 248,248,255 ], + gold : [ 255,215,0 ], + goldenrod : [ 218,165,32 ], + gray : [ 128,128,128 ], + green : [ 0,128,0 ], + greenyellow : [ 173,255,47 ], + grey : [ 128,128,128 ], + honeydew : [ 240,255,240 ], + hotpink : [ 255,105,180 ], + indianred : [ 205,92,92 ], + indigo : [ 75,0,130 ], + ivory : [ 255,255,240 ], + khaki : [ 240,230,140 ], + lavender : [ 230,230,250 ], + lavenderblush : [ 255,240,245 ], + lawngreen : [ 124,252,0 ], + lemonchiffon : [ 255,250,205 ], + lightblue : [ 173,216,230 ], + lightcoral : [ 240,128,128 ], + lightcyan : [ 224,255,255 ], + lightgoldenrodyellow : [ 250,250,210 ], + lightgray : [ 211,211,211 ], + lightgreen : [ 144,238,144 ], + lightgrey : [ 211,211,211 ], + lightpink : [ 255,182,193 ], + lightsalmon : [ 255,160,122 ], + lightseagreen : [ 32,178,170 ], + lightskyblue : [ 135,206,250 ], + lightslategray : [ 119,136,153 ], + lightslategrey : [ 119,136,153 ], + lightsteelblue : [ 176,196,222 ], + lightyellow : [ 255,255,224 ], + lime : [ 0,255,0 ], + limegreen : [ 50,205,50 ], + linen : [ 250,240,230 ], + magenta : [ 255,0,255 ], + maroon : [ 128,0,0 ], + mediumaquamarine : [ 102,205,170 ], + mediumblue : [ 0,0,205 ], + mediumorchid : [ 186,85,211 ], + mediumpurple : [ 147,112,219 ], + mediumseagreen : [ 60,179,113 ], + mediumslateblue : [ 123,104,238 ], + mediumspringgreen : [ 0,250,154 ], + mediumturquoise : [ 72,209,204 ], + mediumvioletred : [ 199,21,133 ], + midnightblue : [ 25,25,112 ], + mintcream : [ 245,255,250 ], + mistyrose : [ 255,228,225 ], + moccasin : [ 255,228,181 ], + navajowhite : [ 255,222,173 ], + navy : [ 0,0,128 ], + oldlace : [ 253,245,230 ], + olive : [ 128,128,0 ], + olivedrab : [ 107,142,35 ], + orange : [ 255,165,0 ], + orangered : [ 255,69,0 ], + orchid : [ 218,112,214 ], + palegoldenrod : [ 238,232,170 ], + palegreen : [ 152,251,152 ], + paleturquoise : [ 175,238,238 ], + palevioletred : [ 219,112,147 ], + papayawhip : [ 255,239,213 ], + peachpuff : [ 255,218,185 ], + peru : [ 205,133,63 ], + pink : [ 255,192,203 ], + plum : [ 221,160,221 ], + powderblue : [ 176,224,230 ], + purple : [ 128,0,128 ], + red : [ 255,0,0 ], + rosybrown : [ 188,143,143 ], + royalblue : [ 65,105,225 ], + saddlebrown : [ 139,69,19 ], + salmon : [ 250,128,114 ], + sandybrown : [ 244,164,96 ], + seagreen : [ 46,139,87 ], + seashell : [ 255,245,238 ], + sienna : [ 160,82,45 ], + silver : [ 192,192,192 ], + skyblue : [ 135,206,235 ], + slateblue : [ 106,90,205 ], + slategray : [ 112,128,144 ], + slategrey : [ 112,128,144 ], + snow : [ 255,250,250 ], + springgreen : [ 0,255,127 ], + steelblue : [ 70,130,180 ], + tan : [ 210,180,140 ], + teal : [ 0,128,128 ], + thistle : [ 216,191,216 ], + tomato : [ 255,99,71 ], + turquoise : [ 64,224,208 ], + violet : [ 238,130,238 ], + wheat : [ 245,222,179 ], + white : [ 255,255,255 ], + whitesmoke : [ 245,245,245 ], + yellow : [ 255,255,0 ], + yellowgreen : [ 154,205,50 ] +}; + +/** + * ActiveBorder: Active window border. + * ActiveCaption: Active window caption. + * + * AppWorkspace: Background color of multiple document interface. + * Background: Desktop background. + * + * ButtonFace: Face color for three-dimensional display elements. + * ButtonHighlight: Highlight color for three-dimensional display elements (for edges facing away from the light source). + * ButtonShadow: Shadow color for three-dimensional display elements. + * ButtonText: Text on push buttons. + * + * CaptionText: Text in caption, size box, and scrollbar arrow box. + * GrayText: Grayed (disabled) text. + * + * Highlight: Item(s) selected in a control. + * HighlightText: Text of item(s) selected in a control. + * + * InactiveBorder: Inactive window border. + * InactiveCaption: Inactive window caption. + * InactiveCaptionText: Color of text in an inactive caption. + * + * InfoBackground: Background color for tooltip controls. + * InfoText: Text color for tooltip controls. + * + * Menu: Menu background. + * MenuText: Text in menus. + * + * Scrollbar: Scroll bar gray area. + * + * ThreeDDarkShadow: Dark shadow for three-dimensional display elements. + * ThreeDFace: Face color for three-dimensional display elements. + * ThreeDHighlight: Highlight color for three-dimensional display elements. + * ThreeDLightShadow: Light color for three-dimensional display elements (for edges facing the light source). + * ThreeDShadow: Dark shadow for three-dimensional display elements. + * + * Window: Window background. + * WindowFrame: Window frame. + * WindowText: Text in windows. + */ +qx.Class.themedNames = +{ + activeborder : 1, + activecaption : 1, + appworkspace : 1, + background : 1, + buttonface : 1, + buttonhighlight : 1, + buttonshadow : 1, + buttontext : 1, + captiontext : 1, + graytext : 1, + highlight : 1, + highlighttext : 1, + inactiveborder : 1, + inactivecaption : 1, + inactivecaptiontext : 1, + infobackground : 1, + infotext : 1, + menu : 1, + menutext : 1, + scrollbar : 1, + threeddarkshadow : 1, + threedface : 1, + threedhighlight : 1, + threedlightshadow : 1, + threedshadow : 1, + window : 1, + windowframe : 1, + windowtext : 1 +} + + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Class.fromString = function(vDefString) { + return new qx.renderer.color.Color(vDefString); +} + +qx.Class.fromRandom = function() { + return new qx.renderer.color.Color([Math.round(255*Math.random()), Math.round(255*Math.random()), Math.round(255*Math.random())]); +} + + + + + + +/* +--------------------------------------------------------------------------- + DATA +--------------------------------------------------------------------------- +*/ + +qx.Proto._value = null; +qx.Proto._style = null; + +qx.Proto._isRgbColor = false; +qx.Proto._isHtmlColor = false; +qx.Proto._isThemedColor = false; + +qx.Proto._red = null; +qx.Proto._green = null; +qx.Proto._blue = null; + +qx.Proto._hex = null; + + + + + +/* +--------------------------------------------------------------------------- + COMPATIBILITY METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = qx.lang.Function.returnTrue; +qx.Proto.remove = qx.lang.Function.returnTrue; + + + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.isRgbColor = function() { + return this._isRgbColor; +} + +qx.Proto.isHtmlColor = function() { + return this._isHtmlColor; +} + +qx.Proto.isThemedColor = function() { + return this._isThemedColor; +} + + + + +qx.Proto.setValue = function(vValue) +{ + this._normalize(vValue); + + if (this._isThemedColor) { + throw new Error("Please use qx.renderer.color.ColorObject for themed colors!"); + } +} + +qx.Proto.getValue = function() { + return this._value || ""; +} + + + + +qx.Proto.getStyle = function() +{ + if (this._style == null) { + this._evalStyle(); + } + + return this._style; +} + +qx.Proto._evalStyle = function() +{ + if (this._isRgbColor) + { + this._style = qx.renderer.color.Color.rgb2style(this._red, this._green, this._blue); + } + else if (this._isThemedColor) + { + this._applyThemedValue(); + } + else if (this._isHtmlColor) + { + this._style = this._value; + } + else if (this._value != null) + { + this.error("Could not handle non-rgb colors :" + this.getValue() + "!"); + } +} + + + + +qx.Proto.getHex = function() +{ + if (this._hex == null) { + this._evalHex(); + } + + return this._hex; +} + +qx.Proto._evalHex = function() +{ + if (this._isRgbColor) + { + var a = ["#"]; + + var r = this.getRed(); + a.push(qx.renderer.color.Color.m_hex[Math.floor(r/16)]); + a.push(qx.renderer.color.Color.m_hex[Math.floor(r%16)]); + + var g = this.getGreen(); + a.push(qx.renderer.color.Color.m_hex[Math.floor(g/16)]); + a.push(qx.renderer.color.Color.m_hex[Math.floor(g%16)]); + + var b = this.getBlue(); + a.push(qx.renderer.color.Color.m_hex[Math.floor(b/16)]); + a.push(qx.renderer.color.Color.m_hex[Math.floor(b%16)]); + + this._hex = a.join(""); + } + else + { + // TODO + } +} + + + + +qx.Proto.getRed = function() +{ + if (this._red == null) { + this._evalRgb(); + } + + return this._red; +} + +qx.Proto.getGreen = function() +{ + if (this._green == null) { + this._evalRgb(); + } + + return this._green; +} + +qx.Proto.getBlue = function() +{ + if (this._blue == null) { + this._evalRgb(); + } + + return this._blue; +} + + + + +qx.Proto._evalRgb = function() +{ + if (this._isThemedColor) + { + this._applyThemedValue(); + } + else if (this._isHtmlColor) + { + var a = qx.renderer.color.Color.htmlNames[this._value]; + + this._red = a[0]; + this._green = a[1]; + this._blue = a[2]; + } + else + { + throw new Error("_evalRgb needs implementation!"); + } +} + + + + + +/* +--------------------------------------------------------------------------- + PRIVATE METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto._normalize = function(vInValue) +{ + this._isThemedColor = this._isRgbColor = this._isHtmlColor = false; + this._hex = null; + + var invalid = new Error("Invalid color: " + vInValue); + + switch(typeof vInValue) + { + case "string": + vInValue = vInValue.toLowerCase(); + + if (qx.renderer.color.Color.htmlNames[vInValue]) + { + this._isHtmlColor = true; + } + else if (qx.renderer.color.Color.themedNames[vInValue]) + { + this._isThemedColor = true; + } + else if (qx.renderer.color.Color.r_cssrgb.test(vInValue)) + { + this._red = parseInt(RegExp.$1); + this._green = parseInt(RegExp.$2); + this._blue = parseInt(RegExp.$3); + + this._isRgbColor = true; + } + else if (qx.renderer.color.Color.r_hex3.test(vInValue)) + { + this._hex = vInValue; + + this._red = (qx.renderer.color.Color.m_rgb[RegExp.$1] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$1]; + this._green = (qx.renderer.color.Color.m_rgb[RegExp.$2] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$2]; + this._blue = (qx.renderer.color.Color.m_rgb[RegExp.$3] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$3]; + + this._isRgbColor = true; + } + else if (qx.renderer.color.Color.r_hex6.test(vInValue)) + { + this._hex = vInValue; + + this._red = (qx.renderer.color.Color.m_rgb[RegExp.$1] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$2]; + this._green = (qx.renderer.color.Color.m_rgb[RegExp.$3] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$4]; + this._blue = (qx.renderer.color.Color.m_rgb[RegExp.$5] * 16) + qx.renderer.color.Color.m_rgb[RegExp.$6]; + + this._isRgbColor = true; + } + else + { + throw invalid; + } + + break; + + case "number": + if (vInValue >= 0 && vInValue <= 255) + { + this._red = this._green = this._blue = vInValue; + this._isRgbColor = true; + } + else + { + throw invalid; + } + + break; + + case "object": + if (qx.util.Validation.isValidArray(vInValue) && vInValue.length == 3) + { + this._red = vInValue[0]; + this._green = vInValue[1]; + this._blue = vInValue[2]; + + this._isRgbColor = true; + break; + } + + default: + throw invalid; + } + + if (!this._isRgbColor) + { + this._red = this._green = this._blue = null; + this._style = this._isHtmlColor ? vInValue : null; + } + else + { + this._style = null; + + if (!(this._red >= 0 && this._red <= 255 && this._green >= 0 && this._green <= 255 && this._blue >= 0 && this._blue <= 255)) { + throw invalid; + } + } + + return this._value = vInValue; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + delete this._value; + delete this._style; + + delete this._red; + delete this._green; + delete this._blue; + + delete this._isRgbColor; + delete this._isHtmlColor; + delete this._isThemedColor; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorCache.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorCache.js new file mode 100644 index 0000000000..0ae7e91869 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorCache.js @@ -0,0 +1,85 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.color.ColorCache"); + +qx.renderer.color.ColorCache = function(propValue) +{ + var propKey; + var propKeyAsStyle = false; + + switch(typeof propValue) + { + case "string": + if (propValue != "") { + propValue = propKey = propValue.toLowerCase(); + break; + } + + return propValue; + + case "number": + if (propValue >= 0 && propValue <= 255) + { + propKey = propValue.toString(); + break; + } + + return propValue; + + case "object": + if (propValue == null || propValue instanceof qx.renderer.color.Color) { + return propValue; + } + + // Try to detect array of RGB values + if (typeof propValue.join === "function" && propValue.length == 3) + { + propKey = "rgb(" + propValue.join(",") + ")"; + propKeyAsStyle = true; + break; + } + + default: + return propValue; + } + + if (qx.renderer.color.ColorCache._data[propKey]) { + return qx.renderer.color.ColorCache._data[propKey]; + } + + // this.debug("Create new color instance: " + propKey); + + var vColorObject = qx.renderer.color.ColorCache._data[propKey] = qx.renderer.color.Color.themedNames[propValue] ? new qx.renderer.color.ColorObject(propValue) : new qx.renderer.color.Color(propValue); + + if (propKeyAsStyle) { + vColorObject._style = propKey; + } + + return vColorObject; +} + +qx.renderer.color.ColorCache._data = {}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorObject.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorObject.js new file mode 100644 index 0000000000..353c87c59e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/color/ColorObject.js @@ -0,0 +1,156 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.color.ColorObject", qx.renderer.color.Color, +function(vValue) +{ + // this.debug("Value: " + vValue); + this.setValue(vValue); + + if(qx.manager.object.ColorManager.getInstance().has(this._value)) { + return qx.manager.object.ColorManager.getInstance().get(this._value); + } + + qx.core.Object.call(this); + + // Register this color object to manager instance + qx.manager.object.ColorManager.getInstance().add(this); + + // Here will all objects with a dependency to this + // color stored. + this._dependentObjects = {}; +}); + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.renderer.color.ColorObject.fromString = function(vDefString) { + return new qx.renderer.color.ColorObject(vDefString); +} + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS +--------------------------------------------------------------------------- +*/ + +/*! + Set a new value from selected theme (only for Operating System Colors) +*/ +qx.Proto._updateTheme = function(vTheme) +{ + if (!this._isThemedColor) { + throw new Error("Could not redefine themed value of non os colors!"); + } + + this._applyThemedValue(); + this._syncObjects(); +} + +qx.Proto._applyThemedValue = function() +{ + var vTheme = qx.manager.object.ColorManager.getInstance().getColorTheme(); + var vRgb = vTheme.getValueByName(this._value); + + if (vRgb) + { + this._red = vRgb[0]; + this._green = vRgb[1]; + this._blue = vRgb[2]; + } + + this._style = vTheme.getStyleByName(this._value); + this._hex = null; +} + +qx.Proto._syncObjects = function() +{ + for (var i in this._dependentObjects) { + this._dependentObjects[i]._updateColors(this, this._style); + } +} + +qx.Proto.setValue = function(vValue) +{ + this._normalize(vValue); + this._syncObjects(); +} + + + + + +/* +--------------------------------------------------------------------------- + OBJECT MANAGMENT +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(vObject) { + this._dependentObjects[vObject.toHashCode()] = vObject; +} + +qx.Proto.remove = function(vObject) { + delete this._dependentObjects[vObject.toHashCode()]; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._dependentObjects) + { + for (var i in this._dependentObjects) { + delete this._dependentObjects[i]; + } + + delete this._dependentObjects; + } + + return qx.renderer.color.Color.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/Font.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/Font.js new file mode 100644 index 0000000000..816ca7639e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/Font.js @@ -0,0 +1,220 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#load(qx.renderer.font.FontObject) + +************************************************************************ */ + +/*! + Font implementation for qx.ui.core.Widget instances. +*/ + +qx.OO.defineClass("qx.renderer.font.Font", qx.core.Object, +function(vSize, vName) +{ + qx.core.Object.call(this); + + this._defs = {}; + + if (vSize != null) { + this.setSize(vSize); + } + + if (vName != null) { + this.setName(vName); + } +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "size", type : "number", impl : "style" }); +qx.OO.addProperty({ name : "name", type : "string", impl : "style" }); +qx.OO.addProperty({ name : "bold", type : "boolean", defaultValue : false, impl : "style" }); +qx.OO.addProperty({ name : "italic", type : "boolean", defaultValue : false, impl : "style" }); +qx.OO.addProperty({ name : "underline", type : "boolean", defaultValue : false, impl : "style" }); +qx.OO.addProperty({ name : "strikeout", type : "boolean", defaultValue : false, impl : "style" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyStyle = function(propValue, propOldValue, propData) +{ + this._needsCompilation = true; + return true; +} + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.renderer.font.Font.fromString = function(s) +{ + var vFont = new qx.renderer.font.Font; + var vAllParts = s.split(/\s+/); + var vName = []; + var vPart; + + for (var i = 0; i < vAllParts.length; i++) + { + switch(vPart = vAllParts[i]) + { + case "bold": + vFont.setBold(true); + break; + + case "italic": + vFont.setItalic(true); + break; + + case "underline": + vFont.setUnderline(true); + break; + + case "strikeout": + vFont.setStrikeout(true); + break; + + default: + var vTemp = parseFloat(vPart); + + if(vTemp == vPart || qx.lang.String.contains(vPart, "px")) + { + vFont.setSize(vTemp); + } + else + { + vName.push(vPart); + } + + break; + } + } + + if(vName.length > 0) { + vFont.setName(vName.join(" ")); + } + + return vFont; +} + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto._needsCompilation = true; + +qx.Proto._compile = function() +{ + var vName = this.getName(); + var vSize = this.getSize(); + var vBold = this.getBold(); + var vItalic = this.getItalic(); + var vUnderline = this.getUnderline(); + var vStrikeout = this.getStrikeout(); + var vDecoration = ""; + + if (this.getUnderline()) { + vDecoration = "underline"; + } + + if (this.getStrikeout()) { + vDecoration += " " + "strikeout"; + } + + this._defs.fontFamily = vName || ""; + this._defs.fontSize = typeof vSize == "number" ? vSize + "px" : ""; + this._defs.fontWeight = this.getBold() ? "bold" : "normal"; + this._defs.fontStyle = this.getItalic() ? "italic" : "normal"; + this._defs.textDecoration = vDecoration || ""; + + this._needsCompilation = false; +} + +qx.Proto._applyWidget = function(vWidget) +{ + if (this._needsCompilation) { + this._compile(); + } + + vWidget.setStyleProperty("fontFamily", this._defs.fontFamily); + vWidget.setStyleProperty("fontSize", this._defs.fontSize); + vWidget.setStyleProperty("fontWeight", this._defs.fontWeight); + vWidget.setStyleProperty("fontStyle", this._defs.fontStyle); + vWidget.setStyleProperty("textDecoration", this._defs.textDecoration); +} + +qx.Proto._resetWidget = function(vWidget) +{ + vWidget.removeStyleProperty("fontFamily"); + vWidget.removeStyleProperty("fontSize"); + vWidget.removeStyleProperty("fontWeight"); + vWidget.removeStyleProperty("fontStyle"); + vWidget.removeStyleProperty("textDecoration"); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + delete this._defs; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontCache.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontCache.js new file mode 100644 index 0000000000..c7344803c3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontCache.js @@ -0,0 +1,72 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.font.FontCache"); + +qx.renderer.font.FontCache = function(propValue, propData) +{ + var propKey; + var propKeyAsStyle = false; + + switch(typeof propValue) + { + case "string": + if (propValue != "") + { + propValue = propKey = propValue.toLowerCase(); + break; + } + + return propValue; + + case "number": + propKey = propValue.toString(); + break; + + case "object": + if (propValue == null || propValue instanceof qx.renderer.font.Font) { + return propValue; + } + + // Try to detect array of RGB values + if (typeof propValue.join === "function") + { + propKey = propValue.join(" ").toLowerCase(); + break; + } + + default: + return propValue; + } + + if (qx.renderer.font.FontCache._data[propKey]) { + return qx.renderer.font.FontCache._data[propKey]; + } + + return qx.renderer.font.FontCache._data[propKey] = qx.renderer.font.Font.fromString(propKey); +} + +qx.renderer.font.FontCache._data = {}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontObject.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontObject.js new file mode 100644 index 0000000000..d9ff4bbbe5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/font/FontObject.js @@ -0,0 +1,95 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.font.FontObject", qx.renderer.font.Font, +function(vSize, vName) +{ + this._dependentObjects = {}; + + qx.renderer.font.Font.call(this, vSize, vName); +}); + + + + +/* +--------------------------------------------------------------------------- + WIDGET CONNECTION +--------------------------------------------------------------------------- +*/ + +qx.Proto.addListenerWidget = function(o) { + this._dependentObjects[o.toHashCode()] = o; +} + +qx.Proto.removeListenerWidget = function(o) { + delete this._dependentObjects[o.toHashCode()]; +} + +qx.Proto._sync = function(vEdge) +{ + var vAll = this._dependentObjects; + var vCurrent; + + for (vKey in vAll) + { + vCurrent = vAll[vKey]; + + if (vCurrent.isCreated()) { + vCurrent._updateFont(vEdge); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (typeof this._dependentObjects === "object") + { + for (vKey in this._dependentObjects) { + delete this._dependentObjects[vKey]; + } + + delete this._dependentObjects; + } + + return qx.renderer.font.Font.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/CanvasLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/CanvasLayoutImpl.js new file mode 100644 index 0000000000..aec420dac6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/CanvasLayoutImpl.js @@ -0,0 +1,299 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.CanvasLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + + + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.LayoutImpl: + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [11] DISPOSER +*/ + + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the box width of the given child +*/ +qx.Proto.computeChildBoxWidth = function(vChild) +{ + var vValue = null; + + if (vChild._computedLeftTypeNull || vChild._computedRightTypeNull) + { + vValue = vChild.getWidthValue(); + } + else if (vChild._hasParent) + { + vValue = this.getWidget().getInnerWidth() - vChild.getLeftValue() - vChild.getRightValue(); + } + + return vValue || vChild._computeBoxWidthFallback(); +} + +/*! + Compute and return the box height of the given child +*/ +qx.Proto.computeChildBoxHeight = function(vChild) +{ + var vValue = null; + + if (vChild._computedTopTypeNull || vChild._computedBottomTypeNull) + { + vValue = vChild.getHeightValue(); + } + else if (vChild._hasParent) + { + vValue = this.getWidget().getInnerHeight() - vChild.getTopValue() - vChild.getBottomValue(); + } + + return vValue || vChild._computeBoxHeightFallback(); +} + + + + + +/* +--------------------------------------------------------------------------- + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the needed width of the given child +*/ +qx.Proto.computeChildNeededWidth = function(vChild) +{ + var vLeft = vChild._computedLeftTypePercent ? null : vChild.getLeftValue(); + var vRight = vChild._computedRightTypePercent ? null : vChild.getRightValue(); + var vMinBox = vChild._computedMinWidthTypePercent ? null : vChild.getMinWidthValue(); + var vMaxBox = vChild._computedMaxWidthTypePercent ? null : vChild.getMaxWidthValue(); + + if (vLeft != null && vRight != null) + { + var vBox = vChild.getPreferredBoxWidth() || 0; + } + else + { + var vBox = (vChild._computedWidthTypePercent ? null : vChild.getWidthValue()) || vChild.getPreferredBoxWidth() || 0; + } + + return qx.lang.Number.limit(vBox, vMinBox, vMaxBox) + vLeft + vRight + vChild.getMarginLeft() + vChild.getMarginRight(); +} + +/*! + Compute and return the needed height of the given child +*/ +qx.Proto.computeChildNeededHeight = function(vChild) +{ + var vTop = vChild._computedTopTypePercent ? null : vChild.getTopValue(); + var vBottom = vChild._computedBottomTypePercent ? null : vChild.getBottomValue(); + var vMinBox = vChild._computedMinHeightTypePercent ? null : vChild.getMinHeightValue(); + var vMaxBox = vChild._computedMaxHeightTypePercent ? null : vChild.getMaxHeightValue(); + + if (vTop != null && vBottom != null) + { + var vBox = vChild.getPreferredBoxHeight() || 0; + } + else + { + var vBox = (vChild._computedHeightTypePercent ? null : vChild.getHeightValue()) || vChild.getPreferredBoxHeight() || 0; + } + + return qx.lang.Number.limit(vBox, vMinBox, vMaxBox) + vTop + vBottom + vChild.getMarginTop() + vChild.getMarginBottom(); +} + + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + // this makes sure that both functions get executed before return + var vUpdatePercent = vChild._recomputePercentX(); + var vUpdateRange = vChild._recomputeRangeX(); + + return vUpdatePercent || vUpdateRange; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + // this makes sure that both functions get executed before return + var vUpdatePercent = vChild._recomputePercentY(); + var vUpdateRange = vChild._recomputeRangeY(); + + return vUpdatePercent || vUpdateRange; +} + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/*! + This is called from qx.ui.core.Widget and it's task is to apply the layout + (excluding border and padding) to the child. +*/ +qx.Proto.layoutChild = function(vChild, vJobs) +{ + this.layoutChild_sizeX_essentialWrapper(vChild, vJobs); + this.layoutChild_sizeY_essentialWrapper(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this.layoutChild_locationX(vChild, vJobs); + this.layoutChild_locationY(vChild, vJobs); + + this.layoutChild_marginX(vChild, vJobs); + this.layoutChild_marginY(vChild, vJobs); +} + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera()) +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth || vJobs.left || vJobs.right) + { + if (vChild._computedMinWidthTypeNull && vChild._computedWidthTypeNull && vChild._computedMaxWidthTypeNull && !(!vChild._computedLeftTypeNull && !vChild._computedRightTypeNull)) + { + vChild._resetRuntimeWidth(); + } + else + { + vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight || vJobs.top || vJobs.bottom) + { + if (vChild._computedMinHeightTypeNull && vChild._computedHeightTypeNull && vChild._computedMaxHeightTypeNull && !(!vChild._computedTopTypeNull && !vChild._computedBottomTypeNull)) + { + vChild._resetRuntimeHeight(); + } + else + { + vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + } + } +} +else +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width) { + vChild._computedWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getWidthValue()); + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height) { + vChild._computedHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getHeightValue()); + } + } +} + +qx.Proto.layoutChild_locationX = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + if (vJobs.initial || vJobs.left || vJobs.parentPaddingLeft) { + vChild._computedLeftTypeNull ? vChild._computedRightTypeNull && vWidget.getPaddingLeft() > 0 ? vChild._applyRuntimeLeft(vWidget.getPaddingLeft()) : vChild._resetRuntimeLeft() : vChild._applyRuntimeLeft(vChild.getLeftValue() + vWidget.getPaddingLeft()); + } + + if (vJobs.initial || vJobs.right || vJobs.parentPaddingRight) { + vChild._computedRightTypeNull ? vChild._computedLeftTypeNull && vWidget.getPaddingRight() > 0 ? vChild._applyRuntimeRight(vWidget.getPaddingRight()) : vChild._resetRuntimeRight() : vChild._applyRuntimeRight(vChild.getRightValue() + vWidget.getPaddingRight()); + } +} + +qx.Proto.layoutChild_locationY = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + if (vJobs.initial || vJobs.top || vJobs.parentPaddingTop) { + vChild._computedTopTypeNull ? vChild._computedBottomTypeNull && vWidget.getPaddingTop() > 0 ? vChild._applyRuntimeTop(vWidget.getPaddingTop()) : vChild._resetRuntimeTop() : vChild._applyRuntimeTop(vChild.getTopValue() + vWidget.getPaddingTop()); + } + + if (vJobs.initial || vJobs.bottom || vJobs.parentPaddingBottom) { + vChild._computedBottomTypeNull ? vChild._computedTopTypeNull && vWidget.getPaddingBottom() > 0 ? vChild._applyRuntimeBottom(vWidget.getPaddingBottom()) : vChild._resetRuntimeBottom() : vChild._applyRuntimeBottom(vChild.getBottomValue() + vWidget.getPaddingBottom()); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/DockLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/DockLayoutImpl.js new file mode 100644 index 0000000000..4c77209f50 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/DockLayoutImpl.js @@ -0,0 +1,490 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.DockLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.LayoutImpl: + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [11] DISPOSER +*/ + + + + +/* +--------------------------------------------------------------------------- + [00] ADDITIONAL GLOBAL DATA AND METHODS +--------------------------------------------------------------------------- +*/ + +qx.renderer.layout.DockLayoutImpl.METHOD_LOCATION = "layoutChild_location_"; + +qx.renderer.layout.DockLayoutImpl._childRanking = { + vertical : function(c) { return c.getVerticalAlign() ? 1e6 : c.getHorizontalAlign() ? 2e6 : 3e6; }, + horizontal : function(c) { return c.getHorizontalAlign() ? 1e6 : c.getVerticalAlign() ? 2e6 : 3e6; }, + ordered : function(c) { return c.getHorizontalAlign() || c.getVerticalAlign() ? 1e6 : 2e6; } +} + +qx.renderer.layout.DockLayoutImpl._childCheck = +{ + common : function(vChild) { + if (!(vChild._computedLeftTypeNull && vChild._computedRightTypeNull && vChild._computedTopTypeNull && vChild._computedBottomTypeNull)) { + throw new Error("qx.renderer.layout.DockLayoutImpl: It is not allowed to define any location values for children: " + vChild + "!"); + } + }, + + horizontal : function(vChild) + { + if (!(vChild._computedMinHeightTypeNull && vChild._computedHeightTypeNull && vChild._computedMaxHeightTypeNull)) { + throw new Error("qx.renderer.layout.DockLayoutImpl: It is not allowed to define any vertical dimension for 'horizontal' placed children: " + vChild + "!"); + } + }, + + vertical : function(vChild) + { + if (!(vChild._computedMinWidthTypeNull && vChild._computedWidthTypeNull && vChild._computedMaxWidthTypeNull)) { + throw new Error("qx.renderer.layout.DockLayoutImpl: It is not allowed to define any horizontal dimension for 'vertical' placed children: " + vChild + "!"); + } + }, + + "default" : function(vChild) + { + qx.renderer.layout.DockLayoutImpl._childCheck.horizontal(vChild); + qx.renderer.layout.DockLayoutImpl._childCheck.vertical(vChild); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the box width of the given child +*/ +qx.Proto.computeChildBoxWidth = function(vChild) +{ + if (this.getChildAlignMode(vChild) == "horizontal") { + return vChild.getWidthValue() || vChild._computeBoxWidthFallback(); + } + + return this.getWidget().getInnerWidth() - this._lastLeft - this._lastRight; +} + +/*! + Compute and return the box height of the given child +*/ +qx.Proto.computeChildBoxHeight = function(vChild) +{ + if (this.getChildAlignMode(vChild) == "vertical") { + return vChild.getHeightValue() || vChild._computeBoxHeightFallback(); + } + + return this.getWidget().getInnerHeight() - this._lastTop - this._lastBottom; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + vChild._recomputePercentX(); + vChild.addToLayoutChanges("location"); + + // inform the caller if there were any notable changes occured + return true; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + vChild._recomputePercentY(); + vChild.addToLayoutChanges("location"); + + // inform the caller if there were any notable changes occured + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Invalidate and recompute things because of job in queue (before the rest of job handling will be executed). +*/ +qx.Proto.updateSelfOnJobQueueFlush = qx.lang.Function.returnFalse; + + + + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Updates children on special jobs +*/ +qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue) +{ + if (vQueue.mode || vQueue.addChild || vQueue.removeChild) { + this.getWidget()._addChildrenToLayoutQueue("location"); + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + [09] FLUSH LAYOUT QUEUES OF CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + This method have full control of the order in which the + registered (or also non-registered) children should be + layouted on the horizontal axis. +*/ +qx.Proto.flushChildrenQueue = function(vChildrenQueue) +{ + var vWidget=this.getWidget(), vChildren=vWidget.getVisibleChildren(), vChildrenLength=vChildren.length, vMode=vWidget.getMode(); + + // reset layout + this._lastLeft = this._lastRight = this._lastTop = this._lastBottom = 0; + + // sorting children + var vRankImpl = qx.renderer.layout.DockLayoutImpl._childRanking[vMode]; + var vOrderedChildren = qx.lang.Array.copy(vChildren).sort(function(c1, c2) { + return (vRankImpl(c1) + vChildren.indexOf(c1)) - (vRankImpl(c2) + vChildren.indexOf(c2)); + }); + + // flushing children + for (var i=0; i<vChildrenLength; i++) { + vWidget._layoutChild(vOrderedChildren[i]); + } +} + +qx.Proto.getChildAlign = function(vChild) { + return vChild.getVerticalAlign() || vChild.getHorizontalAlign() || "default"; +} + +qx.Proto.getChildAlignMode = function(vChild) { + return vChild.getVerticalAlign() ? "vertical" : vChild.getHorizontalAlign() ? "horizontal" : "default"; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/*! + This is called from qx.ui.core.Widget and it's task is to apply the layout + (excluding border and padding) to the child. +*/ +qx.Proto.layoutChild = function(vChild, vJobs) +{ + qx.renderer.layout.DockLayoutImpl._childCheck.common(vChild); + qx.renderer.layout.DockLayoutImpl._childCheck[this.getChildAlignMode(vChild)](vChild); + + this.layoutChild_sizeX_essentialWrapper(vChild, vJobs); + this.layoutChild_sizeY_essentialWrapper(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this[qx.renderer.layout.DockLayoutImpl.METHOD_LOCATION + this.getChildAlign(vChild)](vChild, vJobs); +} + +qx.Proto.layoutChild_location_top = function(vChild, vJobs) +{ + vChild._applyRuntimeTop(this._lastTop); + vChild._applyRuntimeLeft(this._lastLeft); + + this.layoutChild_location_horizontal(vChild); + + this._lastTop += vChild.getBoxHeight(); +} + +qx.Proto.layoutChild_location_left = function(vChild, vJobs) +{ + vChild._applyRuntimeLeft(this._lastLeft); + vChild._applyRuntimeTop(this._lastTop); + + this.layoutChild_location_vertical(vChild); + + this._lastLeft += vChild.getBoxWidth(); +} + + + + + + + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._applyComputedWidth = function(vChild) + { + // direct recompute (need to be done, while layouting as the + // _last* variable changes during layout process) + vChild._recomputeBoxWidth(); + + // wrong: simple invalidates are enough here + // correct: needs recompute to inform children (to update centering for example) + vChild._recomputeOuterWidth(); + vChild._recomputeInnerWidth(); + + // apply calculated width + vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + + qx.Proto._applyComputedHeight = function(vChild) + { + // direct recompute (need to be done, while layouting as the + // _last* variable changes during layout process) + vChild._recomputeBoxHeight(); + + // wrong: simple invalidates are enough here + // correct: needs recompute to inform children (to update centering for example) + vChild._recomputeOuterHeight(); + vChild._recomputeInnerHeight(); + + // apply calculated height + vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + // We need to respect all dimension properties on the horizontal axis in internet explorer to set the 'width' style + if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth) { + vChild._computedWidthTypeNull && vChild._computedMinWidthTypeNull && vChild._computedMaxWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + // We need to respect all dimension properties on the vertical axis in internet explorer to set the 'height' style + if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight) { + vChild._computedHeightTypeNull && vChild._computedMinHeightTypeNull && vChild._computedMaxHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + } + + qx.Proto.layoutChild_location_horizontal = function(vChild) { + this._applyComputedWidth(vChild); + } + + qx.Proto.layoutChild_location_vertical = function(vChild) { + this._applyComputedHeight(vChild); + } + + qx.Proto.layoutChild_location_right = function(vChild, vJobs) + { + vChild._applyRuntimeLeft(this.getWidget().getInnerWidth() - this._lastRight - vChild.getBoxWidth()); + vChild._applyRuntimeTop(this._lastTop); + + this.layoutChild_location_vertical(vChild); + + this._lastRight += vChild.getBoxWidth(); + } + + qx.Proto.layoutChild_location_bottom = function(vChild, vJobs) + { + vChild._applyRuntimeTop(this.getWidget().getInnerHeight() - this._lastBottom - vChild.getBoxHeight()); + vChild._applyRuntimeLeft(this._lastLeft); + + this.layoutChild_location_horizontal(vChild); + + this._lastBottom += vChild.getBoxHeight(); + } + + qx.Proto.layoutChild_location_default = function(vChild, vJobs) + { + var vWidget = this.getWidget(); + + vChild._resetRuntimeRight(); + vChild._resetRuntimeBottom(); + + vChild._applyRuntimeTop(this._lastTop); + vChild._applyRuntimeLeft(this._lastLeft); + + this._applyComputedWidth(vChild); + this._applyComputedHeight(vChild); + } +} +else +{ + qx.Proto._applyComputedWidth = function(vChild) + { + // direct recompute (need to be done, while layouting as the + // _last* variable changes during layout process) + vChild._recomputeBoxWidth(); + + // wrong: simple invalidates are enough here + // correct: needs recompute to inform children (to update centering for example) + vChild._recomputeOuterWidth(); + vChild._recomputeInnerWidth(); + } + + qx.Proto._applyComputedHeight = function(vChild) + { + // direct recompute (need to be done, while layouting as the + // _last* variable changes during layout process) + vChild._recomputeBoxHeight(); + + // wrong: simple invalidates are enough here + // correct: needs recompute to inform children (to update centering for example) + vChild._recomputeOuterHeight(); + vChild._recomputeInnerHeight(); + } + + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width) { + vChild._computedWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getWidthValue()); + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height) { + vChild._computedHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getHeightValue()); + } + } + + qx.Proto.layoutChild_location_horizontal = function(vChild) + { + this._applyComputedWidth(vChild); + vChild._applyRuntimeRight(this._lastRight); + } + + qx.Proto.layoutChild_location_vertical = function(vChild) + { + this._applyComputedHeight(vChild); + vChild._applyRuntimeBottom(this._lastBottom); + } + + qx.Proto.layoutChild_location_right = function(vChild, vJobs) + { + vChild._applyRuntimeRight(this._lastRight); + vChild._applyRuntimeTop(this._lastTop); + + this.layoutChild_location_vertical(vChild); + + this._lastRight += vChild.getBoxWidth(); + } + + qx.Proto.layoutChild_location_bottom = function(vChild, vJobs) + { + vChild._applyRuntimeBottom(this._lastBottom); + vChild._applyRuntimeLeft(this._lastLeft); + + this.layoutChild_location_horizontal(vChild); + + this._lastBottom += vChild.getBoxHeight(); + } + + qx.Proto.layoutChild_location_default = function(vChild, vJobs) + { + vChild._resetRuntimeWidth(); + vChild._resetRuntimeHeight(); + + vChild._applyRuntimeTop(this._lastTop); + vChild._applyRuntimeRight(this._lastRight); + vChild._applyRuntimeBottom(this._lastBottom); + vChild._applyRuntimeLeft(this._lastLeft); + + this._applyComputedWidth(vChild); + this._applyComputedHeight(vChild); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/FlowLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/FlowLayoutImpl.js new file mode 100644 index 0000000000..153356d3bb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/FlowLayoutImpl.js @@ -0,0 +1,428 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.FlowLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + +qx.renderer.layout.FlowLayoutImpl.STR_FIRST = "getFirstVisibleChild"; +qx.renderer.layout.FlowLayoutImpl.STR_LAST = "getLastVisibleChild"; +qx.renderer.layout.FlowLayoutImpl.STR_NEXT = "getNextSibling"; +qx.renderer.layout.FlowLayoutImpl.STR_PREVIOUS = "getPreviousSibling"; + + +/*! + Global Structure: + + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + Inherits from qx.renderer.layout.LayoutImpl: + + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [11] DISPOSER +*/ + + + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the width needed by all children of this widget +*/ +qx.Proto.computeChildrenNeededWidth = function() +{ + var w = this.getWidget(); + return qx.renderer.layout.LayoutImpl.prototype.computeChildrenNeededWidth_sum.call(this) + ((w.getVisibleChildrenLength()-1) * w.getHorizontalSpacing()); +} + +/*! + Calculate the layout to get the needed height of the children +*/ +qx.Proto.computeChildrenNeededHeight = function() +{ + var vWidget = this.getWidget(); + + var vInnerWidth = vWidget.getInnerWidth(); + + var vHorizontalSpacing = vWidget.getHorizontalSpacing(); + var vVerticalSpacing = vWidget.getVerticalSpacing(); + var vReversed = vWidget.getReverseChildrenOrder(); + + var vRowWidth = 0; + var vRowHeight = 0; + + var vRowHeightSum = 0; + + for (var i=0, ch=vWidget.getVisibleChildren(), chl=ch.length, chc; i<chl; i++) + { + chc = vReversed ? ch[chl-1-i] : ch[i]; + + vRowWidth += chc.getNeededWidth(); + + if (vRowWidth > vInnerWidth) + { + vRowHeightSum += vRowHeight + vVerticalSpacing; + vRowWidth = chc.getNeededWidth(); + vRowHeight = chc.getNeededHeight(); + } + else + { + vRowHeight = Math.max(vRowHeight, chc.getNeededHeight()); + } + + vRowWidth += vHorizontalSpacing; + } + + return vRowHeightSum + vRowHeight; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS +--------------------------------------------------------------------------- +*/ + +/*! + Things to do and layout when any of the childs changes it's outer width. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateSelfOnChildOuterWidthChange = function(vChild) +{ + // If a child only change it's width also recompute the height + // as the layout flows around here + //this.getWidget()._recomputeNeededHeightHelper(); + this.getWidget()._invalidatePreferredInnerHeight(); +} + + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + vChild._recomputePercentX(); + vChild.addToLayoutChanges("location"); + + return true; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + vChild._recomputePercentY(); + vChild.addToLayoutChanges("location"); + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Updates children on special jobs +*/ +qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue) +{ + if (vQueue.horizontalSpacing || vQueue.verticalSpacing || vQueue.reverseChildrenOrder || vQueue.horizontalChildrenAlign || vQueue.verticalChildrenAlign) { + this.getWidget()._addChildrenToLayoutQueue("location"); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [08] CHILDREN ADD/REMOVE/MOVE HANDLING +--------------------------------------------------------------------------- +*/ + +/*! + This method combines calls of methods which should be done if a widget should be removed from the current layout. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnRemoveChild = function(vChild, vIndex) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i=-1; + + if (w.getReverseChildrenOrder()) + { + while((chc=ch[++i]) && i<vIndex) { + chc.addToLayoutChanges("location"); + } + } + else + { + i+=vIndex; + while(chc=ch[++i]) { + chc.addToLayoutChanges("location"); + } + } +} + +/*! + This method combines calls of methods which should be done if a child should be moved + inside the same parent to a new positions. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnMoveChild = function(vChild, vIndex, vOldIndex) +{ + for (var i=Math.min(vIndex, vOldIndex), ch=this.getWidget().getVisibleChildren(), l=ch.length; i<l; i++) { + ch[i].addToLayoutChanges("location"); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [09] FLUSH LAYOUT QUEUES OF CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + This method have full control of the order in which the + registered (or also non-registered) children should be + layouted on the horizontal axis. +*/ + +qx.Proto.flushChildrenQueue = function(vChildrenQueue) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, chh; + + if (w.getReverseChildrenOrder()) + { + // layout all childs from the first child + // with an own layout request to the end + var i=chl, changed=false; + while(chc=ch[--i]) + { + chh = chc.toHashCode(); + + if (changed || vChildrenQueue[chh]) + { + w._layoutChild(chc); + changed = true; + } + } + } + else + { + // layout all childs from the first child + // with an own layout request to the end + var i=-1, changed=false; + while(chc=ch[++i]) + { + chh = chc.toHashCode(); + + if (changed || vChildrenQueue[chh]) + { + w._layoutChild(chc); + changed = true; + } + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +qx.Proto.layoutChild = function(vChild, vJobs) +{ + this.layoutChild_sizeX_essentialWrapper(vChild, vJobs); + this.layoutChild_sizeY_essentialWrapper(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this.layoutChild_marginX(vChild, vJobs); + this.layoutChild_marginY(vChild, vJobs); + + this.layoutChild_location(vChild, vJobs); +} + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera()) +{ + /*! + We need to respect all dimension properties on the horizontal axis in + internet explorer to set the 'width' style + */ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth) { + vChild._computedWidthTypeNull && vChild._computedMinWidthTypeNull && vChild._computedMaxWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + } + + /*! + We need to respect all dimension properties on the vertical axis in + internet explorer to set the 'height' style + */ + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight) { + vChild._computedHeightTypeNull && vChild._computedMinHeightTypeNull && vChild._computedMaxHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + } +} +else +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width) { + vChild._computedWidthTypeNull ? vChild._resetRuntimeWidth() : vChild._applyRuntimeWidth(vChild.getWidthValue()); + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height) { + vChild._computedHeightTypeNull ? vChild._resetRuntimeHeight() : vChild._applyRuntimeHeight(vChild.getHeightValue()); + } + } +} + +qx.Proto.layoutChild_location = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + var vReverse = vWidget.getReverseChildrenOrder(); + + var vMethodBegin = vReverse ? qx.renderer.layout.FlowLayoutImpl.STR_LAST : qx.renderer.layout.FlowLayoutImpl.STR_FIRST; + var vMethodContinue = vReverse ? qx.renderer.layout.FlowLayoutImpl.STR_NEXT : qx.renderer.layout.FlowLayoutImpl.STR_PREVIOUS; + + if (vChild == vWidget[vMethodBegin]()) + { + vChild._cachedLocationHorizontal = vChild._cachedLocationVertical = vChild._cachedRow = 0; + } + else + { + var vTempChild = vChild[vMethodContinue](); + + // stupidly update cache value (check them later) + vChild._cachedLocationHorizontal = vTempChild._cachedLocationHorizontal + vTempChild.getOuterWidth() + vWidget.getHorizontalSpacing(); + vChild._cachedLocationVertical = vTempChild._cachedLocationVertical; + vChild._cachedRow = vTempChild._cachedRow; + + // check now + if ((vChild._cachedLocationHorizontal + vChild.getOuterWidth()) > vWidget.getInnerWidth()) + { + // evaluate width of previous row + vRowMax = vTempChild.getOuterHeight(); + while((vTempChild = vTempChild[vMethodContinue]()) && vTempChild._cachedRow == vChild._cachedRow) { + vRowMax = Math.max(vRowMax, vTempChild.getOuterHeight()); + } + + // switch to new row + vChild._cachedLocationHorizontal = 0; + vChild._cachedLocationVertical += vWidget.getVerticalSpacing() + vRowMax; + vChild._cachedRow++; + } + } + + // add margins and parent padding + if (vWidget.getHorizontalChildrenAlign() == "right") + { + vChild._resetRuntimeLeft(); + vChild._applyRuntimeRight(vWidget.getPaddingRight() + vChild._cachedLocationHorizontal); + } + else + { + vChild._resetRuntimeRight(); + vChild._applyRuntimeLeft(vWidget.getPaddingLeft() + vChild._cachedLocationHorizontal); + } + + if (vWidget.getVerticalChildrenAlign() == "bottom") + { + vChild._resetRuntimeTop(); + vChild._applyRuntimeBottom(vWidget.getPaddingBottom() + vChild._cachedLocationVertical); + } + else + { + vChild._resetRuntimeBottom(); + vChild._applyRuntimeTop(vWidget.getPaddingTop() + vChild._cachedLocationVertical); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/GridLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/GridLayoutImpl.js new file mode 100644 index 0000000000..e6079d31eb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/GridLayoutImpl.js @@ -0,0 +1,302 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.GridLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + + + + +/*! + Global Structure: + + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + Inherits from qx.renderer.layout.LayoutImpl: + + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [11] DISPOSER +*/ + + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the box width of the given child. +*/ +qx.Proto.computeChildBoxWidth = function(vChild) +{ + var vWidget = this.getWidget(); + var vColWidth = vWidget.getColumnInnerWidth(vChild._col, vChild._row); + + // extend colwidth to spanned area + if (vWidget.isSpanStart(vChild._col, vChild._row)) + { + var vEntry = vWidget.getSpanEntry(vChild._col, vChild._row); + for (var i=1; i<vEntry.colLength; i++) + { + // right padding from the previous cell + vColWidth += vWidget.getComputedCellPaddingRight(vChild._col + i - 1, vChild._row); + + // left padding from the current cell + vColWidth += vWidget.getComputedCellPaddingLeft(vChild._col + i, vChild._row); + + // spacing between previous and current cell + vColWidth += vWidget.getHorizontalSpacing(); + + // inner width of the current cell plus + vColWidth += vWidget.getColumnInnerWidth(vChild._col + i, vChild._row); + } + } + + return vChild.getAllowStretchX() ? vColWidth : Math.min(vChild.getWidthValue(), vColWidth); +} + +/*! + Compute and return the box height of the given child. +*/ +qx.Proto.computeChildBoxHeight = function(vChild) +{ + var vWidget = this.getWidget(); + var vRowHeight = vWidget.getRowInnerHeight(vChild._col, vChild._row); + + // extend colwidth to spanned area + if (vWidget.isSpanStart(vChild._col, vChild._row)) + { + var vEntry = vWidget.getSpanEntry(vChild._col, vChild._row); + for (var i=1; i<vEntry.rowLength; i++) + { + // right padding from the previous cell + vRowHeight += vWidget.getComputedCellPaddingBottom(vChild._col, vChild._row + i - 1); + + // left padding from the current cell + vRowHeight += vWidget.getComputedCellPaddingTop(vChild._col, vChild._row + i); + + // spacing between previous and current cell + vRowHeight += vWidget.getVerticalSpacing(); + + // inner width of the current cell plus + vRowHeight += vWidget.getRowInnerHeight(vChild._col, vChild._row + i); + } + } + + return vChild.getAllowStretchY() ? vRowHeight : Math.min(vChild.getHeightValue(), vRowHeight); +} + + + + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the width needed by all children of this widget + which is in a grid layout the width used by all columns. +*/ +qx.Proto.computeChildrenNeededWidth = function() +{ + var vWidget = this.getWidget(); + var vSpacingX = vWidget.getHorizontalSpacing(); + var vSum = -vSpacingX; + + for (var i=0, l=vWidget.getColumnCount(); i<l; i++) { + vSum += vWidget.getColumnBoxWidth(i) + vSpacingX; + } + + return vSum; +} + +/*! + Compute and return the height needed by all children of this widget + which is in a grid layout the height used by all rows. +*/ +qx.Proto.computeChildrenNeededHeight = function() +{ + var vWidget = this.getWidget(); + var vSpacingY = vWidget.getVerticalSpacing(); + var vSum = -vSpacingY; + + for (var i=0, l=vWidget.getRowCount(); i<l; i++) { + vSum += vWidget.getRowBoxHeight(i) + vSpacingY; + } + + return vSum; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + vChild._recomputePercentX(); + vChild.addToLayoutChanges("locationX"); + + return true; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + vChild._recomputePercentY(); + vChild.addToLayoutChanges("locationY"); + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/*! + This is called from qx.ui.core.Widget and it's task is to apply the layout + (excluding border and padding) to the child. +*/ + +qx.Proto.layoutChild = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + this.layoutChild_sizeX(vChild, vJobs); + this.layoutChild_sizeY(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this.layoutChild_marginX(vChild, vJobs); + this.layoutChild_marginY(vChild, vJobs); + + this.layoutChild_locationX(vChild, vJobs); + this.layoutChild_locationY(vChild, vJobs); +} + +qx.Proto.layoutChild_sizeX = function(vChild, vJobs) +{ + vChild._applyRuntimeWidth(vChild.getBoxWidth()); +} + +qx.Proto.layoutChild_sizeY = function(vChild, vJobs) +{ + vChild._applyRuntimeHeight(vChild.getBoxHeight()); +} + +qx.Proto.layoutChild_locationX = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + var vSpacingX = vWidget.getHorizontalSpacing(); + var vLocSumX = vWidget.getPaddingLeft() + vWidget.getComputedCellPaddingLeft(vChild._col, vChild._row); + + for (var i=0; i<vChild._col; i++) { + vLocSumX += vWidget.getColumnBoxWidth(i) + vSpacingX; + } + + switch(vChild.getHorizontalAlign() || vWidget.getColumnHorizontalAlignment(vChild._col) || vWidget.getRowHorizontalAlignment(vChild._row) || vWidget.getHorizontalChildrenAlign()) + { + case "center": + vLocSumX += Math.round((vWidget.getColumnInnerWidth(vChild._col, vChild._row) - vChild.getBoxWidth()) / 2); + break; + + case "right": + vLocSumX += vWidget.getColumnInnerWidth(vChild._col, vChild._row) - vChild.getBoxWidth(); + break; + } + + vChild._applyRuntimeLeft(vLocSumX); +} + +qx.Proto.layoutChild_locationY = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + var vSpacingY = vWidget.getVerticalSpacing(); + var vLocSumY = vWidget.getPaddingTop() + vWidget.getComputedCellPaddingTop(vChild._col, vChild._row); + + for (var i=0; i<vChild._row; i++) { + vLocSumY += vWidget.getRowBoxHeight(i) + vSpacingY; + } + + switch(vChild.getVerticalAlign() || vWidget.getRowVerticalAlignment(vChild._row) || vWidget.getColumnVerticalAlignment(vChild._col) || vWidget.getVerticalChildrenAlign()) + { + case "middle": + vLocSumY += Math.round((vWidget.getRowInnerHeight(vChild._col, vChild._row) - vChild.getBoxHeight()) / 2); + break; + + case "bottom": + vLocSumY += vWidget.getRowInnerHeight(vChild._col, vChild._row) - vChild.getBoxHeight(); + break; + } + + vChild._applyRuntimeTop(vLocSumY); +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/HorizontalBoxLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/HorizontalBoxLayoutImpl.js new file mode 100644 index 0000000000..035b146d0e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/HorizontalBoxLayoutImpl.js @@ -0,0 +1,865 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.HorizontalBoxLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + +qx.OO.addProperty({ name : "enableFlexSupport", type : "boolean", defaultValue : true }); + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.LayoutImpl: + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [11] DISPOSER +*/ + + + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the box width of the given child. +*/ +qx.Proto.computeChildBoxWidth = function(vChild) { + return vChild.getWidthValue() || vChild._computeBoxWidthFallback(); +} + +/*! + Compute and return the box height of the given child. +*/ +qx.Proto.computeChildBoxHeight = function(vChild) +{ + if (this.getWidget().getStretchChildrenOrthogonalAxis() && vChild._computedHeightTypeNull && vChild.getAllowStretchY()) { + return this.getWidget().getInnerHeight(); + } + + return vChild.getHeightValue() || vChild._computeBoxHeightFallback(); +} + +/*! + Computes the width of all flexible children. +*/ +qx.Proto.computeChildrenFlexWidth = function() +{ + if (this._childrenFlexWidthComputed || !this.getEnableFlexSupport()) { + return; + } + + this._childrenFlexWidthComputed = true; + + // this.debug("computeChildrenFlexWidth"); + + var vWidget = this.getWidget(); + var vChildren = vWidget.getVisibleChildren(); + var vChildrenLength = vChildren.length; + var vCurrentChild; + var vFlexibleChildren = []; + var vAvailWidth = vWidget.getInnerWidth(); + var vUsedWidth = vWidget.getSpacing() * (vChildrenLength-1); + var vIterator; + + + // ************************************************************* + // 1. Compute the sum of all static sized children and finding + // all flexible children. + // ************************************************************* + for (vIterator=0; vIterator<vChildrenLength; vIterator++) + { + vCurrentChild = vChildren[vIterator]; + + if (vCurrentChild._computedWidthTypeFlex) + { + vFlexibleChildren.push(vCurrentChild); + + if (vWidget._computedWidthTypeAuto) { + vUsedWidth += vCurrentChild.getPreferredBoxWidth(); + } + } + else + { + vUsedWidth += vCurrentChild.getOuterWidth(); + } + } + + // this.debug("Width: " + vUsedWidth + "/" + vAvailWidth); + // this.debug("Flexible Count: " + vFlexibleChildren.length); + + + // ************************************************************* + // 2. Compute the sum of all flexible children widths + // ************************************************************* + var vRemainingWidth = vAvailWidth - vUsedWidth; + var vFlexibleChildrenLength = vFlexibleChildren.length; + var vPrioritySum = 0; + + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) { + vPrioritySum += vFlexibleChildren[vIterator]._computedWidthParsed; + } + + + // ************************************************************* + // 3. Calculating the size of each 'part'. + // ************************************************************* + var vPartWidth = vRemainingWidth / vPrioritySum; + + + if (!vWidget.getUseAdvancedFlexAllocation()) + { + // ************************************************************* + // 4a. Computing the flex width value of each flexible child + // and add the width to the usedWidth, so that we can + // fix rounding problems later. + // ************************************************************* + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthParsed * vPartWidth); + vUsedWidth += vCurrentChild._computedWidthFlexValue; + } + } + else + { + // ************************************************************* + // 4b. Calculating the diff. Which means respect the min/max + // width configuration in flex and store the higher/lower + // data in a diff. + // ************************************************************* + + var vAllocationDiff = 0; + var vMinAllocationLoops, vFlexibleChildrenLength, vAdjust, vCurrentAllocationSum, vFactorSum, vComputedFlexibleWidth; + + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vComputedFlexibleWidth = vCurrentChild._computedWidthFlexValue = vCurrentChild._computedWidthParsed * vPartWidth; + vAllocationDiff += vComputedFlexibleWidth - qx.lang.Number.limit(vComputedFlexibleWidth, vCurrentChild.getMinWidthValue(), vCurrentChild.getMaxWidthValue()); + } + + // Rounding diff + vAllocationDiff = Math.round(vAllocationDiff); + + if (vAllocationDiff == 0) + { + // ************************************************************* + // 5a. If the diff is equal zero we must not do anything more + // and do nearly identical the same like in 4a. which means + // to round the calculated flex value and add it to the + // used width so we can fix rounding problems later. + // ************************************************************* + + // Rounding values and fixing rounding errors + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthFlexValue); + vUsedWidth += vCurrentChild._computedWidthFlexValue; + } + } + else + { + // ************************************************************* + // 5b. Find maximum loops of each adjustable child to adjust + // the width until the min/max width limits are reached. + // ************************************************************* + + var vUp = vAllocationDiff > 0; + for (vIterator=vFlexibleChildrenLength-1; vIterator>=0; vIterator--) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + if (vUp) + { + vAdjust = (vCurrentChild.getMaxWidthValue() || Infinity) - vCurrentChild._computedWidthFlexValue; + + if (vAdjust > 0) + { + vCurrentChild._allocationLoops = Math.floor(vAdjust / vCurrentChild._computedWidthParsed); + } + else + { + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthFlexValue); + vUsedWidth += Math.round(vCurrentChild._computedWidthFlexValue + vAdjust); + } + } + else + { + vAdjust = qx.util.Validation.isValidNumber(vCurrentChild.getMinWidthValue()) ? vCurrentChild._computedWidthFlexValue - vCurrentChild.getMinWidthValue() : vCurrentChild._computedWidthFlexValue; + + if (vAdjust > 0) + { + vCurrentChild._allocationLoops = Math.floor(vAdjust / vCurrentChild._computedWidthParsed); + } + else + { + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthFlexValue); + vUsedWidth += Math.round(vCurrentChild._computedWidthFlexValue - vAdjust); + } + } + } + + // ************************************************************* + // 6. Try to reallocate the width between flexible children + // so that the requirements through min/max limits + // are satisfied. + // ************************************************************* + while (vAllocationDiff != 0 && vFlexibleChildrenLength > 0) + { + vFlexibleChildrenLength = vFlexibleChildren.length; + vMinAllocationLoops = Infinity; + vFactorSum = 0; + + // Find minimal loop amount + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vMinAllocationLoops = Math.min(vMinAllocationLoops, vFlexibleChildren[vIterator]._allocationLoops); + vFactorSum += vFlexibleChildren[vIterator]._computedWidthParsed; + } + + // Be sure that the adjustment is not bigger/smaller than diff + vCurrentAllocationSum = Math.min(vFactorSum * vMinAllocationLoops, vAllocationDiff); + + // this.debug("Diff: " + vAllocationDiff); + // this.debug("Min Loops: " + vMinAllocationLoops); + // this.debug("Sum: " + vCurrentAllocationSum); + // this.debug("Factor: " + vFactorSum); + + // Reducing diff by current sum + vAllocationDiff -= vCurrentAllocationSum; + + // Adding sizes to children to adjust + for (vIterator=vFlexibleChildrenLength-1; vIterator>=0; vIterator--) + { + vCurrentChild = vFlexibleChildren[vIterator]; + vCurrentChild._computedWidthFlexValue += vCurrentAllocationSum / vFactorSum * vCurrentChild._computedWidthParsed; + + if (vCurrentChild._allocationLoops == vMinAllocationLoops) + { + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthFlexValue); + + vUsedWidth += vCurrentChild._computedWidthFlexValue; + delete vCurrentChild._allocationLoops; + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + } + else + { + if (vAllocationDiff == 0) + { + vCurrentChild._computedWidthFlexValue = Math.round(vCurrentChild._computedWidthFlexValue); + vUsedWidth += vCurrentChild._computedWidthFlexValue; + delete vCurrentChild._allocationLoops; + } + else + { + vCurrentChild._allocationLoops -= vMinAllocationLoops; + } + } + } + } + } + } + + // ************************************************************* + // 7. Fix rounding errors + // ************************************************************* + vCurrentChild._computedWidthFlexValue += vAvailWidth - vUsedWidth; +} + +qx.Proto.invalidateChildrenFlexWidth = function() { + delete this._childrenFlexWidthComputed; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the width needed by all children of this widget +*/ +qx.Proto.computeChildrenNeededWidth = function() +{ + var w = this.getWidget(); + return qx.renderer.layout.LayoutImpl.prototype.computeChildrenNeededWidth_sum.call(this) + ((w.getVisibleChildrenLength()-1) * w.getSpacing()); +} + + + + + + +/* +--------------------------------------------------------------------------- + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS +--------------------------------------------------------------------------- +*/ + +/*! + Things to do and layout when any of the childs changes its outer width. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateSelfOnChildOuterWidthChange = function(vChild) +{ + // if a childrens outer width changes we need to update our accumulated + // width of all childrens (used for center or right alignments) + this.getWidget()._invalidateAccumulatedChildrenOuterWidth(); +} + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + if (this.getWidget().getHorizontalChildrenAlign() == "center") { + vChild.addToLayoutChanges("locationX"); + } + + // use variables here to be sure to call both methods. + var vUpdatePercent = vChild._recomputePercentX(); + var vUpdateFlex = vChild._recomputeFlexX(); + + // inform the caller if there were any notable changes occured + return vUpdatePercent || vUpdateFlex; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + // use variables here to be sure to call both methods. + var vUpdatePercent = vChild._recomputePercentY(); + var vUpdateStretch = vChild._recomputeStretchingY(); + + // priority to childs internal alignment + if ((vChild.getVerticalAlign() || this.getWidget().getVerticalChildrenAlign()) == "middle") { + vChild.addToLayoutChanges("locationY"); + } + + // inform the caller if there were any notable changes occured + return vUpdatePercent || vUpdateStretch; +} + + + + + +/* +--------------------------------------------------------------------------- + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Invalidate and recompute things because of job in queue (before the rest of job handling will be executed). +*/ +qx.Proto.updateSelfOnJobQueueFlush = function(vJobQueue) +{ + if (vJobQueue.addChild || vJobQueue.removeChild) { + this.getWidget()._invalidateAccumulatedChildrenOuterWidth(); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Updates children on special jobs +*/ +qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue) +{ + var vStretchX=false, vStretchY=false; + var vWidget = this.getWidget(); + + // switching the orientation need updates for stretching on both axis + if (vQueue.orientation) { + vStretchX = vStretchY = true; + } + + // different updates depending from the current orientation (or the new one) + if (vQueue.spacing || vQueue.orientation || vQueue.reverseChildrenOrder || vQueue.horizontalChildrenAlign) { + vWidget._addChildrenToLayoutQueue("locationX"); + } + + if (vQueue.verticalChildrenAlign) { + vWidget._addChildrenToLayoutQueue("locationY"); + } + + if (vQueue.stretchChildrenOrthogonalAxis) { + vStretchY = true; + } + + // if stretching should be reworked reset the previous one and add + // a layout job to update the width respectively height. + if (vStretchX) + { + vWidget._recomputeChildrenStretchingX(); + vWidget._addChildrenToLayoutQueue("width"); + } + + if (vStretchY) + { + vWidget._recomputeChildrenStretchingY(); + vWidget._addChildrenToLayoutQueue("height"); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + [08] CHILDREN ADD/REMOVE/MOVE HANDLING +--------------------------------------------------------------------------- +*/ + +/*! + This method combines calls of methods which should be done if a widget should be removed from the current layout. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnRemoveChild = function(vChild, vIndex) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i=-1; + + // Fix index to be at the first flex child + if (this.getEnableFlexSupport()) + { + for (i=0; i<chl; i++) + { + chc = ch[i]; + if (chc.getHasFlexX()) + { + vIndex = Math.min(vIndex, i); + break; + } + } + + i=-1; + } + + // Handle differently depending on layout mode + switch(w.getLayoutMode()) + { + case "right": + case "left-reversed": + while((chc=ch[++i]) && i<vIndex) { + chc.addToLayoutChanges("locationX"); + } + + break; + + case "center": + case "center-reversed": + while(chc=ch[++i]) { + chc.addToLayoutChanges("locationX"); + } + + break; + + default: + i+=vIndex; + while(chc=ch[++i]) { + chc.addToLayoutChanges("locationX"); + } + } +} + +/*! + This method combines calls of methods which should be done if a child should be moved + inside the same parent to a new positions. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnMoveChild = function(vChild, vIndex, vOldIndex) +{ + var vChildren = this.getWidget().getVisibleChildren(); + + var vStart = Math.min(vIndex, vOldIndex); + var vStop = Math.max(vIndex, vOldIndex)+1; + + for (var i=vStart; i<vStop; i++) { + vChildren[i].addToLayoutChanges("locationX"); + } +} + + + + + +/* +--------------------------------------------------------------------------- + [09] FLUSH LAYOUT QUEUES OF CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + This method have full control of the order in which the + registered (or also non-registered) children should be + layouted on the horizontal axis. +*/ +qx.Proto.flushChildrenQueue = function(vChildrenQueue) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i; + + // This block is needed for flex handling and + // will inform flex children if there was any + // change to the other content + if (this.getEnableFlexSupport()) + { + this.invalidateChildrenFlexWidth(); + + for (i=0; i<chl; i++) + { + chc = ch[i]; + if (chc.getHasFlexX()) + { + chc._computedWidthValue = null; + + if (chc._recomputeBoxWidth()) + { + chc._recomputeOuterWidth(); + chc._recomputeInnerWidth(); + } + + vChildrenQueue[chc.toHashCode()] = chc; + chc._layoutChanges.width = true; + } + } + } + + switch(w.getLayoutMode()) + { + case "right": + case "left-reversed": + // find the last child which has a layout request + for (var i=chl-1; i>=0 && !vChildrenQueue[ch[i].toHashCode()]; i--) {} + + // layout all children before this last child + for (var j=0; j<=i; j++) { + w._layoutChild(chc=ch[j]); + } + + break; + + case "center": + case "center-reversed": + // re-layout all children + i = -1; + while(chc=ch[++i]) { + w._layoutChild(chc); + } + + break; + + default: + // layout all childs from the first child + // with an own layout request to the end + i = -1; + var changed=false; + while(chc=ch[++i]) + { + if (changed || vChildrenQueue[chc.toHashCode()]) + { + w._layoutChild(chc); + changed = true; + } + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/*! + This is called from qx.ui.core.Widget and it's task is to apply the layout + (excluding border and padding) to the child. +*/ +qx.Proto.layoutChild = function(vChild, vJobs) +{ + this.layoutChild_sizeX(vChild, vJobs); + this.layoutChild_sizeY(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this.layoutChild_locationX(vChild, vJobs); + this.layoutChild_locationY(vChild, vJobs); + + this.layoutChild_marginX(vChild, vJobs); + this.layoutChild_marginY(vChild, vJobs); +} + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera() || qx.core.Client.getInstance().isWebkit() ) +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth) + { + if (vChild._isWidthEssential() && (!vChild._computedWidthTypeNull || !vChild._computedMinWidthTypeNull || !vChild._computedMaxWidthTypeNull)) + { + vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + else + { + vChild._resetRuntimeWidth(); + } + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight) + { + if ((vChild._isHeightEssential() && (!vChild._computedHeightTypeNull || !vChild._computedMinHeightTypeNull || !vChild._computedMaxHeightTypeNull)) || (vChild.getAllowStretchY() && this.getWidget().getStretchChildrenOrthogonalAxis())) + { + vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + else + { + vChild._resetRuntimeHeight(); + } + } + } +} +else +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width) + { + if (vChild._isWidthEssential() && !vChild._computedWidthTypeNull) + { + vChild._applyRuntimeWidth(vChild.getWidthValue()); + } + else + { + vChild._resetRuntimeWidth(); + } + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height) + { + if (vChild._isHeightEssential() && !vChild._computedHeightTypeNull) + { + vChild._applyRuntimeHeight(vChild.getHeightValue()); + } + else + { + vChild._resetRuntimeHeight(); + } + } + } +} + +qx.Proto.layoutChild_locationX = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + // handle first child + if (vWidget.getFirstVisibleChild() == vChild) + { + switch(vWidget.getLayoutMode()) + { + case "right": + case "left-reversed": + var vPos = vWidget.getPaddingRight() + vWidget.getAccumulatedChildrenOuterWidth() - vChild.getOuterWidth(); + break; + + case "center": + case "center-reversed": + var vPos = vWidget.getPaddingLeft() + Math.round((vWidget.getInnerWidth() - vWidget.getAccumulatedChildrenOuterWidth()) / 2); + break; + + default: + var vPos = vWidget.getPaddingLeft(); + } + } + + // handle any following child + else + { + var vPrev = vChild.getPreviousVisibleSibling(); + + switch(vWidget.getLayoutMode()) + { + case "right": + case "left-reversed": + var vPos = vPrev._cachedLocationHorizontal - vChild.getOuterWidth() - vWidget.getSpacing(); + break; + + default: + var vPos = vPrev._cachedLocationHorizontal + vPrev.getOuterWidth() + vWidget.getSpacing(); + } + } + + // store for next sibling + vChild._cachedLocationHorizontal = vPos; + + // apply styles + switch(vWidget.getLayoutMode()) + { + case "right": + case "right-reversed": + case "center-reversed": + // add relative positions (like 'position:relative' in css) + vPos += !vChild._computedRightTypeNull ? vChild.getRightValue() : !vChild._computedLeftTypeNull ? -(vChild.getLeftValue()) : 0; + + vChild._resetRuntimeLeft(); + vChild._applyRuntimeRight(vPos); + break; + + default: + // add relative positions (like 'position:relative' in css) + vPos += !vChild._computedLeftTypeNull ? vChild.getLeftValue() : !vChild._computedRightTypeNull ? -(vChild.getRightValue()) : 0; + + vChild._resetRuntimeRight(); + vChild._applyRuntimeLeft(vPos); + } +} + +qx.Proto.layoutChild_locationY = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + // special stretching support + if (qx.core.Client.getInstance().isGecko() && vChild.getAllowStretchY() && vWidget.getStretchChildrenOrthogonalAxis() && vChild._computedHeightTypeNull) + { + vChild._applyRuntimeTop(vWidget.getPaddingTop() || 0); + vChild._applyRuntimeBottom(vWidget.getPaddingBottom() || 0); + + return; + } + + // priority to childs internal alignment + var vAlign = vChild.getVerticalAlign() || vWidget.getVerticalChildrenAlign(); + + // handle middle alignment + var vPos = vAlign == "middle" ? Math.round((vWidget.getInnerHeight() - vChild.getOuterHeight()) / 2) : 0; + + // the bottom alignment use the real 'bottom' styleproperty to + // use the best available method in modern browsers + if (vAlign == "bottom") + { + // add parent padding + vPos += vWidget.getPaddingBottom(); + + // relative positions (like 'position:relative' in css) + if (!vChild._computedBottomTypeNull) { + vPos += vChild.getBottomValue(); + } + else if (!vChild._computedTopTypeNull) { + vPos -= vChild.getTopValue(); + } + + // apply styles + vChild._resetRuntimeTop(); + vChild._applyRuntimeBottom(vPos); + } + else + { + // add parent padding + vPos += vWidget.getPaddingTop(); + + // relative positions (like 'position:relative' in css) + if (!vChild._computedTopTypeNull) { + vPos += vChild.getTopValue(); + } + else if (!vChild._computedBottomTypeNull) { + vPos -= vChild.getBottomValue(); + } + + // apply styles + vChild._resetRuntimeBottom(); + vChild._applyRuntimeTop(vPos); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/LayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/LayoutImpl.js new file mode 100644 index 0000000000..ee78f0cc50 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/LayoutImpl.js @@ -0,0 +1,551 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(ui_layout) +#require(qx.core.Client) + +************************************************************************ */ + +/** + * Abstact base class of all layout implementations + * + * @param vWidget {qx.ui.core.Parent} reference to the associated widget + */ +qx.OO.defineClass("qx.renderer.layout.LayoutImpl", qx.core.Object, +function(vWidget) +{ + qx.core.Object.call(this); + + this._widget = vWidget; +}); + + + + +/** + * Returns the associated widget + * + * @return {qx.ui.core.Parent} reference to the associated widget + */ +qx.Proto.getWidget = function() { + return this._widget; +} + + +/* + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER +*/ + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/** + * Compute and return the box width of the given child + * + * @param vChild {qx.ui.core.Widget} + * @return {Integer} box width of the given child + */ +qx.Proto.computeChildBoxWidth = function(vChild) { + return vChild.getWidthValue() || vChild._computeBoxWidthFallback(); +} + +/** + * Compute and return the box height of the given child + * + * @param vChild {qx.ui.core.Widget} + * @return {Integer} box height of the given child + */ +qx.Proto.computeChildBoxHeight = function(vChild) { + return vChild.getHeightValue() || vChild._computeBoxHeightFallback(); +} + + + + + +/* +--------------------------------------------------------------------------- + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/** + * Compute and return the needed width of the given child + * + * @param vChild {qx.ui.core.Widget} + * @return {Integer} needed width + */ +qx.Proto.computeChildNeededWidth = function(vChild) +{ + // omit ultra long lines, these two variables only needed once + // here, but this enhance the readability of the code :) + var vMinBox = vChild._computedMinWidthTypePercent ? null : vChild.getMinWidthValue(); + var vMaxBox = vChild._computedMaxWidthTypePercent ? null : vChild.getMaxWidthValue(); + + var vBox = (vChild._computedWidthTypePercent || vChild._computedWidthTypeFlex ? null : vChild.getWidthValue()) || vChild.getPreferredBoxWidth() || 0; + + return qx.lang.Number.limit(vBox, vMinBox, vMaxBox) + vChild.getMarginLeft() + vChild.getMarginRight(); +} + +/** + * Compute and return the needed height of the given child + * + * @param vChild {qx.ui.core.Widget} + * @return {Integer} needed height + */ +qx.Proto.computeChildNeededHeight = function(vChild) +{ + // omit ultra long lines, these two variables only needed once + // here, but this enhance the readability of the code :) + var vMinBox = vChild._computedMinHeightTypePercent ? null : vChild.getMinHeightValue(); + var vMaxBox = vChild._computedMaxHeightTypePercent ? null : vChild.getMaxHeightValue(); + + var vBox = (vChild._computedHeightTypePercent || vChild._computedHeightTypeFlex ? null : vChild.getHeightValue()) || vChild.getPreferredBoxHeight() || 0; + + return qx.lang.Number.limit(vBox, vMinBox, vMaxBox) + vChild.getMarginTop() + vChild.getMarginBottom(); +} + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/** + * Calculate the maximum needed width of all children + * + * @return {Integer} maximum needed width of all children + */ +qx.Proto.computeChildrenNeededWidth_max = function() +{ + for (var i=0, ch=this.getWidget().getVisibleChildren(), chl=ch.length, maxv=0; i<chl; i++) { + maxv = Math.max(maxv, ch[i].getNeededWidth()); + } + + return maxv; +} + +/** + * Calculate the maximum needed height of all children + * + * @return {Integer} maximum needed height of all children + */ +qx.Proto.computeChildrenNeededHeight_max = function() +{ + for (var i=0, ch=this.getWidget().getVisibleChildren(), chl=ch.length, maxv=0; i<chl; i++) { + maxv = Math.max(maxv, ch[i].getNeededHeight()); + } + + return maxv; +} + +/** + * Compute and return the width needed by all children of this widget + * + * @return {Integer} + */ +qx.Proto.computeChildrenNeededWidth_sum = function() +{ + for (var i=0, ch=this.getWidget().getVisibleChildren(), chl=ch.length, sumv=0; i<chl; i++) { + sumv += ch[i].getNeededWidth(); + } + + return sumv; +} + +/** + * Compute and return the height needed by all children of this widget + * + * @return {Integer} height needed by all children of this widget + */ +qx.Proto.computeChildrenNeededHeight_sum = function() +{ + for (var i=0, ch=this.getWidget().getVisibleChildren(), chl=ch.length, sumv=0; i<chl; i++) { + sumv += ch[i].getNeededHeight(); + } + + return sumv; +} + +/** + * Compute and return the width needed by all children of this widget + * + * @return {Integer} width needed by all children of this widget + */ +qx.Proto.computeChildrenNeededWidth = qx.Proto.computeChildrenNeededWidth_max; + +/** + * Compute and return the height needed by all children of this widget + * + * @return {Integer} height needed by all children of this widget + */ +qx.Proto.computeChildrenNeededHeight = qx.Proto.computeChildrenNeededHeight_max; + + + + +/* +--------------------------------------------------------------------------- + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS +--------------------------------------------------------------------------- +*/ + +/** + * Things to do and layout when any of the childs changes its outer width. + * Needed by layouts where the children depend on each other, like flow or box layouts. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} changed child widget + */ +qx.Proto.updateSelfOnChildOuterWidthChange = function(vChild) {} + +/** + * Things to do and layout when any of the childs changes its outer height. + * Needed by layouts where the children depend on each other, like flow or box layouts. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} changed child widget + */ +qx.Proto.updateSelfOnChildOuterHeightChange = function(vChild) {} + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/** + * Actions that should be done if the inner width of the layout widget has changed. + * Normally this includes updates to percent values and ranges. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} changed child widget + */ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) {} + +/** + * Actions that should be done if the inner height of the layout widget has changed. + * Normally this includes updates to percent values and ranges. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} changed child widget + */ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) {} + + + + + +/* +--------------------------------------------------------------------------- + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/** + * Invalidate and recompute cached data according to job queue. + * This is executed at the beginning of the job queue handling. + * + * Subclasses might implement this method + * + * @param vJobQueue {Object} + */ +qx.Proto.updateSelfOnJobQueueFlush = function(vJobQueue) {} + + + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ +/** + * Updates children on job queue flush. + * This is executed at the end of the job queue handling. + * + * Subclasses might implement this method + * + * @param vJobQueue {Object} + */ +qx.Proto.updateChildrenOnJobQueueFlush = function(vJobQueue) {} + + + + + + +/* +--------------------------------------------------------------------------- + [08] CHILDREN ADD/REMOVE/MOVE HANDLING +--------------------------------------------------------------------------- +*/ + +/** + * Add child to current layout. Rarely needed by some layout implementations. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} newly added child + * @param vIndex {Integer} index of the child + */ +qx.Proto.updateChildrenOnAddChild = function(vChild, vIndex) {} + +/** + *Remove child from current layout. + * Needed by layouts where the children depend on each other, like flow or box layouts. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} newly added child + * @param vIndex {Integer} index of the child + */ + qx.Proto.updateChildrenOnRemoveChild = function(vChild, vIndex) {} + +/** + * Move child within its parent to a new position. + * Needed by layouts where the children depend on each other, like flow or box layouts. + * + * Subclasses might implement this method + * + * @param vChild {qx.ui.core.Widget} newly added child + * @param vIndex {Integer} new index of the child + * @param vOldIndex {Integer} old index of the child + */ +qx.Proto.updateChildrenOnMoveChild = function(vChild, vIndex, vOldIndex) {} + + + + + + + +/* +--------------------------------------------------------------------------- + [09] FLUSH LAYOUT QUEUES OF CHILDREN +--------------------------------------------------------------------------- +*/ + +/** + * Has full control of the order in which the registered + * (or non-registered) children should be layouted. + * + * @param vChildrenQueue {Object} + */ +qx.Proto.flushChildrenQueue = function(vChildrenQueue) +{ + var vWidget = this.getWidget(); + + for (var vHashCode in vChildrenQueue) { + vWidget._layoutChild(vChildrenQueue[vHashCode]); + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/** + * Called from qx.ui.core.Parent. Its task is to apply the layout + * (excluding border and padding) to the child. + * + * @param vChild {qx.ui.core.Widget} child to layout + * @param vJobs {Set} layout changes to perform + */ +qx.Proto.layoutChild = function(vChild, vJobs) {} + + +/** + * Apply min-/max-width to the child. Direct usage of stylesheet properties. + * This is only possible in modern capable clients (i.e. excluding all current + * versions of Internet Explorer) + * + * @param vChild {qx.ui.core.Widget} child to layout + * @param vJobs {Set} layout changes to perform + */ +qx.Proto.layoutChild_sizeLimitX = function(vChild, vJobs) {} + +/** + * Apply min-/max-height to the child. Direct usage of stylesheet properties. + * This is only possible in modern capable clients (i.e. excluding all current + * versions of Internet Explorer) + * + * @param vChild {qx.ui.core.Widget} child to layout + * @param vJobs {Set} layout changes to perform + */ +qx.Proto.layoutChild_sizeLimitY = function(vChild, vJobs) {} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.layoutChild_sizeLimitX = qx.lang.Function.returnTrue; + qx.Proto.layoutChild_sizeLimitY = qx.lang.Function.returnTrue; +} +else +{ + + qx.Proto.layoutChild_sizeLimitX = function(vChild, vJobs) + { + if (vJobs.minWidth) { + vChild._computedMinWidthTypeNull ? vChild._resetRuntimeMinWidth() : vChild._applyRuntimeMinWidth(vChild.getMinWidthValue()); + } + else if (vJobs.initial && !vChild._computedMinWidthTypeNull) { + vChild._applyRuntimeMinWidth(vChild.getMinWidthValue()); + } + + if (vJobs.maxWidth) { + vChild._computedMaxWidthTypeNull ? vChild._resetRuntimeMaxWidth() : vChild._applyRuntimeMaxWidth(vChild.getMaxWidthValue()); + } + else if (vJobs.initial && !vChild._computedMaxWidthTypeNull) { + vChild._applyRuntimeMaxWidth(vChild.getMaxWidthValue()); + } + } + + qx.Proto.layoutChild_sizeLimitY = function(vChild, vJobs) + { + if (vJobs.minHeight) { + vChild._computedMinHeightTypeNull ? vChild._resetRuntimeMinHeight() : vChild._applyRuntimeMinHeight(vChild.getMinHeightValue()); + } + else if (vJobs.initial && !vChild._computedMinHeightTypeNull) { + vChild._applyRuntimeMinHeight(vChild.getMinHeightValue()); + } + + if (vJobs.maxHeight) { + vChild._computedMaxHeightTypeNull ? vChild._resetRuntimeMaxHeight() : vChild._applyRuntimeMaxHeight(vChild.getMaxHeightValue()); + } + else if (vJobs.initial && !vChild._computedMaxHeightTypeNull) { + vChild._applyRuntimeMaxHeight(vChild.getMaxHeightValue()); + } + } +} + +/** + * Apply the X margin values as pure stylesheet equivalent. + * + * @param vChild {qx.ui.core.Widget} child to layout + * @param vJobs {Set} layout changes to perform + */ +qx.Proto.layoutChild_marginX = function(vChild, vJobs) +{ + if (vJobs.marginLeft || vJobs.initial) + { + var vValueLeft = vChild.getMarginLeft(); + vValueLeft != null ? vChild._applyRuntimeMarginLeft(vValueLeft) : vChild._resetRuntimeMarginLeft(); + } + + if (vJobs.marginRight || vJobs.initial) + { + var vValueRight = vChild.getMarginRight(); + vValueRight != null ? vChild._applyRuntimeMarginRight(vValueRight) : vChild._resetRuntimeMarginRight(); + } +} + +/** + * Apply the Y margin values as pure stylesheet equivalent. + * + * @param vChild {qx.ui.core.Widget} child to layout + * @param vJobs {Set} layout changes to perform + */ +qx.Proto.layoutChild_marginY = function(vChild, vJobs) +{ + if (vJobs.marginTop || vJobs.initial) + { + var vValueTop = vChild.getMarginTop(); + vValueTop != null ? vChild._applyRuntimeMarginTop(vValueTop) : vChild._resetRuntimeMarginTop(); + } + + if (vJobs.marginBottom || vJobs.initial) + { + var vValueBottom = vChild.getMarginBottom(); + vValueBottom != null ? vChild._applyRuntimeMarginBottom(vValueBottom) : vChild._resetRuntimeMarginBottom(); + } +} + +qx.Proto.layoutChild_sizeX_essentialWrapper = function(vChild, vJobs) { + return vChild._isWidthEssential() ? this.layoutChild_sizeX(vChild, vJobs) : vChild._resetRuntimeWidth(); +} + +qx.Proto.layoutChild_sizeY_essentialWrapper = function(vChild, vJobs) { + return vChild._isHeightEssential() ? this.layoutChild_sizeY(vChild, vJobs) : vChild._resetRuntimeHeight(); +} + + + + + + +/* +--------------------------------------------------------------------------- + [11] DISPOSER +--------------------------------------------------------------------------- +*/ + +/*! + Dispose the layout implmentation and release the associated widget. +*/ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + this._widget = null; + + qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuButtonLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuButtonLayoutImpl.js new file mode 100644 index 0000000000..a9c6f3499d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuButtonLayoutImpl.js @@ -0,0 +1,185 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.MenuButtonLayoutImpl", qx.renderer.layout.HorizontalBoxLayoutImpl, +function(vWidget) +{ + qx.renderer.layout.HorizontalBoxLayoutImpl.call(this, vWidget); + + // We don't need flex support, should make things a bit faster, + // as this omits some additional loops in qx.renderer.layout.HorizontalBoxLayoutImpl. + this.setEnableFlexSupport(false); +}); + + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.HorizontalBoxLayoutImpl: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [11] DISPOSER +*/ + + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the width needed by all children of this widget +*/ +qx.Proto.computeChildrenNeededWidth = function() +{ + // Caching the widget reference + var vWidget = this.getWidget(); + + // Ignore the verticalBoxLayout inside qx.ui.menu.Menu + var vMenu = vWidget.getParent().getParent(); + + // Let the menu do the real hard things + return vMenu.getMenuButtonNeededWidth(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS +--------------------------------------------------------------------------- +*/ + +/*! + Things to do and layout when any of the childs changes its outer width. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateSelfOnChildOuterWidthChange = function(vChild) +{ + // Caching the widget reference + var vWidget = this.getWidget(); + + // Ignore the verticalBoxLayout inside qx.ui.menu.Menu + var vMenu = vWidget.getParent().getParent(); + + // Send out invalidate signals + switch(vChild) + { + case vWidget._iconObject: + vMenu._invalidateMaxIconWidth(); + break; + + case vWidget._labelObject: + vMenu._invalidateMaxLabelWidth(); + break; + + case vWidget._shortcutObject: + vMenu._invalidateMaxShortcutWidth(); + break; + + case vWidget._arrowObject: + vMenu._invalidateMaxArrowWidth(); + break; + } + + // Call superclass implementation + return qx.renderer.layout.HorizontalBoxLayoutImpl.prototype.updateSelfOnChildOuterWidthChange.call(this, vChild); +} + + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +qx.Proto.layoutChild_locationX = function(vChild, vJobs) +{ + // Caching the widget reference + var vWidget = this.getWidget(); + + // Ignore the verticalBoxLayout inside qx.ui.menu.Menu + var vMenu = vWidget.getParent().getParent(); + + // Left position of the child + var vPos = null; + + // Ask the menu instance for the correct location + switch(vChild) + { + case vWidget._iconObject: + vPos = vMenu.getIconPosition(); + break; + + case vWidget._labelObject: + vPos = vMenu.getLabelPosition(); + break; + + case vWidget._shortcutObject: + vPos = vMenu.getShortcutPosition(); + break; + + case vWidget._arrowObject: + vPos = vMenu.getArrowPosition(); + break; + } + + if (vPos != null) + { + vPos += vWidget.getPaddingLeft(); + vChild._applyRuntimeLeft(vPos); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuLayoutImpl.js new file mode 100644 index 0000000000..14ef800a76 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/MenuLayoutImpl.js @@ -0,0 +1,102 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.MenuLayoutImpl", qx.renderer.layout.VerticalBoxLayoutImpl, +function(vWidget) +{ + qx.renderer.layout.VerticalBoxLayoutImpl.call(this, vWidget); + + // We don't need flex support, should make things a bit faster, + // as this omits some additional loops in qx.renderer.layout.HorizontalBoxLayoutImpl. + this.setEnableFlexSupport(false); +}); + + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.VerticalBoxLayoutImpl: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER +*/ + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Updates children on special jobs +*/ +qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue) +{ + var vWidget = this.getWidget(); + var ch, chc; + + if (vQueue.preferredInnerWidth) + { + var ch = vWidget.getChildren(), chl = ch.length, chc; + var sch, schl; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + sch = chc.getChildren(); + schl = sch.length; + + for (var j=0; j<schl; j++) { + sch[j].addToLayoutChanges("locationX"); + } + } + } + + // Call superclass implementation + return qx.renderer.layout.VerticalBoxLayoutImpl.prototype.updateChildrenOnJobQueueFlush.call(this, vQueue); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/VerticalBoxLayoutImpl.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/VerticalBoxLayoutImpl.js new file mode 100644 index 0000000000..fe2eb8f897 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/layout/VerticalBoxLayoutImpl.js @@ -0,0 +1,868 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.layout.VerticalBoxLayoutImpl", qx.renderer.layout.LayoutImpl, +function(vWidget) { + qx.renderer.layout.LayoutImpl.call(this, vWidget); +}); + +qx.OO.addProperty({ name : "enableFlexSupport", type : "boolean", defaultValue : true }); + + + +/*! + Global Structure: + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH + [08] CHILDREN ADD/REMOVE/MOVE HANDLING + [09] FLUSH LAYOUT QUEUES OF CHILDREN + [10] LAYOUT CHILD + [11] DISPOSER + + + Inherits from qx.renderer.layout.LayoutImpl: + [02] COMPUTE NEEDED DIMENSIONS FOR AN INDIVIDUAL CHILD + [11] DISPOSER +*/ + + + +/* +--------------------------------------------------------------------------- + [01] COMPUTE BOX DIMENSIONS FOR AN INDIVIDUAL CHILD +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the box width of the given child. +*/ +qx.Proto.computeChildBoxWidth = function(vChild) +{ + if (this.getWidget().getStretchChildrenOrthogonalAxis() && vChild._computedWidthTypeNull && vChild.getAllowStretchX()) { + return this.getWidget().getInnerWidth(); + } + + return vChild.getWidthValue() || vChild._computeBoxWidthFallback(); +} + +/*! + Compute and return the box height of the given child. +*/ +qx.Proto.computeChildBoxHeight = function(vChild) { + return vChild.getHeightValue() || vChild._computeBoxHeightFallback(); +} + +/*! + Computes the height of all flexible children. +*/ +qx.Proto.computeChildrenFlexHeight = function() +{ + if (this._childrenFlexHeightComputed || !this.getEnableFlexSupport()) { + return; + } + + this._childrenFlexHeightComputed = true; + + // this.debug("computeChildrenFlexHeight"); + + var vWidget = this.getWidget(); + var vChildren = vWidget.getVisibleChildren(); + var vChildrenLength = vChildren.length; + var vCurrentChild; + var vFlexibleChildren = []; + var vAvailHeight = vWidget.getInnerHeight(); + var vUsedHeight = vWidget.getSpacing() * (vChildrenLength-1); + var vIterator; + + + // ************************************************************* + // 1. Compute the sum of all static sized children and finding + // all flexible children. + // ************************************************************* + for (vIterator=0; vIterator<vChildrenLength; vIterator++) + { + vCurrentChild = vChildren[vIterator]; + + if (vCurrentChild._computedHeightTypeFlex) + { + vFlexibleChildren.push(vCurrentChild); + + if (vWidget._computedHeightTypeAuto) { + vUsedHeight += vCurrentChild.getPreferredBoxHeight(); + } + } + else + { + vUsedHeight += vCurrentChild.getOuterHeight(); + } + } + + // this.debug("Height: " + vUsedHeight + "/" + vAvailHeight); + // this.debug("Flexible Count: " + vFlexibleChildren.length); + + + // ************************************************************* + // 2. Compute the sum of all flexible children heights + // ************************************************************* + var vRemainingHeight = vAvailHeight - vUsedHeight; + var vFlexibleChildrenLength = vFlexibleChildren.length; + var vPrioritySum = 0; + + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) { + vPrioritySum += vFlexibleChildren[vIterator]._computedHeightParsed; + } + + + // ************************************************************* + // 3. Calculating the size of each 'part'. + // ************************************************************* + var vPartHeight = vRemainingHeight / vPrioritySum; + + + if (!vWidget.getUseAdvancedFlexAllocation()) + { + // ************************************************************* + // 4a. Computing the flex height value of each flexible child + // and add the height to the usedHeight, so that we can + // fix rounding problems later. + // ************************************************************* + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightParsed * vPartHeight); + vUsedHeight += vCurrentChild._computedHeightFlexValue; + } + } + else + { + // ************************************************************* + // 4b. Calculating the diff. Which means respect the min/max + // height configuration in flex and store the higher/lower + // data in a diff. + // ************************************************************* + + var vAllocationDiff = 0; + var vMinAllocationLoops, vFlexibleChildrenLength, vAdjust, vCurrentAllocationSum, vFactorSum, vComputedFlexibleHeight; + + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vComputedFlexibleHeight = vCurrentChild._computedHeightFlexValue = vCurrentChild._computedHeightParsed * vPartHeight; + vAllocationDiff += vComputedFlexibleHeight - qx.lang.Number.limit(vComputedFlexibleHeight, vCurrentChild.getMinHeightValue(), vCurrentChild.getMaxHeightValue()); + } + + // Rounding diff + vAllocationDiff = Math.round(vAllocationDiff); + + if (vAllocationDiff == 0) + { + // ************************************************************* + // 5a. If the diff is equal zero we must not do anything more + // and do nearly identical the same like in 4a. which means + // to round the calculated flex value and add it to the + // used height so we can fix rounding problems later. + // ************************************************************* + + // Rounding values and fixing rounding errors + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightFlexValue); + vUsedHeight += vCurrentChild._computedHeightFlexValue; + } + } + else + { + // ************************************************************* + // 5b. Find maximum loops of each adjustable child to adjust + // the height until the min/max height limits are reached. + // ************************************************************* + + var vUp = vAllocationDiff > 0; + for (vIterator=vFlexibleChildrenLength-1; vIterator>=0; vIterator--) + { + vCurrentChild = vFlexibleChildren[vIterator]; + + if (vUp) + { + vAdjust = (vCurrentChild.getMaxHeightValue() || Infinity) - vCurrentChild._computedHeightFlexValue; + + if (vAdjust > 0) + { + vCurrentChild._allocationLoops = Math.floor(vAdjust / vCurrentChild._computedHeightParsed); + } + else + { + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightFlexValue); + vUsedHeight += Math.round(vCurrentChild._computedHeightFlexValue + vAdjust); + } + } + else + { + vAdjust = qx.util.Validation.isValidNumber(vCurrentChild.getMinHeightValue()) ? vCurrentChild._computedHeightFlexValue - vCurrentChild.getMinHeightValue() : vCurrentChild._computedHeightFlexValue; + + if (vAdjust > 0) + { + vCurrentChild._allocationLoops = Math.floor(vAdjust / vCurrentChild._computedHeightParsed); + } + else + { + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightFlexValue); + vUsedHeight += Math.round(vCurrentChild._computedHeightFlexValue - vAdjust); + } + } + } + + // ************************************************************* + // 6. Try to reallocate the height between flexible children + // so that the requirements through min/max limits + // are satisfied. + // ************************************************************* + while (vAllocationDiff != 0 && vFlexibleChildrenLength > 0) + { + vFlexibleChildrenLength = vFlexibleChildren.length; + vMinAllocationLoops = Infinity; + vFactorSum = 0; + + // Find minimal loop amount + for (vIterator=0; vIterator<vFlexibleChildrenLength; vIterator++) + { + vMinAllocationLoops = Math.min(vMinAllocationLoops, vFlexibleChildren[vIterator]._allocationLoops); + vFactorSum += vFlexibleChildren[vIterator]._computedHeightParsed; + } + + // Be sure that the adjustment is not bigger/smaller than diff + vCurrentAllocationSum = Math.min(vFactorSum * vMinAllocationLoops, vAllocationDiff); + + // this.debug("Diff: " + vAllocationDiff); + // this.debug("Min Loops: " + vMinAllocationLoops); + // this.debug("Sum: " + vCurrentAllocationSum); + // this.debug("Factor: " + vFactorSum); + + // Reducing diff by current sum + vAllocationDiff -= vCurrentAllocationSum; + + // Adding sizes to children to adjust + for (vIterator=vFlexibleChildrenLength-1; vIterator>=0; vIterator--) + { + vCurrentChild = vFlexibleChildren[vIterator]; + vCurrentChild._computedHeightFlexValue += vCurrentAllocationSum / vFactorSum * vCurrentChild._computedHeightParsed; + + if (vCurrentChild._allocationLoops == vMinAllocationLoops) + { + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightFlexValue); + + vUsedHeight += vCurrentChild._computedHeightFlexValue; + delete vCurrentChild._allocationLoops; + qx.lang.Array.removeAt(vFlexibleChildren, vIterator); + } + else + { + if (vAllocationDiff == 0) + { + vCurrentChild._computedHeightFlexValue = Math.round(vCurrentChild._computedHeightFlexValue); + vUsedHeight += vCurrentChild._computedHeightFlexValue; + delete vCurrentChild._allocationLoops; + } + else + { + vCurrentChild._allocationLoops -= vMinAllocationLoops; + } + } + } + } + } + } + + // ************************************************************* + // 7. Fix rounding errors + // ************************************************************* + vCurrentChild._computedHeightFlexValue += vAvailHeight - vUsedHeight; +} + +qx.Proto.invalidateChildrenFlexHeight = function() { + delete this._childrenFlexHeightComputed; +} + + + + + +/* +--------------------------------------------------------------------------- + [03] COMPUTE NEEDED DIMENSIONS FOR ALL CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + Compute and return the height needed by all children of this widget +*/ +qx.Proto.computeChildrenNeededHeight = function() +{ + var w = this.getWidget(); + return qx.renderer.layout.LayoutImpl.prototype.computeChildrenNeededHeight_sum.call(this) + ((w.getVisibleChildrenLength()-1) * w.getSpacing()); +} + + + + + + +/* +--------------------------------------------------------------------------- + [04] UPDATE LAYOUT WHEN A CHILD CHANGES ITS OUTER DIMENSIONS +--------------------------------------------------------------------------- +*/ + +/*! + Things to do and layout when any of the childs changes its outer height. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateSelfOnChildOuterHeightChange = function(vChild) +{ + // if a childrens outer height changes we need to update our accumulated + // height of all childrens (used for middle or bottom alignments) + this.getWidget()._invalidateAccumulatedChildrenOuterHeight(); +} + + + + + +/* +--------------------------------------------------------------------------- + [05] UPDATE CHILD ON INNER DIMENSION CHANGES OF LAYOUT +--------------------------------------------------------------------------- +*/ + +/*! + Actions that should be done if the inner width of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerWidthChange = function(vChild) +{ + // use variables here to be sure to call both methods. + var vUpdatePercent = vChild._recomputePercentX(); + var vUpdateStretch = vChild._recomputeStretchingX(); + + // priority to childs internal alignment + if ((vChild.getHorizontalAlign() || this.getWidget().getHorizontalChildrenAlign()) == "center") { + vChild.addToLayoutChanges("locationX"); + } + + // inform the caller if there were any notable changes occured + return vUpdatePercent || vUpdateStretch; +} + +/*! + Actions that should be done if the inner height of the widget was changed. + Normally this includes update to percent values and ranges. +*/ +qx.Proto.updateChildOnInnerHeightChange = function(vChild) +{ + if (this.getWidget().getVerticalChildrenAlign() == "middle") { + vChild.addToLayoutChanges("locationY"); + } + + // use variables here to be sure to call both methods. + var vUpdatePercent = vChild._recomputePercentY(); + var vUpdateFlex = vChild._recomputeFlexY(); + + // inform the caller if there were any notable changes occured + return vUpdatePercent || vUpdateFlex; +} + + + + + + + +/* +--------------------------------------------------------------------------- + [06] UPDATE LAYOUT ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Invalidate and recompute things because of job in queue (before the rest of job handling will be executed). +*/ +qx.Proto.updateSelfOnJobQueueFlush = function(vJobQueue) +{ + if (vJobQueue.addChild || vJobQueue.removeChild) { + this.getWidget()._invalidateAccumulatedChildrenOuterHeight(); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + [07] UPDATE CHILDREN ON JOB QUEUE FLUSH +--------------------------------------------------------------------------- +*/ + +/*! + Updates children on special jobs +*/ +qx.Proto.updateChildrenOnJobQueueFlush = function(vQueue) +{ + var vStretchX=false, vStretchY=false; + var vWidget = this.getWidget(); + + // switching the orientation need updates for stretching on both axis + if (vQueue.orientation) { + vStretchX = vStretchY = true; + } + + // different updates depending from the current orientation (or the new one) + if (vQueue.spacing || vQueue.orientation || vQueue.reverseChildrenOrder || vQueue.verticalChildrenAlign) { + vWidget._addChildrenToLayoutQueue("locationY"); + } + + if (vQueue.horizontalChildrenAlign) { + vWidget._addChildrenToLayoutQueue("locationX"); + } + + if (vQueue.stretchChildrenOrthogonalAxis) { + vStretchX = true; + } + + // if stretching should be reworked reset the previous one and add + // a layout job to update the width respectively height. + if (vStretchX) + { + vWidget._recomputeChildrenStretchingX(); + vWidget._addChildrenToLayoutQueue("width"); + } + + if (vStretchY) + { + vWidget._recomputeChildrenStretchingY(); + vWidget._addChildrenToLayoutQueue("height"); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + [08] CHILDREN ADD/REMOVE/MOVE HANDLING +--------------------------------------------------------------------------- +*/ + +/*! + This method combines calls of methods which should be done if a widget should be removed from the current layout. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnRemoveChild = function(vChild, vIndex) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i=-1; + + // Fix index to be at the first flex child + if (this.getEnableFlexSupport()) + { + for (var i=0; i<chl; i++) + { + chc = ch[i]; + if (chc.getHasFlexY()) + { + vIndex = Math.min(vIndex, i); + break; + } + } + + i=-1; + } + + // Handle differently depending on layout mode + switch(w.getLayoutMode()) + { + case "bottom": + case "top-reversed": + while((chc=ch[++i]) && i<vIndex) { + chc.addToLayoutChanges("locationY"); + } + + break; + + case "middle": + case "middle-reversed": + while(chc=ch[++i]) { + chc.addToLayoutChanges("locationY"); + } + + break; + + default: + i+=vIndex; + while(chc=ch[++i]) { + chc.addToLayoutChanges("locationY"); + } + } +} + +/*! + This method combines calls of methods which should be done if a child should be moved + inside the same parent to a new positions. + Needed by layouts where the children depends on each-other, like flow- or box-layouts. +*/ +qx.Proto.updateChildrenOnMoveChild = function(vChild, vIndex, vOldIndex) +{ + var vChildren = this.getWidget().getVisibleChildren(); + + var vStart = Math.min(vIndex, vOldIndex); + var vStop = Math.max(vIndex, vOldIndex)+1; + + for (var i=vStart; i<vStop; i++) { + vChildren[i].addToLayoutChanges("locationY"); + } +} + + + + + +/* +--------------------------------------------------------------------------- + [09] FLUSH LAYOUT QUEUES OF CHILDREN +--------------------------------------------------------------------------- +*/ + +/*! + This method have full control of the order in which the + registered (or also non-registered) children should be + layouted on the horizontal axis. +*/ +qx.Proto.flushChildrenQueue = function(vChildrenQueue) +{ + var w=this.getWidget(), ch=w.getVisibleChildren(), chl=ch.length, chc, i; + + // This block is needed for flex handling and + // will inform flex children if there was any + // change to the other content + if (this.getEnableFlexSupport()) + { + this.invalidateChildrenFlexHeight(); + + for (i=0; i<chl; i++) + { + chc = ch[i]; + if (chc.getHasFlexY()) + { + chc._computedHeightValue = null; + + if (chc._recomputeBoxHeight()) + { + chc._recomputeOuterHeight(); + chc._recomputeInnerHeight(); + } + + vChildrenQueue[chc.toHashCode()] = chc; + chc._layoutChanges.height = true; + } + } + } + + switch(w.getLayoutMode()) + { + case "bottom": + case "top-reversed": + // find the last child which has a layout request + for (var i=chl-1; i>=0 && !vChildrenQueue[ch[i].toHashCode()]; i--) {} + + // layout all children before this last child + for (var j=0; j<=i; j++) { + w._layoutChild(chc=ch[j]); + } + + break; + + case "middle": + case "middle-reversed": + // re-layout all children + i = -1; + while(chc=ch[++i]) { + w._layoutChild(chc); + } + + break; + + default: + // layout all childs from the first child + // with an own layout request to the end + i = -1; + var changed=false; + while(chc=ch[++i]) + { + if (changed || vChildrenQueue[chc.toHashCode()]) + { + w._layoutChild(chc); + changed = true; + } + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + [10] LAYOUT CHILD +--------------------------------------------------------------------------- +*/ + +/*! + This is called from qx.ui.core.Widget and it's task is to apply the layout + (excluding border and padding) to the child. +*/ +qx.Proto.layoutChild = function(vChild, vJobs) +{ + this.layoutChild_sizeX(vChild, vJobs); + this.layoutChild_sizeY(vChild, vJobs); + + this.layoutChild_sizeLimitX(vChild, vJobs); + this.layoutChild_sizeLimitY(vChild, vJobs); + + this.layoutChild_locationX(vChild, vJobs); + this.layoutChild_locationY(vChild, vJobs); + + this.layoutChild_marginX(vChild, vJobs); + this.layoutChild_marginY(vChild, vJobs); +} + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera() || qx.core.Client.getInstance().isWebkit()) +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width || vJobs.minWidth || vJobs.maxWidth) + { + if ((vChild._isWidthEssential() && (!vChild._computedWidthTypeNull || !vChild._computedMinWidthTypeNull || !vChild._computedMaxWidthTypeNull)) || (vChild.getAllowStretchX() && this.getWidget().getStretchChildrenOrthogonalAxis())) + { + vChild._applyRuntimeWidth(vChild.getBoxWidth()); + } + else + { + vChild._resetRuntimeWidth(); + } + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height || vJobs.minHeight || vJobs.maxHeight) + { + if (vChild._isHeightEssential() && (!vChild._computedHeightTypeNull || !vChild._computedMinHeightTypeNull || !vChild._computedMaxHeightTypeNull)) + { + vChild._applyRuntimeHeight(vChild.getBoxHeight()); + } + else + { + vChild._resetRuntimeHeight(); + } + } + } +} +else +{ + qx.Proto.layoutChild_sizeX = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.width) + { + if (vChild._isWidthEssential() && !vChild._computedWidthTypeNull) + { + vChild._applyRuntimeWidth(vChild.getWidthValue()); + } + else + { + vChild._resetRuntimeWidth(); + } + } + } + + qx.Proto.layoutChild_sizeY = function(vChild, vJobs) + { + if (vJobs.initial || vJobs.height) + { + if (vChild._isHeightEssential() && !vChild._computedHeightTypeNull) + { + vChild._applyRuntimeHeight(vChild.getHeightValue()); + } + else + { + vChild._resetRuntimeHeight(); + } + } + } +} + +qx.Proto.layoutChild_locationY = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + // handle first child + if (vWidget.getFirstVisibleChild() == vChild) + { + switch(vWidget.getLayoutMode()) + { + case "bottom": + case "top-reversed": + var vPos = vWidget.getPaddingBottom() + vWidget.getAccumulatedChildrenOuterHeight() - vChild.getOuterHeight(); + break; + + case "middle": + case "middle-reversed": + var vPos = vWidget.getPaddingTop() + Math.round((vWidget.getInnerHeight() - vWidget.getAccumulatedChildrenOuterHeight()) / 2); + break; + + default: + var vPos = vWidget.getPaddingTop(); + } + } + + // handle any following child + else + { + var vPrev = vChild.getPreviousVisibleSibling(); + + switch(vWidget.getLayoutMode()) + { + case "bottom": + case "top-reversed": + var vPos = vPrev._cachedLocationVertical - vChild.getOuterHeight() - vWidget.getSpacing(); + break; + + default: + var vPos = vPrev._cachedLocationVertical + vPrev.getOuterHeight() + vWidget.getSpacing(); + } + } + + // store for next sibling + vChild._cachedLocationVertical = vPos; + + // apply styles + switch(this.getWidget().getLayoutMode()) + { + case "bottom": + case "bottom-reversed": + case "middle-reversed": + // add relative positions (like 'position:relative' in css) + vPos += !vChild._computedBottomTypeNull ? vChild.getBottomValue() : !vChild._computedTopTypeNull ? -(vChild.getTopValue()) : 0; + + vChild._resetRuntimeTop(); + vChild._applyRuntimeBottom(vPos); + break; + + default: + // add relative positions (like 'position:relative' in css) + vPos += !vChild._computedTopTypeNull ? vChild.getTopValue() : !vChild._computedBottomTypeNull ? -(vChild.getBottomValue()) : 0; + + vChild._resetRuntimeBottom(); + vChild._applyRuntimeTop(vPos); + } +} + +qx.Proto.layoutChild_locationX = function(vChild, vJobs) +{ + var vWidget = this.getWidget(); + + // special stretching support + if (qx.core.Client.getInstance().isGecko() && vChild.getAllowStretchX() && vWidget.getStretchChildrenOrthogonalAxis() && vChild._computedWidthTypeNull) + { + vChild._applyRuntimeLeft(vWidget.getPaddingLeft() || 0); + vChild._applyRuntimeRight(vWidget.getPaddingRight() || 0); + + return; + } + + // priority to childs internal alignment + var vAlign = vChild.getHorizontalAlign() || vWidget.getHorizontalChildrenAlign(); + + // handle center alignment + var vPos = vAlign == "center" ? Math.round((vWidget.getInnerWidth() - vChild.getOuterWidth()) / 2) : 0; + + // the right alignment use the real 'right' styleproperty to + // use the best available method in modern browsers + if (vAlign == "right") + { + // add parent padding + vPos += vWidget.getPaddingRight(); + + // relative positions (like 'position:relative' in css) + if (!vChild._computedRightTypeNull) { + vPos += vChild.getRightValue(); + } + else if (!vChild._computedLeftTypeNull) { + vPos -= vChild.getLeftValue(); + } + + // apply styles + vChild._resetRuntimeLeft(); + vChild._applyRuntimeRight(vPos); + } + else + { + // add parent padding + vPos += vWidget.getPaddingLeft(); + + // relative positions (like 'position:relative' in css) + if (!vChild._computedLeftTypeNull) { + vPos += vChild.getLeftValue(); + } + else if (!vChild._computedRightTypeNull) { + vPos -= vChild.getRightValue(); + } + + // apply styles + vChild._resetRuntimeRight(); + vChild._applyRuntimeLeft(vPos); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/AppearanceTheme.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/AppearanceTheme.js new file mode 100644 index 0000000000..cea49e86ab --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/AppearanceTheme.js @@ -0,0 +1,216 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/** + * Appearance Theme + * + * @param vTitle {String} anme of the appearance + */ +qx.OO.defineClass("qx.renderer.theme.AppearanceTheme", qx.core.Object, +function(vTitle) +{ + qx.core.Object.call(this); + + this.setTitle(vTitle); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** name of the theme */ +qx.OO.addProperty({ name : "title", type : "string", allowNull : false, defaultValue : "" }); + + + + + +/* +--------------------------------------------------------------------------- + DATA +--------------------------------------------------------------------------- +*/ + +qx.Proto._appearances = {}; + + + + + +/* +--------------------------------------------------------------------------- + CORE METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Register an appearance for a given id + * + * vData has the following structure: + * <pre> + * { + * setup : function() {} + * initial : function(vTheme) {} + * state : function(vTheme, vStates) {} + * } + * </pre> + * @param vId {String} id of the apperance (e.g. "button", "label", ...) + * @param vData {Map} + */ +qx.Proto.registerAppearance = function(vId, vData) { + this._appearances[vId] = vData; +}; + + +/** + * Return the apperance object for a specific apperance id. + * + * @param vId {String} id of the apperance (e.g. "button", "label", ...) + * @return {Object} appearance map + */ +qx.Proto.getAppearance = function(vId) { + return this._appearances[vId]; +} + + +/** + * Call the "setup" function of the apperance + * + * @param vAppearance {Object} appearance map + */ +qx.Proto.setupAppearance = function(vAppearance) +{ + if (!vAppearance._setupDone) + { + if (vAppearance.setup) { + vAppearance.setup(this); + } + + vAppearance._setupDone = true; + } +}; + + + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Get the result of the "initial" function for a given id + * + * @param vId {String} id of the apperance (e.g. "button", "label", ...) + * @return {Map} map of widget properties as returned by the "initial" function + */ +qx.Proto.initialFrom = function(vId) +{ + var vAppearance = this.getAppearance(vId); + if (vAppearance) + { + this.setupAppearance(vAppearance); + + try + { + return vAppearance.initial ? vAppearance.initial(this) : {} + } + catch(ex) + { + this.error("Couldn't apply initial appearance", ex); + } + } + else + { + return this.error("Missing appearance: " + vId); + } +}; + + +/** + * Get the result of the "state" function for a given id and states + * + * @param vId {String} id of the apperance (e.g. "button", "label", ...) + * @param vStates {Map} hash map defining the set states + * @return {Map} map of widget properties as returned by the "state" function + */ +qx.Proto.stateFrom = function(vId, vStates) +{ + var vAppearance = this.getAppearance(vId); + if (vAppearance) + { + this.setupAppearance(vAppearance); + + try + { + return vAppearance.state ? vAppearance.state(this, vStates) : {} + } + catch(ex) + { + this.error("Couldn't apply state appearance", ex); + } + } + else + { + return this.error("Missing appearance: " + vId); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Disposer + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._appearances = null; + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/ColorTheme.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/ColorTheme.js new file mode 100644 index 0000000000..a8ad292443 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/ColorTheme.js @@ -0,0 +1,134 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#after(qx.manager.object.ColorManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.theme.ColorTheme", qx.core.Object, +function(vTitle) +{ + qx.core.Object.call(this); + + this._compiledColors = {}; + this.setTitle(vTitle); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "title", type : "string", allowNull : false, defaultValue : "" }); + + + + + +/* +--------------------------------------------------------------------------- + DATA +--------------------------------------------------------------------------- +*/ + +qx.Proto._needsCompilation = true; +qx.Proto._colors = {}; + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getValueByName = function(vName) { + return this._colors[vName] || ""; +} + +qx.Proto.getStyleByName = function(vName) { + return this._compiledColors[vName] || ""; +} + + + + + + +/* +--------------------------------------------------------------------------- + PRIVATE METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.compile = function() +{ + if (!this._needsCompilation) { + return; + } + + for (var vName in qx.renderer.color.Color.themedNames) { + this._compileValue(vName); + } + + this._needsCompilation = false; +} + +qx.Proto._compileValue = function(vName) +{ + var v = this._colors[vName]; + this._compiledColors[vName] = v ? qx.renderer.color.Color.rgb2style.apply(this, this._colors[vName]) : vName; +} + +qx.Proto._register = function() { + return qx.manager.object.ColorManager.getInstance().registerTheme(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._colors; + delete this._compiledColors; + + qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/IconTheme.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/IconTheme.js new file mode 100644 index 0000000000..d45384376b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/IconTheme.js @@ -0,0 +1,36 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#after(qx.manager.object.ImageManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.theme.IconTheme", qx.core.Object, +function(vTitle) +{ + qx.core.Object.call(this); + + this.setTitle(vTitle); +}); + +qx.OO.addProperty({ name : "title", type : "string", allowNull : false, defaultValue : "" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/WidgetTheme.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/WidgetTheme.js new file mode 100644 index 0000000000..914c8dbbd1 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/renderer/theme/WidgetTheme.js @@ -0,0 +1,36 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#after(qx.manager.object.ImageManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.renderer.theme.WidgetTheme", qx.core.Object, +function(vTitle) +{ + qx.core.Object.call(this); + + this.setTitle(vTitle); +}); + +qx.OO.addProperty({ name : "title", type : "string", allowNull : false, defaultValue : "" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/appearance/Classic.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/appearance/Classic.js new file mode 100644 index 0000000000..9e8d0e702b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/appearance/Classic.js @@ -0,0 +1,2229 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Til Schneider (til132) + + ************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_appearance) +#require(qx.manager.object.AppearanceManager) +#optional(qx.renderer.color.Color) +#optional(qx.renderer.color.ColorObject) +#optional(qx.renderer.border.Border) +#optional(qx.renderer.border.BorderObject) +#optional(qx.renderer.font.Font) +#optional(qx.renderer.font.FontObject) +#embed(qx.static/image/dotted_white.gif) +#embed(qx.static/image/blank.gif) + + ************************************************************************ */ + +/** + * The default qooxdoo appearance theme. + * + * @param vTitle {String?"qooxdoo default appearance"} appearance title + */ +qx.OO.defineClass("qx.theme.appearance.Classic", qx.renderer.theme.AppearanceTheme, +function(vTitle) { + qx.renderer.theme.AppearanceTheme.call(this, vTitle || "qooxdoo default appearance"); +}); + + + + +qx.Proto._appearances = qx.lang.Object.carefullyMergeWith( { + /* + --------------------------------------------------------------------------- + CORE + --------------------------------------------------------------------------- + */ + + "image" : { + initial : function(vTheme) { + return { + allowStretchX : false, + allowStretchY : false + } + } + }, + + "client-document" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + this.color = new qx.renderer.color.ColorObject("windowtext"); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.bgcolor, + color : this.color, + hideFocus : true, + enableElementFocus : false + } + } + }, + + "blocker" : { + initial : function(vTheme) { + // You could also use: "static/image/dotted_white.gif" for example as backgroundImage here + // (Visible) background tiles could be dramatically slow down mshtml! + // A background image or color is always needed for mshtml to block the events successfully. + return { + cursor : "default", + backgroundImage : "static/image/blank.gif" + } + } + }, + + "atom" : { + initial : function(vTheme) { + return { + cursor : "default", + spacing : 4, + width : "auto", + height : "auto", + horizontalChildrenAlign : "center", + verticalChildrenAlign : "middle", + stretchChildrenOrthogonalAxis : false, + allowStretchY : false, + allowStretchX : false + } + } + }, + + "label" : { + setup : function() { + this.color_disabled = new qx.renderer.color.ColorObject("graytext"); + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + }, + + initial : function(vTheme) { + return { + font: this.font, + wrap : false + } + }, + + state : function(vTheme, vStates) { + return { + color : vStates.disabled ? this.color_disabled : null + } + } + }, + + "htmlcontainer" : { + initial : function(vTheme) { + return vTheme.initialFrom("label"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("label", vStates); + } + }, + + "popup" : { + initial : function(vTheme) { + return { + width : "auto", + height : "auto" + } + } + }, + + "tool-tip" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("InfoBackground"); + this.color = new qx.renderer.color.ColorObject("InfoText"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("popup"), { + backgroundColor : this.bgcolor, + color : this.color, + border : qx.renderer.border.BorderPresets.getInstance().info, + paddingTop : 1, + paddingRight : 3, + paddingBottom : 2, + paddingLeft : 3 + }); + } + }, + + "iframe" : { + initial : function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().inset + } + } + }, + + + + + + + /* + --------------------------------------------------------------------------- + BUTTON + --------------------------------------------------------------------------- + */ + + "button" : { + setup : function() { + this.bgcolor_default = new qx.renderer.color.ColorObject("buttonface"); + this.bgcolor_over = new qx.renderer.color.Color("#87BCE5"); + this.bgcolor_left = new qx.renderer.color.Color("#FFF0C9"); + + this.border_pressed = qx.renderer.border.BorderPresets.getInstance().inset; + this.border_default = qx.renderer.border.BorderPresets.getInstance().outset; + }, + + initial : function(vTheme) { + return vTheme.initialFrom("atom"); + }, + + state : function(vTheme, vStates) { + var vReturn = { + backgroundColor : vStates.abandoned ? this.bgcolor_left : vStates.over ? this.bgcolor_over : this.bgcolor_default, + border : vStates.pressed || vStates.checked || vStates.abandoned ? this.border_pressed : this.border_default + } + + if (vStates.pressed || vStates.abandoned) { + vReturn.paddingTop = 4; + vReturn.paddingRight = 3; + vReturn.paddingBottom = 2; + vReturn.paddingLeft = 5; + } + else { + vReturn.paddingTop = vReturn.paddingBottom = 3; + vReturn.paddingRight = vReturn.paddingLeft = 4; + } + + return vReturn; + } + }, + + + + + + + + + /* + --------------------------------------------------------------------------- + TOOLBAR + --------------------------------------------------------------------------- + */ + + "toolbar" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + }, + + initial : function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().thinOutset, + backgroundColor : this.bgcolor, + height : "auto" + } + } + }, + + "toolbar-part" : { + initial : function(vTheme) { + return { + width : "auto" + } + } + }, + + "toolbar-part-handle" : { + initial : function(vTheme) { + return { + width : 10 + } + } + }, + + "toolbar-part-handle-line" : { + initial : function(vTheme) { + return { + top : 2, + left : 3, + bottom : 2, + width : 4, + border : qx.renderer.border.BorderPresets.getInstance().thinOutset + } + } + }, + + "toolbar-separator" : { + initial : function(vTheme) { + return { + width : 8 + } + } + }, + + "toolbar-separator-line" : { + setup : function() { + var b = this.border = new qx.renderer.border.BorderObject; + + b.setLeftColor("threedshadow"); + b.setRightColor("threedhighlight"); + + b.setLeftStyle("solid"); + b.setRightStyle("solid"); + + b.setLeftWidth(1); + b.setRightWidth(1); + b.setTopWidth(0); + b.setBottomWidth(0); + }, + + initial : function(vTheme) { + return { + top : 2, + left: 3, + width : 2, + bottom : 2, + border : this.border + } + } + }, + + "toolbar-button" : { + setup : function() { + this.bgcolor_default = new qx.renderer.color.ColorObject("buttonface"); + this.bgcolor_left = new qx.renderer.color.Color("#FFF0C9"); + + this.border_pressed = qx.renderer.border.BorderPresets.getInstance().thinInset; + this.border_over = qx.renderer.border.BorderPresets.getInstance().thinOutset; + this.border_default = qx.renderer.border.BorderPresets.getInstance().none; + + this.checked_background = "static/image/dotted_white.gif"; + }, + + initial : function(vTheme) { + return { + cursor : "default", + spacing : 4, + width : "auto", + verticalChildrenAlign : "middle" + } + }, + + state : function(vTheme, vStates) { + var vReturn = { + backgroundColor : vStates.abandoned ? this.bgcolor_left : this.bgcolor_default, + backgroundImage : vStates.checked && !vStates.over ? this.checked_background : null + } + + if (vStates.pressed || vStates.checked || vStates.abandoned) { + vReturn.border = this.border_pressed; + + vReturn.paddingTop = 3; + vReturn.paddingRight = 2; + vReturn.paddingBottom = 1; + vReturn.paddingLeft = 4; + } else if (vStates.over) { + vReturn.border = this.border_over; + + vReturn.paddingTop = vReturn.paddingBottom = 2; + vReturn.paddingLeft = vReturn.paddingRight = 3; + } else { + vReturn.border = this.border_default; + + vReturn.paddingTop = vReturn.paddingBottom = 3; + vReturn.paddingLeft = vReturn.paddingRight = 4; + } + + return vReturn; + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + BAR VIEW + --------------------------------------------------------------------------- + */ + + "bar-view" : { + setup : function() { + this.background = new qx.renderer.color.ColorObject("#FAFBFE"); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.background, + border : qx.renderer.border.BorderPresets.getInstance().shadow + } + } + }, + + "bar-view-pane" : { + state : function(vTheme, vStates) { + if (vStates.barHorizontal) { + return { + width : null, + height : "1*" + } + } + else { + return { + width : "1*", + height : null + } + } + } + }, + + "bar-view-page" : { + initial : function(vTheme) { + return { + left : 10, + right : 10, + top : 10, + bottom : 10 + } + } + }, + + "bar-view-bar" : { + setup : function() { + this.background_color = new qx.renderer.color.ColorObject("#E1EEFF"); + + this.border_color = new qx.renderer.color.ColorObject("threedshadow"); + + this.border_top = new qx.renderer.border.BorderObject; + this.border_top.setBottom(1, "solid", this.border_color); + + this.border_bottom = new qx.renderer.border.BorderObject; + this.border_bottom.setTop(1, "solid", this.border_color); + + this.border_left = new qx.renderer.border.BorderObject; + this.border_left.setRight(1, "solid", this.border_color); + + this.border_right = new qx.renderer.border.BorderObject; + this.border_right.setLeft(1, "solid", this.border_color); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.background_color + } + }, + + state : function(vTheme, vStates) { + if (vStates.barTop) { + return { + paddingTop : 1, + paddingRight : 0, + paddingBottom : 1, + paddingLeft : 0, + + border : this.border_top, + height : "auto", + width : null, + orientation : "horizontal" + }; + } + else if (vStates.barBottom) { + return { + paddingTop : 1, + paddingRight : 0, + paddingBottom : 1, + paddingLeft : 0, + + border : this.border_bottom, + height : "auto", + width : null, + orientation : "horizontal" + }; + } + else if (vStates.barLeft) { + return { + paddingTop : 0, + paddingRight : 1, + paddingBottom : 0, + paddingLeft : 1, + + border : this.border_left, + height : null, + width : "auto", + orientation : "vertical" + }; + } + else if (vStates.barRight) { + return { + paddingTop : 0, + paddingRight : 1, + paddingBottom : 0, + paddingLeft : 1, + + border : this.border_right, + height : null, + width : "auto", + orientation : "vertical" + }; + } + } + }, + + "bar-view-button" : { + setup : function() { + this.background_color_normal = null; + this.background_color_checked = new qx.renderer.color.ColorObject("#FAFBFE"); + + this.border_color = new qx.renderer.color.ColorObject("threedshadow"); + this.border_color_checked = new qx.renderer.color.ColorObject("#FEC83C"); + + this.border_top_checked = new qx.renderer.border.Border(1, "solid", this.border_color); + this.border_top_checked.setBottom(3, "solid", this.border_color_checked); + + this.border_bottom_checked = new qx.renderer.border.Border(1, "solid", this.border_color); + this.border_bottom_checked.setTop(3, "solid", this.border_color_checked); + + this.border_left_checked = new qx.renderer.border.Border(1, "solid", this.border_color); + this.border_left_checked.setRight(3, "solid", this.border_color_checked); + + this.border_right_checked = new qx.renderer.border.Border(1, "solid", this.border_color); + this.border_right_checked.setLeft(3, "solid", this.border_color_checked); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("atom"), { + iconPosition : "top" + }); + }, + + state : function(vTheme, vStates) { + var vReturn = { + backgroundColor : vStates.checked ? this.background_color_checked : this.background_color_normal, + allowStretchX : true, + allowStretchY : true + } + + if (vStates.checked || vStates.over) { + if (vStates.barTop) { + vReturn.border = this.border_top_checked; + vReturn.paddingTop = 3; + vReturn.paddingRight = 6; + vReturn.paddingBottom = 1; + vReturn.paddingLeft = 6; + } + else if (vStates.barBottom) { + vReturn.border = this.border_bottom_checked; + vReturn.paddingTop = 1; + vReturn.paddingRight = 6; + vReturn.paddingBottom = 3; + vReturn.paddingLeft = 6; + } + else if (vStates.barLeft) { + vReturn.border = this.border_left_checked; + vReturn.paddingTop = 3; + vReturn.paddingRight = 4; + vReturn.paddingBottom = 3; + vReturn.paddingLeft = 6; + } + else if (vStates.barRight) { + vReturn.border = this.border_right_checked; + vReturn.paddingTop = 3; + vReturn.paddingRight = 6; + vReturn.paddingBottom = 3; + vReturn.paddingLeft = 4; + } + } + else { + vReturn.border = qx.renderer.border.BorderPresets.getInstance().none; + vReturn.paddingTop = vReturn.paddingBottom = 4; + vReturn.paddingRight = vReturn.paddingLeft = 7; + } + + if (vStates.barTop || vStates.barBottom) { + vReturn.marginTop = vReturn.marginBottom = 0; + vReturn.marginRight = vReturn.marginLeft = 1; + vReturn.width = "auto"; + vReturn.height = null; + } + else if (vStates.barLeft || vStates.barRight) { + vReturn.marginTop = vReturn.marginBottom = 1; + vReturn.marginRight = vReturn.marginLeft = 0; + vReturn.height = "auto"; + vReturn.width = null; + } + + return vReturn; + } + }, + + + + + + + + + + /* + --------------------------------------------------------------------------- + WINDOW + --------------------------------------------------------------------------- + */ + + "window" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + this.color = new qx.renderer.color.ColorObject("windowtext"); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.bgcolor, + color : this.color, + paddingTop : 1, + paddingRight : 1, + paddingBottom : 1, + paddingLeft : 1 + } + }, + + state : function(vTheme, vStates) { + return { + border : vStates.maximized ? qx.renderer.border.BorderPresets.getInstance().none : qx.renderer.border.BorderPresets.getInstance().outset + } + } + }, + + "window-captionbar" : { + setup : function() { + this.bgcolor_active = new qx.renderer.color.ColorObject("activecaption"); + this.color_active = new qx.renderer.color.ColorObject("captiontext"); + this.bgcolor_inactive = new qx.renderer.color.ColorObject("inactivecaption"); + this.color_inactive = new qx.renderer.color.ColorObject("inactivecaptiontext"); + }, + + initial : function(vTheme) { + return { + paddingTop : 1, + paddingRight : 2, + paddingBottom : 2, + paddingLeft : 2, + verticalChildrenAlign : "middle", + height : "auto", + overflow : "hidden" + } + }, + + state : function(vTheme, vStates) { + return { + backgroundColor : vStates.active ? this.bgcolor_active : this.bgcolor_inactive, + color : vStates.active ? this.color_active : this.color_inactive + } + } + }, + + "window-resize-frame" : { + initial : function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().shadow + } + } + }, + + "window-captionbar-icon" : { + initial : function(vTheme) { + return { + marginRight : 2 + } + } + }, + + "window-captionbar-title" : { + setup : function() { + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + this.font.setBold(true); + }, + + initial : function(vTheme) { + return { + cursor : "default", + font : this.font, + marginRight : 2, + wrap : false + } + } + }, + + "window-captionbar-button" : { + initial : function(vTheme) { + return vTheme.initialFrom("button"); + }, + + state : function(vTheme, vStates) { + var vReturn = vTheme.stateFrom("button", vStates); + + if (vStates.pressed || vStates.abandoned) { + vReturn.paddingTop = 2; + vReturn.paddingRight = 1; + vReturn.paddingBottom = 0; + vReturn.paddingLeft = 3; + } + else { + vReturn.paddingTop = vReturn.paddingBottom = 1; + vReturn.paddingRight = vReturn.paddingLeft = 2; + } + + return vReturn; + } + }, + + "window-captionbar-minimize-button" : { + initial : function(vTheme) { + return vTheme.initialFrom("window-captionbar-button"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("window-captionbar-button", vStates); + } + }, + + "window-captionbar-restore-button" : { + initial : function(vTheme) { + return vTheme.initialFrom("window-captionbar-button"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("window-captionbar-button", vStates); + } + }, + + "window-captionbar-maximize-button" : { + initial : function(vTheme) { + return vTheme.initialFrom("window-captionbar-button"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("window-captionbar-button", vStates); + } + }, + + "window-captionbar-close-button" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("window-captionbar-button"), { + marginLeft : 2 + }); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("window-captionbar-button", vStates); + } + }, + + "window-statusbar" : { + initial : function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().thinInset, + height : "auto" + } + } + }, + + "window-statusbar-text" : { + initial : function(vTheme) { + return { + paddingTop : 1, + paddingRight : 4, + paddingBottom : 1, + paddingLeft : 4, + cursor : "default" + } + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + RESIZER + --------------------------------------------------------------------------- + */ + + "resizer": { + initial: function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().outset + } + } + }, + + "resizer-frame" : { + initial : function(vTheme) { + return { + border : qx.renderer.border.BorderPresets.getInstance().shadow + } + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + MENU + --------------------------------------------------------------------------- + */ + + "menu" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("menu"); + }, + + initial : function(vTheme) { + return { + width : "auto", + height : "auto", + backgroundColor : this.bgcolor, + border : qx.renderer.border.BorderPresets.getInstance().outset, + paddingTop : 1, + paddingRight : 1, + paddingBottom : 1, + paddingLeft : 1 + } + } + }, + + "menu-layout" : { + initial : function(vTheme) { + return { + top : 0, + right : 0, + bottom : 0, + left : 0 + } + } + }, + + "menu-button" : { + setup : function() { + this.BGCOLOR_OVER = new qx.renderer.color.ColorObject("highlight"); + this.BGCOLOR_OUT = null; + + this.COLOR_OVER = new qx.renderer.color.ColorObject("highlighttext"); + this.COLOR_OUT = null; + }, + + initial : function(vTheme) { + return { + minWidth : "auto", + height : "auto", + spacing : 2, + paddingTop : 2, + paddingRight : 4, + paddingBottom : 2, + paddingLeft : 4, + cursor : "default", + verticalChildrenAlign : "middle", + allowStretchX : true + } + }, + + state : function(vTheme, vStates) { + return { + backgroundColor : vStates.over ? this.BGCOLOR_OVER : this.BGCOLOR_OUT, + color : vStates.over ? this.COLOR_OVER : this.COLOR_OUT + } + } + }, + + "menu-check-box" : { + initial : function(vTheme) { + return vTheme.initialFrom("menu-button"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("menu-button", vStates); + } + }, + + "menu-radio-button" : { + initial : function(vTheme) { + return vTheme.initialFrom("menu-button"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("menu-button", vStates); + } + }, + + "menu-separator" : { + initial : function(vTheme) { + return { + height : "auto", + marginTop : 3, + marginBottom : 2, + paddingLeft : 3, + paddingRight : 3 + } + } + }, + + "menu-separator-line" : { + initial : function(vTheme) { + return { + right : 0, + left : 0, + height : "auto", + border : qx.renderer.border.BorderPresets.getInstance().verticalDivider + } + } + }, + + + + + + + + + /* + --------------------------------------------------------------------------- + LIST + --------------------------------------------------------------------------- + */ + + "list" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("white"); + }, + + initial : function(vTheme) { + return { + overflow : "hidden", + border : qx.renderer.border.BorderPresets.getInstance().thinInset, + backgroundColor : this.bgcolor + } + } + }, + + "list-item" : { + setup : function() { + this.bgcolor_selected = new qx.renderer.color.ColorObject("highlight"); + this.color_selected = new qx.renderer.color.ColorObject("highlighttext"); + }, + + initial : function(vTheme) { + return { + cursor : "default", + height : "auto", + horizontalChildrenAlign : "left", + verticalChildrenAlign : "middle", + spacing : 4, + paddingTop : 3, + paddingRight : 5, + paddingBottom : 3, + paddingLeft : 5, + minWidth : "auto" + } + }, + + state : function(vTheme, vStates) { + return { + backgroundColor : vStates.selected ? this.bgcolor_selected : null, + color : vStates.selected ? this.color_selected : null + } + } + }, + + + + + + + + + /* + --------------------------------------------------------------------------- + FIELDS + --------------------------------------------------------------------------- + */ + + "text-field" : { + setup : function() { + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + }, + + initial : function(vTheme) { + return { + hideFocus : true, + border : qx.renderer.border.BorderPresets.getInstance().inset, + paddingTop : 1, + paddingRight : 3, + paddingBottom : 1, + paddingLeft : 3, + allowStretchY : false, + allowStretchX : true, + font : this.font, + width : "auto", + height : "auto" + } + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("label", vStates); + } + }, + + "text-area" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("text-field"), { + overflow : "auto", + + // gecko automatically defines a marginTop/marginBottom of 1px. We need to reset these values. + marginTop : 0, + marginBottom : 0 + }); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("text-field", vStates); + } + }, + + + + + + + + + + + /* + --------------------------------------------------------------------------- + COMBOBOX + --------------------------------------------------------------------------- + */ + + "combo-box" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("white"); + }, + + initial : function(vTheme) { + return { + minWidth : 40, + width : 120, + height : "auto", + border : qx.renderer.border.BorderPresets.getInstance().inset, + backgroundColor : this.bgcolor, + allowStretchY : false + } + } + }, + + "combo-box-ex" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("white"); + }, + + initial : function(vTheme) { + return { + width : "auto", + height : "auto", + border : qx.renderer.border.BorderPresets.getInstance().inset, + backgroundColor : this.bgcolor, + allowStretchY : false + } + } + }, + + "combo-box-list" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("list"), { + top : 0, + right : 0, + bottom : 0, + left : 0, + border : null, + overflow : "scrollY" + }); + } + }, + + "combo-box-ex-list" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("list"), { + statusBarVisible: false, + columnVisibilityButtonVisible: false, + height: 'auto', + maxHeight: 150, + top : 0, + left : 0, + border : null + }); + } + }, + + "combo-box-popup" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("list"), { + height : "auto", + maxHeight : 150, + border : qx.renderer.border.BorderPresets.getInstance().shadow + }); + } + }, + + "combo-box-ex-popup" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("list"), { + width: "auto", + height : "auto", + border : qx.renderer.border.BorderPresets.getInstance().shadow + }); + } + }, + + "combo-box-text-field" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("transparent"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("text-field"), { + border : qx.renderer.border.BorderPresets.getInstance().none, + width : "1*", + backgroundColor : this.bgcolor + }); + } + }, + + "combo-box-ex-text-field" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("transparent"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("text-field"), { + border : qx.renderer.border.BorderPresets.getInstance().none, + minWidth : 30, + width : 100, + backgroundColor : this.bgcolor + }); + } + }, + + // Used both for ComboBox and ComboBoxEx + "combo-box-button" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("button"), { + height : null, + allowStretchY : true + }); + }, + + state : function(vTheme, vStates) { + return qx.lang.Object.mergeWith(vTheme.stateFrom("button", vStates), { + paddingTop : 0, + paddingRight : 3, + paddingBottom : 0, + paddingLeft : 2 + }); + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + TREE + --------------------------------------------------------------------------- + */ + + "tree-element" : { + initial : function(vTheme) { + return { + height : 16, + verticalChildrenAlign : "middle" + } + } + }, + + "tree-element-icon" : { + initial : function(vTheme) { + return { + width : 16, + height : 16 + } + } + }, + + "tree-element-label" : { + setup : function() { + this.bgcolor_selected = new qx.renderer.color.ColorObject("highlight"); + this.color_selected = new qx.renderer.color.ColorObject("highlighttext"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("label"), { + cursor : "default", + marginLeft : 3, + height : 15, + paddingTop : 2, + paddingRight : 2, + paddingBottom : 2, + paddingLeft : 2, + allowStretchY : false + }); + }, + + state : function(vTheme, vStates) { + return qx.lang.Object.mergeWith(vTheme.stateFrom("label", vStates), { + backgroundColor : vStates.selected ? this.bgcolor_selected : null, + color : vStates.selected ? this.color_selected : null + }); + } + }, + + "tree-folder" : { + initial : function(vTheme) { + return vTheme.initialFrom("tree-element"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("tree-element", vStates); + } + }, + + "tree-folder-icon" : { + initial : function(vTheme) { + return { + width : 16, + height : 16 + } + } + }, + + "tree-folder-label" : { + initial : function(vTheme) { + return vTheme.initialFrom("tree-element-label"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("tree-element-label", vStates); + } + }, + + "tree" : { + initial : function(vTheme) { + return vTheme.initialFrom("tree-folder"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("tree-folder", vStates); + } + }, + + "tree-icon" : { + initial : function(vTheme) { + return vTheme.initialFrom("tree-folder-icon"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("tree-folder-icon", vStates); + } + }, + + "tree-label" : { + initial : function(vTheme) { + return vTheme.initialFrom("tree-folder-label"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("tree-folder-label", vStates); + } + }, + + "tree-container" : { + initial : function(vTheme) { + return { + verticalChildrenAlign : "top" + } + } + }, + + "tree-folder-container" : { + initial : function(vTheme) { + return { + height : "auto", + verticalChildrenAlign : "top" + } + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + LISTVIEW + --------------------------------------------------------------------------- + */ + + "list-view" : { + initial : function(vTheme) { + return { + cursor : "default", + overflow: "hidden" + } + } + }, + + "list-view-pane" : { + initial : function(vTheme) { + return { + width : "1*", + horizontalSpacing : 1, + overflow : "hidden" + } + } + }, + + "list-view-header" : { + setup : function() { + this.border = new qx.renderer.border.Border; + this.border.setBottom(1, "solid", "#e2e2e2"); + + this.bgcolor = new qx.renderer.color.Color("#f2f2f2"); + }, + + initial : function(vTheme) { + return { + height : "auto", + overflow: "hidden", + border : this.border, + backgroundColor : this.bgcolor + } + } + }, + + "list-view-header-cell" : { + setup : function() { + this.border_hover = new qx.renderer.border.Border; + this.border_hover.setBottom(2, "solid", "#F9B119"); + + this.bgcolor_hover = new qx.renderer.color.Color("white"); + }, + + initial : function(vTheme) { + return { + overflow : "hidden", + paddingTop : 2, + paddingRight : 6, + paddingBottom : 2, + paddingLeft : 6, + spacing : 4 + }; + }, + + state : function(vTheme, vStates) { + if (vStates.over) { + return { + backgroundColor : this.bgcolor_hover, + paddingBottom : 0, + border : this.border_hover + }; + } + else { + return { + backgroundColor : null, + paddingBottom : 2, + border : null + }; + } + } + }, + + "list-view-header-separator" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("#D6D5D9"); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.bgcolor, + width : 1, + marginTop : 1, + marginBottom : 1 + }; + } + }, + + "list-view-content-cell" : { + setup : function() { + this.bgcolor_selected = new qx.renderer.color.ColorObject("highlight"); + this.color_selected = new qx.renderer.color.ColorObject("highlighttext"); + }, + + state : function(vTheme, vStates) { + return { + backgroundColor : vStates.selected ? this.bgcolor_selected : null, + color : vStates.selected ? this.color_selected : null + }; + } + }, + + "list-view-content-cell-image" : { + initial : function(vTheme) { + return { + paddingLeft : 6, + paddingRight : 6 + }; + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("list-view-content-cell", vStates); + } + }, + + "list-view-content-cell-text" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("htmlcontainer"), { + overflow: "hidden", + paddingLeft : 6, + paddingRight : 6 + }); + }, + + state : function(vTheme, vStates) { + return qx.lang.Object.mergeWith(vTheme.stateFrom("htmlcontainer", vStates), vTheme.stateFrom("list-view-content-cell", vStates)); + } + }, + + "list-view-content-cell-html" : { + initial : function(vTheme) { + return vTheme.initialFrom("list-view-content-cell-text"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("list-view-content-cell-text", vStates); + } + }, + + "list-view-content-cell-icon-html" : { + initial : function(vTheme) { + return vTheme.initialFrom("list-view-content-cell-text"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("list-view-content-cell-text", vStates); + } + }, + + "list-view-content-cell-link" : { + initial : function(vTheme) { + return vTheme.initialFrom("list-view-content-cell-text"); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("list-view-content-cell-text", vStates); + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + TABVIEW + --------------------------------------------------------------------------- + */ + + "tab-view" : { + initial : function(vTheme) { + return { + spacing : -1 + }; + } + }, + + "tab-view-bar" : { + initial : function(vTheme) { + return { + height : "auto" + }; + } + }, + + "tab-view-pane" : { + setup : function() { + this.border = new qx.renderer.border.Border(1, "solid", "#91A5BD"); + this.bgcolor = new qx.renderer.color.ColorObject("#FAFBFE"); + }, + + initial : function(vTheme) { + return { + height : "1*", + backgroundColor : this.bgcolor, + border : this.border, + paddingTop : 10, + paddingRight : 10, + paddingBottom : 10, + paddingLeft : 10 + }; + } + }, + + "tab-view-page" : { + initial : function(vTheme) { + return { + top : 0, + right : 0, + bottom : 0, + left : 0 + }; + } + }, + + "tab-view-button" : { + setup : function() { + this.bgcolor_normal = new qx.renderer.color.ColorObject("#E1EEFF"); + this.bgcolor_checked = new qx.renderer.color.ColorObject("#FAFBFE"); + + this.border_top_normal = new qx.renderer.border.Border(1, "solid", "#91A5BD"); + this.border_top_normal.setBottomWidth(0); + + this.border_top_checked = new qx.renderer.border.Border(1, "solid", "#91A5BD"); + this.border_top_checked.setBottomWidth(0); + this.border_top_checked.setTop(3, "solid", "#FEC83C"); + + this.border_bottom_normal = new qx.renderer.border.Border(1, "solid", "#91A5BD"); + this.border_bottom_normal.setTopWidth(0); + + this.border_bottom_checked = new qx.renderer.border.Border(1, "solid", "#91A5BD"); + this.border_bottom_checked.setTopWidth(0); + this.border_bottom_checked.setBottom(3, "solid", "#FEC83C"); + }, + + initial : function(vTheme) { + return vTheme.initialFrom("atom"); + }, + + state : function(vTheme, vStates) { + var vReturn; + + if (vStates.checked) { + vReturn = { + backgroundColor : this.bgcolor_checked, + zIndex : 1, + paddingTop : 2, + paddingBottom : 4, + paddingLeft : 7, + paddingRight : 8, + border : vStates.barTop ? this.border_top_checked : this.border_bottom_checked, + marginTop : 0, + marginBottom : 0, + marginRight : -1, + marginLeft : -2 + } + + if (vStates.alignLeft) { + if (vStates.firstChild) { + vReturn.paddingLeft = 6; + vReturn.paddingRight = 7; + vReturn.marginLeft = 0; + } + } + else { + if (vStates.lastChild) { + vReturn.paddingLeft = 8; + vReturn.paddingRight = 5; + vReturn.marginRight = 0; + } + } + } + else { + vReturn = { + backgroundColor : vStates.over ? this.bgcolor_checked : this.bgcolor_normal, + zIndex : 0, + paddingTop : 2, + paddingBottom : 2, + paddingLeft : 5, + paddingRight : 6, + marginRight : 1, + marginLeft : 0 + } + + if (vStates.alignLeft) { + if (vStates.firstChild) { + vReturn.paddingLeft = 6; + vReturn.paddingRight = 5; + } + } + else { + if (vStates.lastChild) { + vReturn.paddingLeft = 6; + vReturn.paddingRight = 5; + vReturn.marginRight = 0; + } + } + + if (vStates.barTop) { + vReturn.border = this.border_top_normal; + vReturn.marginTop = 3; + vReturn.marginBottom = 1; + } + else { + vReturn.border = this.border_bottom_normal; + vReturn.marginTop = 1; + vReturn.marginBottom = 3; + } + } + + return vReturn; + } + }, + + + + + + + /* + --------------------------------------------------------------------------- + FIELDSET + --------------------------------------------------------------------------- + */ + + "field-set" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + }, + + initial : function(vTheme) { + return { + backgroundColor : this.bgcolor + } + } + }, + + "field-set-legend" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("atom"), { + top : 1, + left : 10, + backgroundColor : this.bgcolor, + paddingRight : 3, + paddingLeft : 4, + marginRight: 10 + }); + } + }, + + "field-set-frame" : { + initial : function(vTheme) { + return { + top : 8, + left : 2, + right : 2, + bottom : 2, + paddingTop : 12, + paddingRight : 9, + paddingBottom : 12, + paddingLeft : 9, + border : qx.renderer.border.BorderPresets.getInstance().groove + } + } + }, + + "check-box-field-set-legend" : { + setup : function() { + this.bgcolor = new qx.renderer.color.ColorObject("threedface"); + }, + + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("atom"), { + top : 1, + left : 10, + backgroundColor : this.bgcolor, + paddingRight : 3 + }); + } + }, + + "radio-button-field-set-legend" : { + initial : function(vTheme) { + return vTheme.initialFrom("check-box-field-set-legend"); + } + }, + + + + + + + + /* + --------------------------------------------------------------------------- + SPINNER + --------------------------------------------------------------------------- + */ + + "spinner" : { + setup : function() { + this.bgcolor = new qx.renderer.color.Color("white"); + }, + + initial : function(vTheme) { + return { + width : 60, + height : 22, + border : qx.renderer.border.BorderPresets.getInstance().inset, + backgroundColor : this.bgcolor + } + } + }, + + "spinner-field" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("text-field"), { + width : "1*", + border : qx.renderer.border.BorderPresets.getInstance().none + }); + }, + + state : function(vTheme, vStates) { + return vTheme.stateFrom("text-field", vStates); + } + }, + + "spinner-button-up" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("image"), { + height: "1*", + width: 16, + backgroundColor: new qx.renderer.color.ColorObject("threedface") + }); + }, + + state : function(vTheme, vStates) { + return qx.lang.Object.mergeWith(vTheme.stateFrom("button", vStates), { + paddingTop : 0, + paddingRight : 0, + paddingBottom: 0, + paddingLeft : 3 + }); + } + }, + + "spinner-button-down" : { + initial : function(vTheme) { + return qx.lang.Object.mergeWith(vTheme.initialFrom("image"), { + height: "1*", + width: 16, + backgroundColor: new qx.renderer.color.ColorObject("threedface") + }); + }, + + state : function(vTheme, vStates) { + return qx.lang.Object.mergeWith(vTheme.stateFrom("button", vStates), { + paddingTop : 1, + paddingRight : 0, + paddingBottom: 0, + paddingLeft : 3 + }); + } + }, + + + + + + /* + --------------------------------------------------------------------------- + COLORSELECTOR + --------------------------------------------------------------------------- + */ + + "colorselector" : { + setup : function() { + this.border = qx.renderer.border.BorderPresets.getInstance().outset; + }, + + initial : function(vTheme) { + return { + border : this.border, + width: "auto", + height: "auto" + } + }, + + state : function(vTheme, vStates) { + + } + }, + + + + + + /* + --------------------------------------------------------------------------- + DATECHOOSER + --------------------------------------------------------------------------- + */ + + "datechooser-toolbar-button" : { + setup : function() { + this.bgcolor_default = new qx.renderer.color.ColorObject("buttonface"); + this.bgcolor_left = new qx.renderer.color.Color("#FFF0C9"); + + this.border_pressed = qx.renderer.border.BorderPresets.getInstance().thinInset; + this.border_over = qx.renderer.border.BorderPresets.getInstance().thinOutset; + this.border_default = null; + + this.checked_background = "static/image/dotted_white.gif"; + }, + + initial : function(vTheme) { + return { + cursor : "default", + spacing : 4, + width : "auto", + verticalChildrenAlign : "middle" + } + }, + + state : function(vTheme, vStates) { + var vReturn = { + backgroundColor : vStates.abandoned ? this.bgcolor_left : this.bgcolor_default, + backgroundImage : (vStates.checked && !vStates.over) ? this.checked_background : null + } + + if (vStates.pressed || vStates.checked || vStates.abandoned) { + vReturn.border = this.border_pressed; + } else if (vStates.over) { + vReturn.border = this.border_over; + } else { + vReturn.border = this.border_default; + } + + if (vStates.pressed || vStates.checked || vStates.abandoned) { + vReturn.paddingTop = 2; + vReturn.paddingRight = 0; + vReturn.paddingBottom = 0; + vReturn.paddingLeft = 2; + } else if (vStates.over) { + vReturn.paddingTop = vReturn.paddingBottom = 1; + vReturn.paddingLeft = vReturn.paddingRight = 1; + } else { + vReturn.paddingTop = vReturn.paddingBottom = 2; + vReturn.paddingLeft = vReturn.paddingRight = 2; + } + + return vReturn; + } + }, + + + "datechooser-monthyear" : { + setup : function() { + this.font = new qx.renderer.font.Font(13, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + }, + + initial : function(vTheme) { + return { + font : this.font, + textAlign: "center", + verticalAlign: "middle" + } + } + }, + + + "datechooser-datepane" : { + setup : function() { + this.border = new qx.renderer.border.Border(1, "solid", "gray"); + this.bgcolor = new qx.renderer.color.ColorObject("window"); + }, + + initial : function(vTheme) { + return { + border : this.border, + backgroundColor : this.bgcolor + } + } + }, + + + "datechooser-weekday" : { + setup : function() { + this.border = new qx.renderer.border.Border; + this.border.set({ bottomColor:"gray", bottomStyle :"solid", bottomWidth:1 }); + this.color = new qx.renderer.color.ColorObject("window"); + this.bgcolor = new qx.renderer.color.ColorObject("#6285BA"); + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + this.font.setBold(true); + }, + + initial : function(vTheme) { + return { + border : this.border, + font : this.font, + textAlign : "center" + } + }, + + state : function(vTheme, vStates) { + return { + color : vStates.weekend ? this.bgcolor : this.color, + backgroundColor : vStates.weekend ? this.color : this.bgcolor + } + } + + }, + + + "datechooser-day" : { + setup : function() { + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + + this.selectedColor = new qx.renderer.color.ColorObject("highlightText"); + this.selectedBgColor = new qx.renderer.color.ColorObject("highlight"); + this.color = new qx.renderer.color.ColorObject("windowText"); + this.otherMonthColor = new qx.renderer.color.ColorObject("grayText"); + + this.transparentBorder = new qx.renderer.border.Border(1, "none"); + }, + + initial : function(vTheme) { + return { + cursor : "default", + border : this.border, + color : this.color, + font : this.font, + textAlign : "center", + verticalAlign: "middle", + selectable: false + } + }, + + state : function(vTheme, vStates) { + return { + border : vStates.today ? qx.renderer.border.BorderPresets.getInstance().black : this.transparentBorder, + color : vStates.selected ? this.selectedColor : + (vStates.otherMonth ? this.otherMonthColor : this.color), + backgroundColor : vStates.selected ? this.selectedBgColor : null + } + } + }, + + "datechooser-week" : { + setup : function() { + this.border = new qx.renderer.border.Border; + this.border.set({ rightColor:"gray", rightStyle :"solid", rightWidth:1 }); + this.headerBorder = new qx.renderer.border.Border; + this.headerBorder.set({ rightColor:"gray", rightStyle :"solid", rightWidth:1, + bottomColor:"gray", bottomStyle :"solid", bottomWidth:1 }); + this.color = new qx.renderer.color.ColorObject("#6285BA"); + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + }, + + initial : function(vTheme) { + return { + border : this.border, + font : this.font, + color: this.color, + paddingLeft : 2 + } + }, + + state : function(vTheme, vStates) { + return { + border : vStates.header ? this.headerBorder : this.border + } + } + }, + + + + + + + /* + --------------------------------------------------------------------------- + TABLE + --------------------------------------------------------------------------- + */ + + "table-focus-statusbar" : { + setup : function() { + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + this.border = new qx.renderer.border.Border; + this.border.set({ topColor:"threedshadow", topStyle :"solid", topWidth:1 }); + }, + + initial : function(vTheme) { + return { + font: this.font, + border: this.border, + paddingLeft: 2, + paddingRight: 2 + } + } + }, + + + "table-focus-indicator" : { + setup : function() { + this.border = new qx.renderer.border.Border(3, "solid", "#b3d9ff"); + this.blurBorder = new qx.renderer.border.Border(3, "solid", "#c5c8ca"); + this.editingBorder = new qx.renderer.border.Border(2, "solid", "#b3d9ff"); + }, + + state : function(vTheme, vStates) { + return { + border : vStates.editing ? this.editingBorder : (vStates.tableHasFocus ? this.border : this.blurBorder) + } + } + }, + + + "table-editor-textfield" : { + setup : function() { + this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'); + }, + + initial : function(vTheme) { + return { + font: this.font, + border: qx.renderer.border.BorderPresets.getInstance().none, + paddingLeft: 2, + paddingRight: 2, + paddingTop: 0, + paddingBottom: 0 + } + } + }, + + "table-header-cell" : { + setup : function() { + this.border = new qx.renderer.border.Border; + this.border.set({ rightColor:"#d6d2c2", rightStyle :"solid", rightWidth:1, + bottomColor:"#d6d2c2", bottomStyle :"solid", bottomWidth:2 }); + + this.mouseOverBorder = new qx.renderer.border.Border; + this.mouseOverBorder.set({ rightColor:"#d6d2c2", rightStyle :"solid", rightWidth:1, + bottomColor:"#F9B119", bottomStyle :"solid", bottomWidth:2 }); + + this.mouseOverBackground = new qx.renderer.color.ColorObject("white"); + this.background = new qx.renderer.color.ColorObject("#ebeadb"); + }, + + initial : function(vTheme) { + return { + cursor : "default", + border : this.border, + paddingLeft : 2, + paddingRight : 2, + spacing:2, + overflow:"hidden", + selectable: false, + backgroundColor:this.background, + iconPosition:"right", + verticalChildrenAlign:"middle" + } + }, + + state : function(vTheme, vStates) { + return { + backgroundColor : vStates.mouseover ? this.mouseOverBackground : this.background, + border : vStates.mouseover ? this.mouseOverBorder : this.border + } + } + }, + + + + + /* + --------------------------------------------------------------------------- + SPLITPANE + --------------------------------------------------------------------------- + */ + + "splitpane" : + { + initial : function(vTheme) + { + return { + overflow : "hidden" + } + } + }, + + "splitpane-glasspane" : + { + setup : function() { + this.background = new qx.renderer.color.ColorObject("threedshadow"); + }, + + initial : function(vTheme) + { + return { + zIndex : 1e7, + backgroundColor : this.background + } + }, + + state : function(vTheme, vStates) { + return { + opacity : vStates.visible ? 0.2 : 0 + } + } + }, + + "splitpane-splitter" : + { + initial : function(vTheme) { + return { + backgroundColor : "threedface" + } + }, + + state : function(vTheme, vStates) + { + return { + cursor : vStates.horizontal ? "col-resize" : "row-resize" + }; + } + }, + + "splitpane-slider" : + { + initial : function(vTheme) + { + return { + opacity: 0.5, + zIndex : 1e8 + } + }, + + state : function(vTheme, vStates) + { + return { + backgroundColor: vStates.dragging ? "threeddarkshadow" : "threedface" + } + } + }, + + "splitpane-knob" : + { + state : function(vTheme, vStates) + { + var vReturn = { + opacity: vStates.dragging ? 0.5 : 1.0 + } + + if (vStates.horizontal) + { + vReturn.top = "33%"; + vReturn.left = null; + vReturn.marginLeft = -6; + vReturn.marginTop = 0; + vReturn.cursor = "col-resize"; + } + else if (vStates.vertical) + { + vReturn.top = null; + vReturn.left = "33%"; + vReturn.marginTop = -6; + vReturn.marginLeft = 0; + vReturn.cursor = "row-resize"; + } + + return vReturn; + } + } + + + + + /* + --------------------------------------------------------------------------- + END + --------------------------------------------------------------------------- + */ +}, qx.Super.prototype._appearances); + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.AppearanceManager.getInstance().registerAppearanceTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/System.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/System.js new file mode 100644 index 0000000000..a73824d179 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/System.js @@ -0,0 +1,59 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_color) + +************************************************************************ */ + +/** + * System color theme + */ +qx.OO.defineClass("qx.theme.color.System", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Operating System Default"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsClassic.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsClassic.js new file mode 100644 index 0000000000..5d4f7e930a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsClassic.js @@ -0,0 +1,103 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_color) + +************************************************************************ */ + + +/** + * Windows classic color theme + */ +qx.OO.defineClass("qx.theme.color.WindowsClassic", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Windows Classic"); +}); + + + + + +/* +--------------------------------------------------------------------------- + DEFINE COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._colors = qx.lang.Object.carefullyMergeWith({ + activeborder : [ 212,208,200 ], + activecaption : [ 10,36,106 ], + appworkspace : [ 128,128,128 ], + background : [ 58,110,165 ], + buttonface : [ 212,208,200 ], + buttonhighlight : [ 255,255,255 ], + buttonshadow : [ 128,128,128 ], + buttontext : [ 0,0,0 ], + captiontext : [ 255,255,255 ], + graytext : [ 128,128,128 ], + highlight : [ 10,36,106 ], + highlighttext : [ 255,255,255 ], + inactiveborder : [ 212,208,200 ], + inactivecaption : [ 128,128,128 ], + inactivecaptiontext : [ 212,208,200 ], + infobackground : [ 255,255,225 ], + infotext : [ 0,0,0 ], + menu : [ 212,208,200 ], + menutext : [ 0,0,0 ], + scrollbar : [ 212,208,200 ], + threeddarkshadow : [ 64,64,64 ], + threedface : [ 212,208,200 ], + threedhighlight : [ 255,255,255 ], + threedlightshadow : [ 212,208,200 ], + threedshadow : [ 128,128,128 ], + window : [ 255,255,255 ], + windowframe : [ 0,0,0 ], + windowtext : [ 0,0,0 ] +}, qx.Super.prototype._colors); + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaBlue.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaBlue.js new file mode 100644 index 0000000000..0928f80420 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaBlue.js @@ -0,0 +1,101 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_color) + +************************************************************************ */ + +/** + * Windows luna blue color theme + */ +qx.OO.defineClass("qx.theme.color.WindowsLunaBlue", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Windows Luna Blue"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFINE COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._colors = qx.lang.Object.carefullyMergeWith({ + activeborder : [ 212,208,200 ], + activecaption : [ 0,84,227 ], + appworkspace : [ 128,128,128 ], + background : [ 0,78,152 ], + buttonface : [ 236,233,216 ], + buttonhighlight : [ 255,255,255 ], + buttonshadow : [ 172,168,153 ], + buttontext : [ 0,0,0 ], + captiontext : [ 255,255,255 ], + graytext : [ 172,168,153 ], + highlight : [ 49,106,197 ], + highlighttext : [ 255,255,255 ], + inactiveborder : [ 212,208,200 ], + inactivecaption : [ 122,150,223 ], + inactivecaptiontext : [ 216,228,248 ], + infobackground : [ 255,255,225 ], + infotext : [ 0,0,0 ], + menu : [ 255,255,255 ], + menutext : [ 0,0,0 ], + scrollbar : [ 212,208,200 ], + threeddarkshadow : [ 113,111,100 ], + threedface : [ 236,233,216 ], + threedhighlight : [ 255,255,255 ], + threedlightshadow : [ 241,239,226 ], + threedshadow : [ 172,168,153 ], + window : [ 255,255,255 ], + windowframe : [ 0,0,0 ], + windowtext : [ 0,0,0 ] +}, qx.Super.prototype._colors); + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaGreen.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaGreen.js new file mode 100644 index 0000000000..e5581849c5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaGreen.js @@ -0,0 +1,99 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_color) + +************************************************************************ */ + +/** + * Windows luna green color theme + */ +qx.OO.defineClass("qx.theme.color.WindowsLunaGreen", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Windows Luna Green"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFINE COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._colors = qx.lang.Object.carefullyMergeWith({ + activeborder : [ 212,208,200 ], + activecaption : [ 139,161,105 ], + appworkspace : [ 128,128,128 ], + background : [ 157,172,189 ], + buttonface : [ 236,233,216 ], + buttonhighlight : [ 255,255,255 ], + buttonshadow : [ 172,168,153 ], + buttontext : [ 0,0,0 ], + captiontext : [ 255,255,255 ], + graytext : [ 172,168,153 ], + highlight : [ 147,160,112 ], + highlighttext : [ 255,255,255 ], + inactiveborder : [ 212,208,200 ], + inactivecaption : [ 212,214,186 ], + inactivecaptiontext : [ 255,255,255 ], + infobackground : [ 255,255,225 ], + infotext : [ 0,0,0 ], + menu : [ 255,255,255 ], + menutext : [ 0,0,0 ], + scrollbar : [ 212,208,200 ], + threeddarkshadow : [ 113,111,100 ], + threedface : [ 236,233,216 ], + threedhighlight : [ 255,255,255 ], + threedlightshadow : [ 241,239,226 ], + threedshadow : [ 172,168,153 ], + window : [ 255,255,255 ], + windowframe : [ 0,0,0 ], + windowtext : [ 0,0,0 ] +}, qx.Super.prototype._colors); + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaSilver.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaSilver.js new file mode 100644 index 0000000000..8c160d96b6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsLunaSilver.js @@ -0,0 +1,99 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_color) + +************************************************************************ */ + +/** + * Windows luna silver color theme + */ +qx.OO.defineClass("qx.theme.color.WindowsLunaSilver", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Windows Luna Silver"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFINE COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._colors = qx.lang.Object.carefullyMergeWith({ + activeborder : [ 212,208,200 ], + activecaption : [ 192,192,192 ], + appworkspace : [ 128,128,128 ], + background : [ 88,87,104 ], + buttonface : [ 224,223,227 ], + buttonhighlight : [ 255,255,255 ], + buttonshadow : [ 157,157,161 ], + buttontext : [ 0,0,0 ], + captiontext : [ 14,16,16 ], + graytext : [ 172,168,153 ], + highlight : [ 178,180,191 ], + highlighttext : [ 0,0,0 ], + inactiveborder : [ 212,208,200 ], + inactivecaption : [ 255,255,255 ], + inactivecaptiontext : [ 162,161,161 ], + infobackground : [ 255,255,225 ], + infotext : [ 0,0,0 ], + menu : [ 255,255,255 ], + menutext : [ 0,0,0 ], + scrollbar : [ 212,208,200 ], + threeddarkshadow : [ 113,111,100 ], + threedface : [ 224,223,227 ], + threedhighlight : [ 255,255,255 ], + threedlightshadow : [ 241,239,226 ], + threedshadow : [ 157,157,161 ], + window : [ 255,255,255 ], + windowframe : [ 0,0,0 ], + windowtext : [ 0,0,0 ] +}, qx.Super.prototype._colors); + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsRoyale.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsRoyale.js new file mode 100644 index 0000000000..b27863116d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/color/WindowsRoyale.js @@ -0,0 +1,100 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_color) + +************************************************************************ */ + +/** + * Windows royale color theme + */ +qx.OO.defineClass("qx.theme.color.WindowsRoyale", qx.renderer.theme.ColorTheme, +function() { + qx.renderer.theme.ColorTheme.call(this, "Windows Royale"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFINE COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._colors = qx.lang.Object.carefullyMergeWith({ + activeborder : [ 212,208,200 ], + activecaption : [ 51,94,168 ], + appworkspace : [ 128,128,128 ], + background : [ 0,0,64 ], + buttonface : [ 235,233,237 ], + buttonhighlight : [ 255,255,255 ], + buttonshadow : [ 167,166,170 ], + buttontext : [ 0,0,0 ], + captiontext : [ 255,255,255 ], + graytext : [ 167,166,170 ], + highlight : [ 51,94,168 ], + highlighttext : [ 255,255,255 ], + inactiveborder : [ 212,208,200 ], + inactivecaption : [ 111,161,217 ], + inactivecaptiontext : [ 255,255,255 ], + infobackground : [ 255,255,225 ], + infotext : [ 0,0,0 ], + menu : [ 255,255,255 ], + menutext : [ 0,0,0 ], + scrollbar : [ 212,208,200 ], + threeddarkshadow : [ 133,135,140 ], + threedface : [ 235,233,237 ], + threedhighlight : [ 255,255,255 ], + threedlightshadow : [ 220,223,228 ], + threedshadow : [ 167,166,170 ], + window : [ 255,255,255 ], + windowframe : [ 0,0,0 ], + windowtext : [ 0,0,0 ] +}, qx.Super.prototype._colors); + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ColorManager.getInstance().registerColorTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/CrystalClear.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/CrystalClear.js new file mode 100644 index 0000000000..839d2f6c7b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/CrystalClear.js @@ -0,0 +1,76 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_icon) +#resource(icontheme:icon/CrystalClear) + +************************************************************************ */ + +/** + * Crystal Clear + * Author: Everaldo (everaldo@everaldo.com) + * License: LGPL + * Home: http://www.kde-look.org/content/show.php?content=25668 + */ +qx.OO.defineClass("qx.theme.icon.CrystalClear", qx.renderer.theme.IconTheme, +function() { + qx.renderer.theme.IconTheme.call(this, "CrystalClear"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("imageUri", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "resourceUri") + "/icon/CrystalClear"); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ImageManager.getInstance().registerIconTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/NuoveXT.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/NuoveXT.js new file mode 100644 index 0000000000..f5ea3899cb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/NuoveXT.js @@ -0,0 +1,76 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_icon) +#resource(icontheme:icon/NuoveXT) + +************************************************************************ */ + +/** + * nuoveXT + * Author: Alexandre Moore (alexandre.moore@gmail.com) + * License: GPL & LGPL/EPL + * Home: http://www.kde-look.org/content/show.php?content=26449 + */ +qx.OO.defineClass("qx.theme.icon.NuoveXT", qx.renderer.theme.IconTheme, +function() { + qx.renderer.theme.IconTheme.call(this, "NuoveXT"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("imageUri", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "resourceUri") + "/icon/NuoveXT"); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ImageManager.getInstance().registerIconTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/Nuvola.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/Nuvola.js new file mode 100644 index 0000000000..4e3b362f14 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/Nuvola.js @@ -0,0 +1,75 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(theme_icon) +#resource(icontheme:icon/Nuvola) + +************************************************************************ */ + + +/** + * Nuvola + * Author: David Vignoni (david@icon-king.com) + * License: LGPL + * Home: http://www.kde-look.org/content/show.php?content=5358 + */ +qx.OO.defineClass("qx.theme.icon.Nuvola", qx.renderer.theme.IconTheme, +function() { + qx.renderer.theme.IconTheme.call(this, "Nuvola"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("imageUri", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "resourceUri") + "/icon/Nuvola"); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ImageManager.getInstance().registerIconTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/VistaInspirate.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/VistaInspirate.js new file mode 100644 index 0000000000..131f83ed8d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/icon/VistaInspirate.js @@ -0,0 +1,77 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_icon) +#resource(icontheme:icon/VistaInspirate) + +************************************************************************ */ + +/** + * Vista-Inspirate + * Author: Alexandre Moore (alexandre.moore@gmail.com) + * License: GPL & LGPL/EPL + * Home: http://www.kde-look.org/content/show.php?content=31585 + * Comment: Based on nuoveXT by the same author + */ +qx.OO.defineClass("qx.theme.icon.VistaInspirate", qx.renderer.theme.IconTheme, +function() { + qx.renderer.theme.IconTheme.call(this, "Vista Inspirate"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("imageUri", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "resourceUri") + "/icon/VistaInspirate"); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ImageManager.getInstance().registerIconTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/widget/Windows.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/widget/Windows.js new file mode 100644 index 0000000000..d8efdcd4c3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/theme/widget/Windows.js @@ -0,0 +1,73 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(theme_widget) +#resource(widgettheme:widget/windows) + +************************************************************************ */ + +/** + * Default qooxdoo widget theme + */ +qx.OO.defineClass("qx.theme.widget.Windows", qx.renderer.theme.WidgetTheme, +function() { + qx.renderer.theme.WidgetTheme.call(this, "Windows"); +}); + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("imageUri", qx.Settings.getValueOfClass("qx.manager.object.AliasManager", "resourceUri") + "/widget/windows"); + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; + + + + + + +/* +--------------------------------------------------------------------------- + REGISTER TO MANAGER +--------------------------------------------------------------------------- +*/ + +qx.manager.object.ImageManager.getInstance().registerWidgetTheme(qx.Class); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Range.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Range.js new file mode 100644 index 0000000000..0a26c78c1c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Range.js @@ -0,0 +1,89 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * This manager is used by all objects which needs ranges like qx.ui.form.Spinner, ... + * + * @event change {qx.event.type.Event} + */ +qx.OO.defineClass("qx.type.Range", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + +/** current value of the Range object */ +qx.OO.addProperty({ name : "value", type : "number", defaultValue : 0 }); + +/** minimal value of the Range object */ +qx.OO.addProperty({ name : "min", type : "number", defaultValue : 0 }); + +/** maximal value of the Range object */ +qx.OO.addProperty({ name : "max", type : "number", defaultValue : 100 }); + +/** Step size for increments/decrements of the value property */ +qx.OO.addProperty({ name : "step", type : "number", defaultValue : 1 }); + +qx.Proto._checkValue = function(propValue) { + return Math.max(this.getMin(), Math.min(this.getMax(), Math.floor(propValue))); +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + if (this.hasEventListeners("change")) { + this.dispatchEvent(new qx.event.type.Event("change"), true); + } + + return true; +} + +qx.Proto._checkMax = function(propValue) { + return Math.floor(propValue); +} + +qx.Proto._modifyMax = function(propValue, propOldValue, propData) +{ + this.setValue(Math.min(this.getValue(), propValue)); + + if (this.hasEventListeners("change")) { + this.dispatchEvent(new qx.event.type.Event("change"), true); + } + + return true; +} + +qx.Proto._checkMin = function(propValue) { + return Math.floor(propValue); +} + +qx.Proto._modifyMin = function(propValue, propOldValue, propData) +{ + this.setValue(Math.max(this.getValue(), propValue)); + + if (this.hasEventListeners("change")) { + this.dispatchEvent(new qx.event.type.Event("change"), true); + } + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Selection.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Selection.js new file mode 100644 index 0000000000..e4025bec42 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Selection.js @@ -0,0 +1,180 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + + +************************************************************************ */ + +/** + * Helper for qx.manager.selection.SelectionManager, contains data for selections + * + * @param vManager {Object} a class which implements a getItemHashCode(oItem) method + */ +qx.OO.defineClass("qx.type.Selection", qx.core.Object, +function(vManager) +{ + qx.core.Object.call(this); + + this._manager = vManager; + this.removeAll(); +}); + + + + + +/* +--------------------------------------------------------------------------- + USER METHODS +--------------------------------------------------------------------------- +*/ + +/** + * Add an item to the selection + * + * @param oItem {var} item to add + */ +qx.Proto.add = function(oItem) { + this._storage[this.getItemHashCode(oItem)] = oItem; +}; + + +/** + * Remove an item from the selection + * + * @param oItem {var} item to remove + */ +qx.Proto.remove = function(oItem) { + delete this._storage[this.getItemHashCode(oItem)]; +}; + + +/** + * Remove all items from the selection + */ +qx.Proto.removeAll = function() { + this._storage = {}; +}; + + +/** + * Check whether the selection contains a given item + * + * @param oItem {var} item to check for + * @return {Boolean} whether the selection contains the item + */ +qx.Proto.contains = function(oItem) { + return this.getItemHashCode(oItem) in this._storage; +}; + + +/** + * Convert selection to an array + * + * @return {Array} array representation of the selection + */ +qx.Proto.toArray = function() +{ + var res = []; + + for (var key in this._storage) { + res.push(this._storage[key]); + } + + return res; +}; + + +/** + * Return first element of the Selection + * + * @return {var} first item of the selection + */ +qx.Proto.getFirst = function() +{ + for (var key in this._storage) { + return this._storage[key]; + } +} + + +/** + * Get a string representation of the Selection. The return value can be used to compare selections. + * + * @return {String} string representation of the Selection + */ +qx.Proto.getChangeValue = function() +{ + var sb = []; + + for (var hc in this._storage) { + sb.push(hc); + } + + sb.sort(); + return sb.join(";"); +}; + + +/** + * Compute a hash code for an item using the manager + * + * @param oItem {var} the item + * @return {var} unique hash code for the item + */ +qx.Proto.getItemHashCode = function(oItem) { + return this._manager.getItemHashCode(oItem); +}; + + +/** + * Whether the selection is empty + * + * @return {Boolean} whether the selection is empty + */ +qx.Proto.isEmpty = function() { + return qx.lang.Object.isEmpty(this._storage); +}; + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Destructor + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._storage = null; + this._manager = null; + + qx.core.Object.prototype.dispose.call(this); +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Version.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Version.js new file mode 100755 index 0000000000..01ffc708db --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/type/Version.js @@ -0,0 +1,185 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the qooxdoo top-level directory for details + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + ________________________________________________________________________ + + This class contains code based on the following work: + + SWFObject: Javascript Flash Player detection and embed script + http://blog.deconcept.com/swfobject/ + Version: 1.4.4 + + Copyright: + 2006 Geoff Stearns + + License: + MIT: http://www.opensource.org/licenses/mit-license.php + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + Authors: + * Geoff Stearns (geoff@deconcept.com) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Generic handling of version numbers based on a string representation of + * major, minor and revision flags. A incoming version object can be compared + * with the stored version string including checks to determine if this + * version is smaller than or identical to the one stored. + * + * This class contains code based on the following work:<br/> + * SWFObject: Javascript Flash Player detection and embed script<br/> + * http://blog.deconcept.com/swfobject/<br/> + * Version: 1.4.4 + * + * License:<br/> + * MIT: http://www.opensource.org/licenses/mit-license.php<br/> + * For more info, please see the corresponding source file. + * + * @param arrVersion {Array|String} array with three elements defining major, + * minor and revision number or an equivalent version string separated by '.' + */ +qx.OO.defineClass("qx.type.Version", qx.core.Object, +function(arrVersion) +{ + qx.core.Object.call(this); + + if (typeof arrVersion === "string") { + arrVersion = arrVersion.split("."); + } + + this._major = parseInt(arrVersion[0]) || 0; + this._minor = parseInt(arrVersion[1]) || 0; + this._rev = parseInt(arrVersion[2]) || 0; +}); + + + + +/* +--------------------------------------------------------------------------- + DATA FIELDS +--------------------------------------------------------------------------- +*/ + +qx.Proto._major = 0; +qx.Proto._minor = 0; +qx.Proto._rev = 0; + + + + + +/* +--------------------------------------------------------------------------- + USER VERSION ACCESS +--------------------------------------------------------------------------- +*/ + +/** + * Comapres the Version with another version number. + * Returns true if this version instance has a bigger version number + * + * @param fv {qx.type.Version} Version number to compare with + * @return {Boolean} whether the version instance has a bigger version numbers. + */ +qx.Proto.versionIsValid = function(fv) +{ + if (this.getMajor() < fv.getMajor()) return false; + if (this.getMajor() > fv.getMajor()) return true; + + if (this.getMinor() < fv.getMinor()) return false; + if (this.getMinor() > fv.getMinor()) return true; + + if (this.getRev() < fv.getRev()) return false; + + return true; +}; + + +/** + * Return major version number + * + * @return {String|Integer} major version number + */ +qx.Proto.getMajor = function() { + return this._major; +}; + + +/** + * Return minor version number + * + * @return {String|Integer} minor version number + */ +qx.Proto.getMinor = function() { + return this._minor; +}; + + +/** + * Return revision number + * + * @return {String|Integer} revision number + */ +qx.Proto.getRev = function() { + return this._rev; +}; + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** Destructor */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._major = this._minor = this._rev = null; + + qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js new file mode 100644 index 0000000000..e65fff4918 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js @@ -0,0 +1,401 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#optional(qx.ui.embed.Flash) + +************************************************************************ */ + +/** + * A multi-purpose widget used by many more complex widgets. + * + * The intended purpose of qx.ui.basic.Atom is to easily align the common icon-text combination in different ways. + * This is useful for all types of buttons, menuentries, tooltips, ... + * + * @param vLabel {String} label of the atom + * @param vIcon {String?null} Icon of the atom + * @param vIconWidth {Integer?null} desired width of the icon (the icon will be scaled to this size) + * @param vIconHeight {Integer?null} desired height of the icon (the icon will be scaled to this size) + * @param vFlash {qx.ui.embed.Flash?null} optional flash animation for the Atom. Needs valid width and height values. + */ +qx.OO.defineClass("qx.ui.basic.Atom", qx.ui.layout.BoxLayout, +function(vLabel, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.layout.BoxLayout.call(this); + + if (this.getOrientation() == null) { + this.setOrientation("horizontal"); + } + + // Prohibit selection + this.setSelectable(false); + + // Disable flex support + this.getLayoutImpl().setEnableFlexSupport(false); + + // Apply constructor arguments + this.setLabel(vLabel); + + // Simple flash wrapper + if (qx.OO.isAvailable("qx.ui.embed.Flash") && vFlash != null && vIconWidth != null && vIconHeight != null && qx.ui.embed.Flash.getPlayerVersion().getMajor() > 0) + { + this._flashMode = true; + + this.setIcon(vFlash); + + // flash needs explicit dimensions! + this.setIconWidth(vIconWidth); + this.setIconHeight(vIconHeight); + } + else if (vIcon != null) + { + this.setIcon(vIcon); + + if (vIconWidth != null) { + this.setIconWidth(vIconWidth); + } + + if (vIconHeight != null) { + this.setIconHeight(vIconHeight); + } + } +}); + +qx.ui.basic.Atom.SHOW_LABEL = "label"; +qx.ui.basic.Atom.SHOW_ICON = "icon"; +qx.ui.basic.Atom.SHOW_BOTH = "both"; + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The label/caption/text of the qx.ui.basic.Atom instance +*/ +qx.OO.addProperty({ name : "label" }); + +/*! + Any URI String supported by qx.ui.basic.Image to display a icon +*/ +qx.OO.addProperty({ name : "icon", type : "string" }); + +/** + * Any URI String supported by qx.ui.basic.Image to display a disabled icon. + * <p> + * If not set the normal icon is shown transparently. + */ +qx.OO.addProperty({ name : "disabledIcon", type : "string" }); + +/*! + Configure the visibility of the sub elements/widgets. + Possible values: both, text, icon, none +*/ +qx.OO.addProperty({ name : "show", type : "string", defaultValue : "both", possibleValues : [ "both", "label", "icon", "none", null ] }); + +/*! + The position of the icon in relation to the text. + Only useful/needed if text and icon is configured and 'show' is configured as 'both' (default) +*/ +qx.OO.addProperty({ name : "iconPosition", type : "string", defaultValue : "left", possibleValues : [ "top", "right", "bottom", "left" ] }); + +/*! + The width of the icon. + If configured, this makes qx.ui.basic.Atom a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconWidth", type : "number" }); + +/*! + The height of the icon + If configured, this makes qx.ui.basic.Atom a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconHeight", type : "number" }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "atom" }); + + + + + +/* +--------------------------------------------------------------------------- + SUB WIDGETS +--------------------------------------------------------------------------- +*/ + +qx.Proto._flashMode = false; + +qx.Proto._labelObject = null; +qx.Proto._iconObject = null; + +qx.Proto._createLabel = function() +{ + var l = this._labelObject = new qx.ui.basic.Label(this.getLabel()); + + l.setAnonymous(true); + l.setEnabled(this.getEnabled()); + l.setSelectable(false); + + this.addAt(l, this._iconObject ? 1 : 0); +} + +qx.Proto._createIcon = function() +{ + if (this._flashMode && qx.OO.isAvailable("qx.ui.embed.Flash")) + { + var i = this._iconObject = new qx.ui.embed.Flash(this.getIcon()); + } + else + { + var i = this._iconObject = new qx.ui.basic.Image(); + } + + i.setAnonymous(true); + + this._updateIcon(); + + this.addAt(i, 0); +} + +qx.Proto._updateIcon = function() { + // NOTE: We have to check whether the properties "icon" and "disabledIcon" + // exist, because some child classes remove them. + if (this._iconObject && this.getIcon && this.getDisabledIcon) { + var disabledIcon = this.getDisabledIcon(); + if (disabledIcon) { + if (this.getEnabled()) { + this._iconObject.setSource(this.getIcon()); + } else { + this._iconObject.setSource(disabledIcon); + } + this._iconObject.setEnabled(true); + } else { + this._iconObject.setSource(this.getIcon()); + this._iconObject.setEnabled(this.getEnabled()); + } + } +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + + if (this._labelObject) { + this._labelObject.setEnabled(propValue); + } + + return qx.ui.layout.BoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyIconPosition = function(propValue, propOldValue, propData) +{ + switch(propValue) + { + case "top": + case "bottom": + this.setOrientation("vertical"); + this.setReverseChildrenOrder(propValue == "bottom"); + break; + + default: + this.setOrientation("horizontal"); + this.setReverseChildrenOrder(propValue == "right"); + break; + } + + return true; +} + +qx.Proto._modifyShow = function(propValue, propOldValue, propData) +{ + this._handleIcon(); + this._handleLabel(); + + return true; +} + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + if (this._labelObject) { + this._labelObject.setHtml(propValue); + } + + this._handleLabel(); + + return true; +} + +qx.Proto._modifyIcon = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + this._handleIcon(); + + return true; +} + +qx.Proto._modifyDisabledIcon = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + this._handleIcon(); + + return true; +} + +qx.Proto._modifyIconWidth = function(propValue, propOldValue, propData) +{ + this._iconObject.setWidth(propValue); + return true; +} + +qx.Proto._modifyIconHeight = function(propValue, propOldValue, propData) +{ + this._iconObject.setHeight(propValue); + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._iconIsVisible = false; +qx.Proto._labelIsVisible = false; + +qx.Proto._handleLabel = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_LABEL: + case qx.ui.basic.Atom.SHOW_BOTH: + this._labelIsVisible = qx.util.Validation.isValidString(this.getLabel()) || this.getLabel() instanceof qx.locale.LocalizedString; + break; + + default: + this._labelIsVisible = false; + } + + if (this._labelIsVisible) + { + this._labelObject ? this._labelObject.setDisplay(true) : this._createLabel(); + } + else if (this._labelObject) + { + this._labelObject.setDisplay(false); + } +} + +qx.Proto._handleIcon = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_ICON: + case qx.ui.basic.Atom.SHOW_BOTH: + this._iconIsVisible = qx.util.Validation.isValidString(this.getIcon()); + break; + + default: + this._iconIsVisible = false; + } + + if (this._iconIsVisible) + { + this._iconObject ? this._iconObject.setDisplay(true) : this._createIcon(); + } + else if (this._iconObject) + { + this._iconObject.setDisplay(false); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +// Omit recursive cloning +qx.Proto._cloneRecursive = qx.lang.Function.returnTrue; + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js new file mode 100644 index 0000000000..d1c6adeb06 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js @@ -0,0 +1,33 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.HorizontalSpacer", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setWidth("1*"); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Image.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Image.js new file mode 100644 index 0000000000..95f50795b5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Image.js @@ -0,0 +1,615 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * This widget represents an image. + * + * @event error {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.basic.Image", qx.ui.basic.Terminator, +function(vSource, vWidth, vHeight) +{ + qx.ui.basic.Terminator.call(this); + + // Reset Alt and Title + this.setHtmlProperty("alt", ""); + this.setHtmlProperty("title", ""); + + // Apply constructor arguments + this.setSource(vSource || "static/image/blank.gif"); + + // Dimensions + this.setWidth(vWidth !== undefined ? vWidth : "auto"); + this.setHeight(vHeight !== undefined ? vHeight : "auto"); + + // Prohibit selection + this.setSelectable(false); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The source uri of the image. +*/ +qx.OO.addProperty({ name : "source", type : "string" }); + +/*! + The assigned preloader instance of the image. +*/ +qx.OO.addProperty({ name : "preloader", type : "object" }); + +/*! + The loading status. + + True if the image is loaded correctly. False if no image is loaded + or the one that should be loaded is currently loading or not available. +*/ +qx.OO.addProperty({ name : "loaded", type : "boolean", defaultValue : false }); + +/*! + Should the image be maxified in it's own container? +*/ +qx.OO.addProperty({ name : "resizeToInner", type : "boolean", defaultValue : false }); + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "image" }); + + + + + +/* +--------------------------------------------------------------------------- + EVENT MAPPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onload = function() { + this.setLoaded(true); +} + +qx.Proto._onerror = function() +{ + this.debug("Could not load: " + this.getSource()); + + this.setLoaded(false); + + if (this.hasEventListeners("error")) { + this.dispatchEvent(new qx.event.type.Event("error"), true); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + var vSource = this.getSource(); + + if (qx.util.Validation.isValidString(vSource)) { + qx.manager.object.ImageManager.getInstance()._sources[vSource]++; + } + + return qx.ui.basic.Terminator.prototype._beforeAppear.call(this); +} + +qx.Proto._beforeDisappear = function() +{ + var vSource = this.getSource(); + + if (qx.util.Validation.isValidString(vSource)) + { + if (qx.manager.object.ImageManager.getInstance()._sources[vSource] <= 1) + { + delete qx.manager.object.ImageManager.getInstance()._sources[vSource]; + } + else + { + qx.manager.object.ImageManager.getInstance()._sources[vSource]--; + } + } + + return qx.ui.basic.Terminator.prototype._beforeDisappear.call(this); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySource = function(propValue, propOldValue, propData) +{ + if (propValue && typeof qx.manager.object.ImageManager.getInstance()._sources[propValue] === "undefined") { + qx.manager.object.ImageManager.getInstance()._sources[propValue] = 0; + } + + if (propOldValue) + { + if (qx.manager.object.ImageManager.getInstance()._sources[propOldValue] <= 1) + { + delete qx.manager.object.ImageManager.getInstance()._sources[propOldValue]; + } + else + { + qx.manager.object.ImageManager.getInstance()._sources[propOldValue]--; + } + } + + if (this.isCreated()) + { + if (propValue) + { + this.setPreloader(qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(propValue))); + } + else if (propOldValue) + { + this._resetContent(); + this.setPreloader(null); + } + } + + return true; +} + +qx.Proto._modifyPreloader = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + // remove event connection + propOldValue.removeEventListener("load", this._onload, this); + propOldValue.removeEventListener("error", this._onerror, this); + } + + if (propValue) + { + // Register to image manager + qx.manager.object.ImageManager.getInstance().add(this); + + // Omit here, otherwise the later setLoaded(true) + // will not be executed (prevent recursion) + + // Changed: Use forceLoaded instead of setLoaded => should be faster + this.forceLoaded(false); + + if (propValue.isErroneous()) + { + this._onerror(); + } + else if (propValue.isLoaded()) + { + this.setLoaded(true); + } + else + { + propValue.addEventListener("load", this._onload, this); + propValue.addEventListener("error", this._onerror, this); + } + } + else + { + // Remove from image manager + qx.manager.object.ImageManager.getInstance().remove(this); + + this.setLoaded(false); + } + + return true; +} + +qx.Proto._modifyLoaded = function(propValue, propOldValue, propData) +{ + if (propValue && this.isCreated()) + { + this._applyContent(); + } + else if (!propValue) + { + this._invalidatePreferredInnerWidth(); + this._invalidatePreferredInnerHeight(); + } + + return true; +} + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (!this._image) + { + try + { + // Create Image-Node + // Webkit has problems with "new Image". Maybe related to "new Function" with + // is also not working correctly. + if (qx.core.Client.getInstance().isWebkit()) + { + this._image = document.createElement("img"); + } + else + { + this._image = new Image; + } + + // Possible alternative for MSHTML for PNG images + // But it seems not to be faster + // this._image = document.createElement("div"); + + // this costs much performance, move setup to blank gif to error handling + // is this SSL save? + // this._image.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + + this._image.style.border = "0 none"; + this._image.style.verticalAlign = "top"; + } + catch(ex) + { + this.error("Failed while creating image #1", ex); + } + + if (!qx.core.Client.getInstance().isMshtml()) { + this._applyEnabled(); + } + } + + propValue.appendChild(this._image); + } + + // call widget implmentation + qx.ui.basic.Terminator.prototype._modifyElement.call(this, propValue, propOldValue, propData); + + if (propValue) + { + try + { + // initialisize preloader + var vSource = this.getSource(); + if (qx.util.Validation.isValidString(vSource)) + { + //this.debug("Post-Create: " + vSource); + this.setPreloader(qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(vSource))); + } + } + catch(ex) + { + this.error("Failed while creating image #2", ex); + } + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + CLIENT OPTIMIZED MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._postApply = function() +{ + if (!this.getLoaded()) { + this._updateContent(qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif")); + return; + } + + this._postApplyDimensions(); + this._updateContent(); +} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) + { + if (this._image) { + this._applyEnabled(); + } + + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); + } + + qx.Proto._updateContent = function(vSource) + { + var i = this._image; + var pl = this.getPreloader(); + + if (pl.getIsPng() && this.getEnabled()) + { + i.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + i.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + (vSource || pl.getSource()) + "',sizingMethod='scale')"; + } + else + { + i.src = vSource || pl.getSource(); + i.style.filter = this.getEnabled() ? "" : "Gray() Alpha(Opacity=30)"; + } + } + + qx.Proto._resetContent = function() + { + var i = this._image; + + i.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + i.style.filter = ""; + } + + qx.Proto._applyEnabled = qx.Proto._postApply; +} +else +{ + qx.Proto._updateContent = function(vSource) { + this._image.src = vSource || this.getPreloader().getSource(); + } + + qx.Proto._resetContent = function() { + this._image.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + } + + qx.Proto._applyEnabled = function() + { + if (this._image) + { + var o = this.getEnabled() ? "" : 0.3; + var s = this._image.style; + + s.opacity = s.KhtmlOpacity = s.MozOpacity = o; + } + } + + qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) + { + if (this._image) { + this._applyEnabled(); + } + + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS: INNER +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() +{ + if (this.getLoaded()) + { + return this.getPreloader().getWidth(); + } + else if (qx.util.Validation.isValidString(this.getSource())) + { + var vPreloader = qx.manager.object.ImagePreloaderManager.getInstance().get(qx.manager.object.AliasManager.getInstance().resolvePath(this.getSource())); + + if (vPreloader && vPreloader.isLoaded()) { + return vPreloader.getWidth(); + } + } + + return 0; +} + +qx.Proto._computePreferredInnerHeight = function() +{ + if (this.getLoaded()) + { + return this.getPreloader().getHeight(); + } + else if (qx.util.Validation.isValidString(this.getSource())) + { + var vPreloader = qx.manager.object.ImagePreloaderManager.getInstance().get(qx.manager.object.AliasManager.getInstance().resolvePath(this.getSource())); + + if (vPreloader && vPreloader.isLoaded()) { + return vPreloader.getHeight(); + } + } + + return 0; +} + + + + + + + +/* +--------------------------------------------------------------------------- + APPLY +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyContent = function() +{ + qx.ui.basic.Terminator.prototype._applyContent.call(this); + + // Images load asyncron, so we need to force flushing here + // to get an up-to-date view when an image is loaded. + qx.ui.core.Widget.flushGlobalQueues(); +} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._postApplyDimensions = function() + { + try + { + var vImageStyle = this._image.style; + + if (this.getResizeToInner()) + { + vImageStyle.pixelWidth = this.getInnerWidth(); + vImageStyle.pixelHeight = this.getInnerHeight(); + } + else + { + vImageStyle.pixelWidth = this.getPreferredInnerWidth(); + vImageStyle.pixelHeight = this.getPreferredInnerHeight(); + } + } + catch(ex) + { + this.error("postApplyDimensions failed", ex); + } + } +} +else +{ + qx.Proto._postApplyDimensions = function() + { + try + { + var vImageNode = this._image; + + if (this.getResizeToInner()) + { + vImageNode.width = this.getInnerWidth(); + vImageNode.height = this.getInnerHeight(); + } + else + { + vImageNode.width = this.getPreferredInnerWidth(); + vImageNode.height = this.getPreferredInnerHeight(); + } + } + catch(ex) + { + this.error("postApplyDimensions failed", ex); + } + } +} + + + + +/* +--------------------------------------------------------------------------- + CHANGES IN DIMENSIONS +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._changeInnerWidth = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.style.pixelWidth = vNew; + } + } + + qx.Proto._changeInnerHeight = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.style.pixelHeight = vNew; + } + } +} +else +{ + qx.Proto._changeInnerWidth = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.width = vNew; + } + } + + qx.Proto._changeInnerHeight = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.height = vNew; + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + var vPreloader = this.getPreloader(); + if (vPreloader) + { + // remove event connection + vPreloader.removeEventListener("load", this._onload, this); + vPreloader.removeEventListener("error", this._onerror, this); + + this.forcePreloader(null); + } + + if (this._image) + { + // Remove leaking filter attribute before leaving page + this._image.style.filter = ""; + this._image = null; + } + + qx.manager.object.ImageManager.getInstance().remove(this); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js new file mode 100644 index 0000000000..593495c670 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js @@ -0,0 +1,39 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.Inline", qx.ui.layout.CanvasLayout, +function(vId) +{ + qx.ui.layout.CanvasLayout.call(this); + + this.setStyleProperty("position", "relative"); + + if (vId != null) { + this.setInlineNodeId(vId); + } +}); + +qx.OO.addProperty({ name : "inlineNodeId", type : "string" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Label.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Label.js new file mode 100644 index 0000000000..63690a703c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Label.js @@ -0,0 +1,502 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.Label", qx.ui.basic.Terminator, +function(vHtml, vMnemonic) +{ + qx.ui.basic.Terminator.call(this); + + // Apply constructor arguments + if (vHtml != null) { + this.setHtml(vHtml); + } + + if (vMnemonic != null) { + this.setMnemonic(vMnemonic); + } + + // Prohibit stretching through layout handler + this.setAllowStretchX(false); + this.setAllowStretchY(false); + + // Auto Sized + this.auto(); +}); + +qx.Class._measureNodes = {}; + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "label" }); + +/*! + Any text string which can contain HTML, too +*/ +qx.OO.addProperty({ name : "html" }); + +/*! + The alignment of the text. +*/ +qx.OO.addProperty({ name : "textAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right", "justify" ] }); + +/*! + The styles which should be copied +*/ +qx.OO.addProperty({ name : "fontPropertiesProfile", type : "string", defaultValue : "default", possibleValues : [ "none", "default", "extended", "multiline", "extendedmultiline", "all" ] }); + +/*! + A single character which will be underlined inside the text. +*/ +qx.OO.addProperty({ name : "mnemonic", type : "string" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + +/*! + Wrap the text? +*/ +qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true }); + + + + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + DATA +--------------------------------------------------------------------------- +*/ + +qx.ui.basic.Label.SYMBOL_ELLIPSIS = String.fromCharCode(8230); +qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS = qx.core.Client.getInstance().isMshtml(); + +// these are the properties what will be copied to the measuring frame. +qx.ui.basic.Label._fontProperties = +{ + "none" : [], + + "default" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration"], + "extended" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing"], + + "multiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration", "lineHeight", "wordWrap"], + "extendedmultiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing", "lineHeight", "wordBreak", "wordWrap", "quotes"], + + "all" : ["fontFamily", "fontSize", "fontStyle", "fontVariant", "fontWeight", "letterSpacing", "lineBreak", "lineHeight", "quotes", "textDecoration", "textIndent", "textShadow", "textTransform", "textUnderlinePosition", "whiteSpace", "wordBreak", "wordSpacing", "wordWrap"] +} + + +qx.ui.basic.Label.createMeasureNode = function(vId) +{ + var vNode = qx.ui.basic.Label._measureNodes[vId]; + + if (!vNode) + { + vNode = document.createElement("div"); + var vStyle = vNode.style; + + vStyle.width = vStyle.height = "auto"; + vStyle.visibility = "hidden"; + vStyle.position = "absolute"; + vStyle.zIndex = "-1"; + + document.body.appendChild(vNode); + + qx.ui.basic.Label._measureNodes[vId] = vNode; + } + + return vNode; +} + + + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._localized = false; +qx.Proto._htmlContent = ""; +qx.Proto._htmlMode = false; +qx.Proto._hasMnemonic = false; +qx.Proto._mnemonicHtml = ""; +qx.Proto._mnemonicTest = null; + +qx.Proto._modifyHtml = function(propValue, propOldValue, propData) +{ + this._localized = this.getHtml() instanceof qx.locale.LocalizedString; + this._updateHtml(); + return true; +} + +qx.Proto._updateHtml = function() +{ + if (this._localized) + { + this._htmlContent = this.getHtml().toString(); + qx.locale.Manager.getInstance().addEventListener("changeLocale", this._updateHtml, this); + } + else + { + this._htmlContent = this.getHtml() || ""; + qx.locale.Manager.getInstance().removeEventListener("changeLocale", this._updateHtml, this); + } + + this._htmlMode = qx.util.Validation.isValidString(this._htmlContent) && this._htmlContent.match(/<.*>/) ? true : false; + + if (this._isCreated) { + this._applyContent(); + } +}; + + +qx.Proto._modifyTextAlign = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("textAlign", propValue); + return true; +} + +qx.Proto._modifyMnemonic = function(propValue, propOldValue, propData) +{ + this._hasMnemonic = qx.util.Validation.isValidString(propValue) && propValue.length == 1; + + this._mnemonicHtml = this._hasMnemonic ? "(<span style=\"text-decoration:underline\">" + propValue + "</span>)" : ""; + this._mnemonicTest = this._hasMnemonic ? new RegExp("^(((<([^>]|" + propValue + ")+>)|(&([^;]|" + propValue + ")+;)|[^&" + propValue + "])*)(" + propValue + ")", "i") : null; + + return true; +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + this._invalidatePreferredInnerDimensions(); + + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + +qx.Proto._modifyWrap = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + HELPER FOR PREFERRED DIMENSION +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeObjectNeededDimensions = function() +{ + // copy styles + var vNode = this._copyStyles(); + + // prepare html + var vHtml = this._htmlContent; + + // test for mnemonic and fix content + if (this._hasMnemonic && !this._mnemonicTest.test(vHtml)) { + vHtml += this._mnemonicHtml; + } + + // apply html + vNode.innerHTML = vHtml; + + // store values + this._cachedPreferredInnerWidth = vNode.scrollWidth; + this._cachedPreferredInnerHeight = vNode.scrollHeight; +} + +qx.Proto._copyStyles = function() +{ + var vProps = this.getFontPropertiesProfile(); + var vNode = qx.ui.basic.Label.createMeasureNode(vProps); + var vUseProperties=qx.ui.basic.Label._fontProperties[vProps]; + var vUsePropertiesLength=vUseProperties.length-1; + var vProperty=vUseProperties[vUsePropertiesLength--]; + + var vStyle = vNode.style; + var vTemp; + + if (!vProperty) { + return vNode; + } + + do { + vStyle[vProperty] = qx.util.Validation.isValid(vTemp = this.getStyleProperty([vProperty])) ? vTemp : ""; + } while(vProperty=vUseProperties[vUsePropertiesLength--]); + + return vNode; +} + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() +{ + this._computeObjectNeededDimensions(); + return this._cachedPreferredInnerWidth; +} + +qx.Proto._computePreferredInnerHeight = function() +{ + this._computeObjectNeededDimensions(); + return this._cachedPreferredInnerHeight; +} + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT APPLY +--------------------------------------------------------------------------- +*/ + +qx.Proto._postApply = function() +{ + var vHtml = this._htmlContent; + var vElement = this._getTargetNode(); + var vMnemonicMode = 0; + + if (qx.util.Validation.isInvalidString(vHtml)) { + vElement.innerHTML = ""; + return; + } + + if (this._hasMnemonic) { + vMnemonicMode = this._mnemonicTest.test(vHtml) ? 1 : 2; + } + + // works only with text, don't use when wrap is enabled + if (!this._htmlMode && !this.getWrap()) + { + switch(this._computedWidthType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + case qx.ui.core.Widget.TYPE_PERCENT: + + //carstenl: enabled truncation code for flex sizing, too. Appears to work except for the + // truncation code (gecko version), which I have disabled (see below). + case qx.ui.core.Widget.TYPE_FLEX: + var vNeeded = this.getPreferredInnerWidth(); + var vInner = this.getInnerWidth(); + + if (vInner < vNeeded) + { + vElement.style.overflow = "hidden"; + + if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS) + { + vElement.style.textOverflow = "ellipsis"; + vHtml += this._mnemonicHtml; + } + else + { + var vMeasureNode = this._copyStyles(); + + var vSplitString = vHtml.split(" "); + var vSplitLength = vSplitString.length; + + var vWordIterator = 0; + var vCharaterIterator = 0; + + var vPost = qx.ui.basic.Label.SYMBOL_ELLIPSIS; + + var vUseInnerText = true; + if (vMnemonicMode == 2) + { + var vPost = this._mnemonicHtml + vPost; + vUseInnerText = false; + } + + // Measure Words (if more than one) + if (vSplitLength > 1) + { + var vSplitTemp = []; + + for (vWordIterator=0; vWordIterator<vSplitLength; vWordIterator++) + { + vSplitTemp.push(vSplitString[vWordIterator]); + + var vLabelText = vSplitTemp.join(" ") + vPost; + if (vUseInnerText) { + qx.dom.Element.setTextContent(vMeasureNode, vLabelText); + } else { + vMeasureNode.innerHTML = vLabelText; + } + + if ((vMeasureNode.scrollWidth > vInner) + /* carstenl: The following code (truncate the text to fit in the available + * space, append ellipsis to indicate truncation) did not reliably + * work in my tests. Problem was that sometimes the measurer returned + * insanely high values for short texts, like "I..." requiring 738 px. + * + * I don't have time to examine this code in detail. Since all of my + * tests used flex width and the truncation code never was intended + * for this, I am disabling truncation if flex is active. + */ + && (this._computedWidthType != qx.ui.core.Widget.TYPE_FLEX)){ + break; + } + } + + // Remove last word which does not fit + vSplitTemp.pop(); + + // Building new temportary array + vSplitTemp = [ vSplitTemp.join(" ") ]; + + // Extracting remaining string + vCharaterString = vHtml.replace(vSplitTemp[0], ""); + } + else + { + var vSplitTemp = []; + vCharaterString = vHtml; + } + + var vCharaterLength = vCharaterString.length; + + // Measure Chars + for (var vCharaterIterator=0; vCharaterIterator<vCharaterLength; vCharaterIterator++) + { + vSplitTemp.push(vCharaterString.charAt(vCharaterIterator)); + + var vLabelText = vSplitTemp.join("") + vPost; + if (vUseInnerText) { + qx.dom.Element.setTextContent(vMeasureNode, vLabelText); + } else { + vMeasureNode.innerHTML = vLabelText; + } + + if (vMeasureNode.scrollWidth > vInner) { + break; + } + } + + // Remove last char which does not fit + vSplitTemp.pop(); + + // Add mnemonic and ellipsis symbol + vSplitTemp.push(vPost); + + // Building Final HTML String + vHtml = vSplitTemp.join(""); + } + + break; + } + else + { + vHtml += this._mnemonicHtml; + } + + // no break here + + default: + vElement.style.overflow = ""; + + if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS) { + vElement.style.textOverflow = ""; + } + } + } + + if (vMnemonicMode == 1) + { + // re-test: needed to make ellipsis handling correct + this._mnemonicTest.test(vHtml); + vHtml = RegExp.$1 + "<span style=\"text-decoration:underline\">" + RegExp.$7 + "</span>" + RegExp.rightContext; + } + + return this._postApplyHtml(vElement, vHtml, vMnemonicMode); +} + + +qx.Proto._postApplyHtml = function(vElement, vHtml, vMnemonicMode) +{ + if (this._htmlMode || vMnemonicMode > 0) + { + vElement.innerHTML = vHtml; + } + else + { + try { + qx.dom.Element.setTextContent(vElement, vHtml); + } catch(ex) { + vElement.innerHTML = vHtml; + } + } +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js new file mode 100644 index 0000000000..5d06ba4d70 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js @@ -0,0 +1,189 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + This widget is the last widget of the current child chain. +*/ +qx.OO.defineClass("qx.ui.basic.Terminator", qx.ui.core.Widget, +function() { + qx.ui.core.Widget.call(this); +}); + + + + + + +/* +--------------------------------------------------------------------------- + APPLY PADDING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyPaddingX = function(vParent, vChanges, vStyle) +{ + if (vChanges.paddingLeft) { + this._applyRuntimePaddingLeft(this.getPaddingLeft()); + } + + if (vChanges.paddingRight) { + this._applyRuntimePaddingRight(this.getPaddingRight()); + } +} + +qx.Proto._applyPaddingY = function(vParent, vChanges, vStyle) +{ + if (vChanges.paddingTop) { + this._applyRuntimePaddingTop(this.getPaddingTop()); + } + + if (vChanges.paddingBottom) { + this._applyRuntimePaddingBottom(this.getPaddingBottom()); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + APPLY CONTENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyContent = function() +{ + // Small optimization: Only add innerPreferred jobs + // if we don't have a static width + if (this._computedWidthTypePixel) { + this._cachedPreferredInnerWidth = null; + } else { + this._invalidatePreferredInnerWidth(); + } + + // Small optimization: Only add innerPreferred jobs + // if we don't have a static height + if (this._computedHeightTypePixel) { + this._cachedPreferredInnerHeight = null; + } else { + this._invalidatePreferredInnerHeight(); + } + + // add load job + if (this._initialLayoutDone) { + this.addToJobQueue("load"); + } +} + +qx.Proto._layoutPost = function(vChanges) { + if (vChanges.initial || vChanges.load || vChanges.width || vChanges.height) { + this._postApply(); + } +} + +qx.Proto._postApply = qx.lang.Function.returnTrue; + + + + + + + +/* +--------------------------------------------------------------------------- + BOX DIMENSION HELPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeBoxWidthFallback = qx.Proto.getPreferredBoxWidth; +qx.Proto._computeBoxHeightFallback = qx.Proto.getPreferredBoxHeight; + +qx.Proto._computePreferredInnerWidth = qx.lang.Function.returnZero; +qx.Proto._computePreferredInnerHeight = qx.lang.Function.returnZero; + + + + + + + +/* +--------------------------------------------------------------------------- + METHODS TO GIVE THE LAYOUTERS INFORMATIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isWidthEssential = function() +{ + if (!this._computedLeftTypeNull && !this._computedRightTypeNull) { + return true; + } + + if (!this._computedWidthTypeNull && !this._computedWidthTypeAuto) { + return true; + } + + if (!this._computedMinWidthTypeNull && !this._computedMinWidthTypeAuto) { + return true; + } + + if (!this._computedMaxWidthTypeNull && !this._computedMaxWidthTypeAuto) { + return true; + } + + if (this._borderElement) { + return true; + } + + return false; +} + +qx.Proto._isHeightEssential = function() +{ + if (!this._computedTopTypeNull && !this._computedBottomTypeNull) { + return true; + } + + if (!this._computedHeightTypeNull && !this._computedHeightTypeAuto) { + return true; + } + + if (!this._computedMinHeightTypeNull && !this._computedMinHeightTypeAuto) { + return true; + } + + if (!this._computedMaxHeightTypeNull && !this._computedMaxHeightTypeAuto) { + return true; + } + + if (this._borderElement) { + return true; + } + + return false; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js new file mode 100644 index 0000000000..32f31f2a9e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js @@ -0,0 +1,33 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.VerticalSpacer", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setHeight("1*"); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js new file mode 100644 index 0000000000..b46e1a5d1f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js @@ -0,0 +1,395 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + + +************************************************************************ */ + +/*! + A color popup +*/ +qx.OO.defineClass("qx.ui.component.ColorPopup", qx.ui.popup.Popup, +function(tables) +{ + qx.ui.popup.Popup.call(this); + + this.setPadding(4); + this.auto(); + this.setBorder(qx.renderer.border.BorderPresets.getInstance().outset); + this.setBackgroundColor("threedface"); + + this._tables = tables; + + this._createLayout(); + this._createAutoBtn(); + this._createBoxes(); + this._createPreview(); + this._createSelectorBtn(); + + this.addEventListener("beforeAppear", this._onBeforeAppear); +}); + +qx.OO.addProperty({ name : "value", type : "object", instance : "qx.renderer.color.Color" }); + +qx.OO.addProperty({ name : "red", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "green", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "blue", type : "number", defaultValue : 0 }); + +qx.Proto._minZIndex = 1e5; + + + + + +/* +--------------------------------------------------------------------------- + CREATOR SUBS +--------------------------------------------------------------------------- +*/ + +qx.Proto._createLayout = function() +{ + this._layout = new qx.ui.layout.VerticalBoxLayout; + this._layout.setLocation(0, 0); + this._layout.auto(); + this._layout.setSpacing(2); + + this.add(this._layout); +} + +qx.Proto._createAutoBtn = function() +{ + this._automaticBtn = new qx.ui.form.Button(this.tr("Automatic")); + this._automaticBtn.setWidth(null); + this._automaticBtn.setAllowStretchX(true); + this._automaticBtn.addEventListener("execute", this._onAutomaticBtnExecute, this); + + this._layout.add(this._automaticBtn); +} + +qx.Proto._recentTableId = "recent"; +qx.Proto._fieldWidth = 14; +qx.Proto._fieldHeight = 14; +qx.Proto._fieldNumber = 12; + +qx.Proto._createBoxes = function() +{ + this._boxes = {}; + + var tables = this._tables; + var table, box, boxLayout, field; + + for (var tableId in tables) + { + table = tables[tableId]; + + box = new qx.ui.groupbox.GroupBox(table.label); + box.setHeight("auto"); + + this._boxes[tableId] = box; + this._layout.add(box); + + boxLayout = new qx.ui.layout.HorizontalBoxLayout; + boxLayout.setLocation(0, 0); + boxLayout.setSpacing(1); + boxLayout.auto(); + box.add(boxLayout); + + for (var i=0; i<this._fieldNumber; i++) + { + field = new qx.ui.basic.Terminator; + + field.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + field.setBackgroundColor(table.values[i] || null); + field.setDimension(this._fieldWidth, this._fieldHeight); + + field.addEventListener("mousedown", this._onFieldMouseDown, this); + field.addEventListener("mouseover", this._onFieldMouseOver, this); + + boxLayout.add(field); + } + } +} + +qx.Proto._createPreview = function() +{ + this._previewBox = new qx.ui.groupbox.GroupBox(this.tr("Preview (Old/New)")); + this._previewLayout = new qx.ui.layout.HorizontalBoxLayout; + this._selectedPreview = new qx.ui.basic.Terminator; + this._currentPreview = new qx.ui.basic.Terminator; + + this._previewLayout.setHeight("auto"); + this._previewLayout.setWidth("100%"); + this._previewLayout.setSpacing(4); + this._previewLayout.add(this._selectedPreview, this._currentPreview); + + this._previewBox.setHeight("auto"); + this._previewBox.add(this._previewLayout); + + this._layout.add(this._previewBox); + + this._selectedPreview.setBorder(qx.renderer.border.BorderPresets.getInstance().inset); + this._selectedPreview.setWidth("1*"); + this._selectedPreview.setHeight(24); + + this._currentPreview.setBorder(qx.renderer.border.BorderPresets.getInstance().inset); + this._currentPreview.setWidth("1*"); + this._currentPreview.setHeight(24); +} + +qx.Proto._createSelectorBtn = function() +{ + this._selectorButton = new qx.ui.form.Button(this.tr("Open ColorSelector")); + this._selectorButton.setWidth(null); + this._selectorButton.setAllowStretchX(true); + this._selectorButton.addEventListener("execute", this._onSelectorButtonExecute, this); + + this._layout.add(this._selectorButton); +} + +qx.Proto._createColorSelector = function() +{ + if (this._colorSelector) { + return; + } + + this._colorSelectorWindow = new qx.ui.window.Window(this.tr("Color Selector")); + this._colorSelectorWindow.setMinWidth(null); + this._colorSelectorWindow.setMinHeight(null); + this._colorSelectorWindow.setResizeable(false); + this._colorSelectorWindow.auto(); + + this._colorSelector = new qx.ui.component.ColorSelector; + this._colorSelector.setBorder(null); + this._colorSelector.setLocation(0, 0); + this._colorSelector.addEventListener("dialogok", this._onColorSelectorOk, this); + this._colorSelector.addEventListener("dialogcancel", this._onColorSelectorCancel, this); + + this._colorSelectorWindow.add(this._colorSelector); + this._colorSelectorWindow.addToDocument(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + if (propValue === null) + { + this.setRed(null); + this.setGreen(null); + this.setBlue(null); + } + else + { + this.setRed(propValue.getRed()); + this.setGreen(propValue.getGreen()); + this.setBlue(propValue.getBlue()); + }; + + this._selectedPreview.setBackgroundColor(propValue); + this._rotatePreviousColors(); + + return true; +} + +qx.Proto._rotatePreviousColors = function() +{ + var vRecentTable = this._tables[this._recentTableId].values; + var vRecentBox = this._boxes[this._recentTableId]; + + if (!vRecentTable) { + return; + } + + var newValue = this.getValue(); + + if (!newValue) { + return; + } + + // use style compatible value (like the incoming value from the user or as RGB value string) + newValue = newValue.getStyle(); + + // Modifying incoming table + var vIndex = vRecentTable.indexOf(newValue); + + if (vIndex != -1) { + qx.lang.Array.removeAt(vRecentTable, vIndex); + } else if (vRecentTable.length == this._fieldNumber) { + vRecentTable.shift(); + } + + vRecentTable.push(newValue); + + // Sync to visible fields + var vFields = vRecentBox.getFrameObject().getFirstChild().getChildren(); + for (var i=0; i<vFields.length; i++) { + vFields[i].setBackgroundColor(vRecentTable[i] || null); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onFieldMouseDown = function(e) +{ + var vValue = this._currentPreview.getBackgroundColor(); + this.setValue(vValue); + + if (vValue) { + this.hide(); + } +} + +qx.Proto._onFieldMouseOver = function(e) { + this._currentPreview.setBackgroundColor(e.getTarget().getBackgroundColor()); +} + +qx.Proto._onAutomaticBtnExecute = function(e) { + this.setValue(null); + this.hide(); +} + +qx.Proto._onSelectorButtonExecute = function(e) +{ + this._createColorSelector(); + + this._colorSelectorWindow.setTop(qx.html.Location.getPageBoxTop(this._selectorButton.getElement()) + 10); + this._colorSelectorWindow.setLeft(qx.html.Location.getPageBoxLeft(this._selectorButton.getElement()) + 100); + + this.hide(); + + this._colorSelectorWindow.open(); +} + +qx.Proto._onColorSelectorOk = function(e) +{ + var sel = this._colorSelector; + this.setValue(qx.renderer.color.ColorCache([sel.getRed(), sel.getGreen(), sel.getBlue()])); + this._colorSelectorWindow.close(); +} + +qx.Proto._onColorSelectorCancel = function(e) { + this._colorSelectorWindow.close(); +} + +qx.Proto._onBeforeAppear = function(e) { + this._currentPreview.setBackgroundColor(null); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._tables = null; + this._boxes = null; + + if (this._layout) + { + this._layout.dispose(); + this._layout = null; + } + + if (this._automaticBtn) + { + this._automaticBtn.dispose(); + this._automaticBtn = null; + } + + if (this._previewBox) + { + this._previewBox.dispose(); + this._previewBox = null; + } + + if (this._previewLayout) + { + this._previewLayout.dispose(); + this._previewLayout = null; + } + + if (this._selectedPreview) + { + this._selectedPreview.dispose(); + this._selectedPreview = null; + } + + if (this._currentPreview) + { + this._currentPreview.dispose(); + this._currentPreview = null; + } + + if (this._selectorButton) + { + this._selectorButton.dispose(); + this._selectorButton = null; + } + + if (this._colorSelectorWindow) + { + this._colorSelectorWindow.dispose(); + this._colorSelectorWindow = null; + } + + if (this._colorSelector) + { + this._colorSelector.dispose(); + this._colorSelector = null; + } + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorSelector.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorSelector.js new file mode 100644 index 0000000000..caf1dca73b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/ColorSelector.js @@ -0,0 +1,1318 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#embed(qx.widgettheme/colorselector/*) +#embed(qx.icontheme/16/actions/dialog-cancel.png) +#embed(qx.icontheme/16/actions/dialog-ok.png) +#embed(qx.static/image/dotted_white.gif) + +************************************************************************ */ + +/** + * A typical color selector as known from native applications. + * + * Includes support for RGB and HSB color areas. + * + * @event dialogok {qx.event.type.Event} + * @event dialogcancel {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.component.ColorSelector", qx.ui.layout.VerticalBoxLayout, +function(vPreviousRed, vPreviousGreen, vPreviousBlue) +{ + qx.ui.layout.VerticalBoxLayout.call(this); + + // ******************************************** + // CREATE CHILDREN + // ******************************************** + + // 1. Base Structure (Vertical Split) + this._createControlBar(); + this._createButtonBar(); + + // 2. Panes (Horizontal Split) + this._createControlPane(); + this._createHueSaturationPane(); + this._createBrightnessPane(); + + // 3. Control Pane Content + this._createPresetFieldSet(); + this._createInputFieldSet(); + this._createPreviewFieldSet(); + + // 4. Input FieldSet Content + this._createHexField(); + this._createRgbSpinner(); + this._createHsbSpinner(); + + // 5. Preview FieldSet Content + this._createPreviewContent(); + + + // ******************************************** + // INIT COLORS + // ******************************************** + + if (arguments.length == 3) { + this.setPreviousColor(vPreviousRed, vPreviousGreen, vPreviousBlue); + } +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "colorselector" }); + +qx.OO.addProperty({ name : "red", type : "number", defaultValue : 255 }); +qx.OO.addProperty({ name : "green", type : "number", defaultValue : 255 }); +qx.OO.addProperty({ name : "blue", type : "number", defaultValue : 255 }); + +qx.OO.addProperty({ name : "hue", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "saturation", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "brightness", type : "number", defaultValue : 100 }); + +/* +--------------------------------------------------------------------------- + LOCALIZATION SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("labelOK", "OK"); +qx.Settings.setDefault("labelCancel", "Cancel"); +qx.Settings.setDefault("labelPresets", "Presets"); +qx.Settings.setDefault("labelDetails", "Details"); +qx.Settings.setDefault("labelPreview", "Preview (Old/New)"); +qx.Settings.setDefault("labelRGB", "RGB"); +qx.Settings.setDefault("labelHSB", "HSB"); +qx.Settings.setDefault("labelHex", "Hex"); + + + + +/* +--------------------------------------------------------------------------- + CONTEXT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._updateContext = null; + + + + + + + +/* +--------------------------------------------------------------------------- + CREATE #1: BASE STRUCTURE +--------------------------------------------------------------------------- +*/ + +qx.Proto._createControlBar = function() +{ + this._controlBar = new qx.ui.layout.HorizontalBoxLayout; + this._controlBar.setHeight("auto"); + this._controlBar.setParent(this); +} + +qx.Proto._createButtonBar = function() +{ + this._btnbar = new qx.ui.layout.HorizontalBoxLayout; + this._btnbar.setHeight("auto"); + this._btnbar.setSpacing(4); + this._btnbar.setHorizontalChildrenAlign("right"); + this._btnbar.setPadding(2, 4); + this.add(this._btnbar); + + this._btncancel = new qx.ui.form.Button(this.tr("Cancel"), "icon/16/actions/dialog-cancel.png"); + this._btnok = new qx.ui.form.Button(this.tr("OK"), "icon/16/actions/dialog-ok.png"); + + this._btncancel.addEventListener("execute", this._onButtonCancelExecute, this); + this._btnok.addEventListener("execute", this._onButtonOkExecute, this); + + this._btnbar.add(this._btncancel, this._btnok); +} + + + + + + +/* +--------------------------------------------------------------------------- + CREATE #2: PANES +--------------------------------------------------------------------------- +*/ + +qx.Proto._createControlPane = function() +{ + this._controlPane = new qx.ui.layout.VerticalBoxLayout; + this._controlPane.setWidth("auto"); + this._controlPane.setPadding(4); + this._controlPane.setPaddingBottom(7); + this._controlPane.setParent(this._controlBar); +} + +qx.Proto._createHueSaturationPane = function() +{ + this._hueSaturationPane = new qx.ui.layout.CanvasLayout; + this._hueSaturationPane.setWidth("auto"); + this._hueSaturationPane.setPadding(6, 4); + this._hueSaturationPane.setParent(this._controlBar); + + this._hueSaturationPane.addEventListener("mousewheel", this._onHueSaturationPaneMouseWheel, this); + + this._hueSaturationField = new qx.ui.basic.Image("widget/colorselector/huesaturation-field.jpg"); + this._hueSaturationField.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + this._hueSaturationField.setMargin(5); + this._hueSaturationField.setParent(this._hueSaturationPane); + + this._hueSaturationField.addEventListener("mousedown", this._onHueSaturationFieldMouseDown, this); + + this._hueSaturationHandle = new qx.ui.basic.Image("widget/colorselector/huesaturation-handle.gif"); + this._hueSaturationHandle.setLocation(0, 256); + this._hueSaturationHandle.setParent(this._hueSaturationPane); + + this._hueSaturationHandle.addEventListener("mousedown", this._onHueSaturationHandleMouseDown, this); + this._hueSaturationHandle.addEventListener("mouseup", this._onHueSaturationHandleMouseUp, this); + this._hueSaturationHandle.addEventListener("mousemove", this._onHueSaturationHandleMouseMove, this); +} + +qx.Proto._createBrightnessPane = function() +{ + this._brightnessPane = new qx.ui.layout.CanvasLayout; + this._brightnessPane.setWidth("auto"); + this._brightnessPane.setPadding(6, 4); + this._brightnessPane.setParent(this._controlBar); + + this._brightnessPane.addEventListener("mousewheel", this._onBrightnessPaneMouseWheel, this); + + this._brightnessField = new qx.ui.basic.Image("widget/colorselector/brightness-field.jpg"); + this._brightnessField.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + this._brightnessField.setMargin(5, 7); + this._brightnessField.setParent(this._brightnessPane); + + this._brightnessField.addEventListener("mousedown", this._onBrightnessFieldMouseDown, this); + + this._brightnessHandle = new qx.ui.basic.Image("widget/colorselector/brightness-handle.gif"); + this._brightnessHandle.setLocation(0, 0); + this._brightnessHandle.setParent(this._brightnessPane); + + this._brightnessHandle.addEventListener("mousedown", this._onBrightnessHandleMouseDown, this); + this._brightnessHandle.addEventListener("mouseup", this._onBrightnessHandleMouseUp, this); + this._brightnessHandle.addEventListener("mousemove", this._onBrightnessHandleMouseMove, this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CREATE #3: CONTROL PANE CONTENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._createPresetFieldSet = function() +{ + this._presetFieldSet = new qx.ui.groupbox.GroupBox(this.tr("Presets")); + this._presetFieldSet.setHeight("auto"); + this._presetFieldSet.setParent(this._controlPane); + + this._presetGrid = new qx.ui.layout.GridLayout; + this._presetGrid.setHorizontalSpacing(2); + this._presetGrid.setVerticalSpacing(2); + this._presetGrid.setColumnCount(11); + this._presetGrid.setRowCount(4); + this._presetGrid.setColumnWidth(0, 18); + this._presetGrid.setColumnWidth(1, 18); + this._presetGrid.setColumnWidth(2, 18); + this._presetGrid.setColumnWidth(3, 18); + this._presetGrid.setColumnWidth(4, 18); + this._presetGrid.setColumnWidth(5, 18); + this._presetGrid.setColumnWidth(6, 18); + this._presetGrid.setColumnWidth(7, 18); + this._presetGrid.setColumnWidth(8, 18); + this._presetGrid.setColumnWidth(9, 18); + + this._presetGrid.setRowHeight(0, 16); + this._presetGrid.setRowHeight(1, 16); + this._presetFieldSet.add(this._presetGrid); + + this._presetTable = [ "maroon", "red", "orange", "yellow", "olive", "purple", "fuchsia", "lime", "green", "navy", "blue", "aqua", "teal", "black", "#333", "#666", "#999", "#BBB", "#EEE", "white" ]; + + var colorField; + + for (var i=0; i<2; i++) + { + for (var j=0; j<10; j++) + { + colorField = new qx.ui.basic.Terminator; + colorField.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + colorField.setBackgroundColor(this._presetTable[i*10+j]); + colorField.addEventListener("mousedown", this._onColorFieldClick, this); + + this._presetGrid.add(colorField, j, i); + } + } +} + +qx.Proto._createInputFieldSet = function() +{ + this._inputFieldSet = new qx.ui.groupbox.GroupBox(this.tr("Details")); + this._inputFieldSet.setHeight("auto"); + this._inputFieldSet.setParent(this._controlPane); + + this._inputLayout = new qx.ui.layout.VerticalBoxLayout; + this._inputLayout.setHeight("auto"); + this._inputLayout.setSpacing(10); + this._inputLayout.setParent(this._inputFieldSet.getFrameObject()); +} + +qx.Proto._createPreviewFieldSet = function() +{ + this._previewFieldSet = new qx.ui.groupbox.GroupBox(this.tr("Preview (Old/New)")); + this._previewFieldSet.setHeight("1*"); + this._previewFieldSet.setParent(this._controlPane); + + this._previewLayout = new qx.ui.layout.HorizontalBoxLayout; + this._previewLayout.setHeight("100%"); + this._previewLayout.setLocation(0, 0); + this._previewLayout.setRight(0); + this._previewLayout.setSpacing(10); + this._previewLayout.setParent(this._previewFieldSet.getFrameObject()); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CREATE #4: INPUT FIELDSET CONTENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._createHexField = function() +{ + this._hexLayout = new qx.ui.layout.HorizontalBoxLayout; + this._hexLayout.setHeight("auto"); + this._hexLayout.setSpacing(4); + this._hexLayout.setVerticalChildrenAlign("middle"); + this._hexLayout.setParent(this._inputLayout); + + this._hexLabel = new qx.ui.basic.Label(this.tr("Hex")); + this._hexLabel.setWidth(25); + this._hexLabel.setParent(this._hexLayout); + + this._hexHelper = new qx.ui.basic.Label("#"); + this._hexHelper.setParent(this._hexLayout); + + this._hexField = new qx.ui.form.TextField("FFFFFF"); + this._hexField.setWidth(50); + this._hexField.setFont('11px "Bitstream Vera Sans Mono", monospace'); + this._hexField.setParent(this._hexLayout); + + this._hexField.addEventListener("changeValue", this._onHexFieldChange, this); +} + +qx.Proto._createRgbSpinner = function() +{ + this._rgbSpinLayout = new qx.ui.layout.HorizontalBoxLayout; + this._rgbSpinLayout.setHeight("auto"); + this._rgbSpinLayout.setSpacing(4); + this._rgbSpinLayout.setVerticalChildrenAlign("middle"); + this._rgbSpinLayout.setParent(this._inputLayout); + + this._rgbSpinLabel = new qx.ui.basic.Label(this.tr("RGB")); + this._rgbSpinLabel.setWidth(25); + this._rgbSpinLabel.setParent(this._rgbSpinLayout); + + this._rgbSpinRed = new qx.ui.form.Spinner(0, 255, 255); + this._rgbSpinRed.setWidth(50); + + this._rgbSpinGreen = new qx.ui.form.Spinner(0, 255, 255); + this._rgbSpinGreen.setWidth(50); + + this._rgbSpinBlue = new qx.ui.form.Spinner(0, 255, 255); + this._rgbSpinBlue.setWidth(50); + + this._rgbSpinLayout.add(this._rgbSpinRed, this._rgbSpinGreen, this._rgbSpinBlue); + + this._rgbSpinRed.addEventListener("change", this._setRedFromSpinner, this); + this._rgbSpinGreen.addEventListener("change", this._setGreenFromSpinner, this); + this._rgbSpinBlue.addEventListener("change", this._setBlueFromSpinner, this); +} + +qx.Proto._createHsbSpinner = function() +{ + this._hsbSpinLayout = new qx.ui.layout.HorizontalBoxLayout; + this._hsbSpinLayout.setHeight("auto"); + this._hsbSpinLayout.setSpacing(4); + this._hsbSpinLayout.setVerticalChildrenAlign("middle"); + this._hsbSpinLayout.setParent(this._inputLayout); + + this._hsbSpinLabel = new qx.ui.basic.Label(this.tr("HSB")); + this._hsbSpinLabel.setWidth(25); + this._hsbSpinLayout.add(this._hsbSpinLabel); + + this._hsbSpinHue = new qx.ui.form.Spinner(0, 0, 360); + this._hsbSpinHue.setWidth(50); + + this._hsbSpinSaturation = new qx.ui.form.Spinner(0, 0, 100); + this._hsbSpinSaturation.setWidth(50); + + this._hsbSpinBrightness = new qx.ui.form.Spinner(0, 100, 100); + this._hsbSpinBrightness.setWidth(50); + + this._hsbSpinLayout.add(this._hsbSpinHue, this._hsbSpinSaturation, this._hsbSpinBrightness); + + this._hsbSpinHue.addEventListener("change", this._setHueFromSpinner, this); + this._hsbSpinSaturation.addEventListener("change", this._setSaturationFromSpinner, this); + this._hsbSpinBrightness.addEventListener("change", this._setBrightnessFromSpinner, this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CREATE #5: PREVIEW CONTENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._createPreviewContent = function() +{ + this._oldColorPreview = new qx.ui.basic.Terminator; + this._oldColorPreview.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + this._oldColorPreview.setWidth("1*"); + this._oldColorPreview.setBackgroundImage("static/image/dotted_white.gif"); + this._oldColorPreview.setParent(this._previewLayout); + + this._newColorPreview = new qx.ui.basic.Terminator; + this._newColorPreview.setBorder(qx.renderer.border.BorderPresets.getInstance().thinInset); + this._newColorPreview.setWidth("1*"); + this._newColorPreview.setBackgroundColor("white"); + this._newColorPreview.setParent(this._previewLayout); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + RGB MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyRed = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "redModifier"; + } + + if (this._updateContext !== "rgbSpinner") { + this._rgbSpinRed.setValue(propValue); + } + + if (this._updateContext !== "hexField") { + this._setHexFromRgb(); + } + + switch(this._updateContext) + { + case "rgbSpinner": + case "hexField": + case "redModifier": + this._setHueFromRgb(); + } + + this._setPreviewFromRgb(); + + if (this._updateContext === "redModifier") { + this._updateContext = null; + } + + return true; +} + +qx.Proto._modifyGreen = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "greenModifier"; + } + + if (this._updateContext !== "rgbSpinner") { + this._rgbSpinGreen.setValue(propValue); + } + + if (this._updateContext !== "hexField") { + this._setHexFromRgb(); + } + + switch(this._updateContext) + { + case "rgbSpinner": + case "hexField": + case "greenModifier": + this._setHueFromRgb(); + } + + this._setPreviewFromRgb(); + + if (this._updateContext === "greenModifier") { + this._updateContext = null; + } + + return true; +} + +qx.Proto._modifyBlue = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "blueModifier"; + } + + if (this._updateContext !== "rgbSpinner") { + this._rgbSpinBlue.setValue(propValue); + } + + if (this._updateContext !== "hexField") { + this._setHexFromRgb(); + } + + switch(this._updateContext) + { + case "rgbSpinner": + case "hexField": + case "blueModifier": + this._setHueFromRgb(); + } + + this._setPreviewFromRgb(); + + if (this._updateContext === "blueModifier") { + this._updateContext = null; + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + HSB MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyHue = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "hueModifier"; + } + + if (this._updateContext !== "hsbSpinner") { + this._hsbSpinHue.setValue(propValue); + } + + if (this._updateContext !== "hueSaturationField") + { + if (this._hueSaturationHandle.isCreated()) + { + this._hueSaturationHandle._applyRuntimeLeft(Math.round(propValue / 1.40625) + this._hueSaturationPane.getPaddingLeft()); + } + else + { + this._hueSaturationHandle.setLeft(Math.round(propValue / 1.40625)); + } + } + + switch(this._updateContext) + { + case "hsbSpinner": + case "hueSaturationField": + case "hueModifier": + this._setRgbFromHue(); + } + + if (this._updateContext === "hueModifier") { + this._updateContext = null; + } + + return true; +} + +qx.Proto._modifySaturation = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "saturationModifier"; + } + + if (this._updateContext !== "hsbSpinner") { + this._hsbSpinSaturation.setValue(propValue); + } + + if (this._updateContext !== "hueSaturationField") + { + if (this._hueSaturationHandle.isCreated()) + { + this._hueSaturationHandle._applyRuntimeTop(256 - Math.round(propValue * 2.56) + this._hueSaturationPane.getPaddingTop()); + } + else + { + this._hueSaturationHandle.setTop(256 - Math.round(propValue * 2.56)); + } + } + + switch(this._updateContext) + { + case "hsbSpinner": + case "hueSaturationField": + case "saturationModifier": + this._setRgbFromHue(); + } + + if (this._updateContext === "saturationModifier") { + this._updateContext = null; + } + + return true; +} + +qx.Proto._modifyBrightness = function(propValue, propOldValue, propData) +{ + if (this._updateContext === null) { + this._updateContext = "brightnessModifier"; + } + + if (this._updateContext !== "hsbSpinner") { + this._hsbSpinBrightness.setValue(propValue); + } + + if (this._updateContext !== "brightnessField") + { + var topValue = 256 - Math.round(propValue * 2.56); + + if (this._brightnessHandle.isCreated()) + { + this._brightnessHandle._applyRuntimeTop(topValue + this._brightnessPane.getPaddingTop()); + } + else + { + this._brightnessHandle.setTop(topValue); + } + } + + switch(this._updateContext) + { + case "hsbSpinner": + case "brightnessField": + case "brightnessModifier": + this._setRgbFromHue(); + } + + if (this._updateContext === "brightnessModifier") { + this._updateContext = null; + } + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + BRIGHTNESS IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._onBrightnessHandleMouseDown = function(e) +{ + // Activate Capturing + this._brightnessHandle.setCapture(true); + + // Calculate subtract: Position of Brightness Field - Current Mouse Offset + this._brightnessSubtract = qx.html.Location.getPageOuterTop(this._brightnessField.getElement()) + (e.getPageY() - qx.html.Location.getPageBoxTop(this._brightnessHandle.getElement())); + + // Block field event handling + e.setPropagationStopped(true); +} + +qx.Proto._onBrightnessHandleMouseUp = function(e) +{ + // Disabling capturing + this._brightnessHandle.setCapture(false); +} + +qx.Proto._onBrightnessHandleMouseMove = function(e) +{ + // Update if captured currently (through previous mousedown) + if (this._brightnessHandle.getCapture()) { + this._setBrightnessOnFieldEvent(e); + } +} + +qx.Proto._onBrightnessFieldMouseDown = function(e) +{ + // Calculate substract: Half height of handler + this._brightnessSubtract = qx.html.Location.getPageOuterTop(this._brightnessField.getElement()) + Math.round(qx.html.Dimension.getBoxHeight(this._brightnessHandle.getElement()) / 2); + + // Update + this._setBrightnessOnFieldEvent(e); + + // Afterwards: Activate Capturing for handle + this._brightnessHandle.setCapture(true); +} + +qx.Proto._onBrightnessPaneMouseWheel = function(e) { + this.setBrightness(qx.lang.Number.limit(this.getBrightness() + e.getWheelDelta(), 0, 100)); +} + +qx.Proto._setBrightnessOnFieldEvent = function(e) +{ + var vValue = qx.lang.Number.limit(e.getPageY() - this._brightnessSubtract, 0, 256); + + this._updateContext = "brightnessField"; + + if (this._brightnessHandle.isCreated()) + { + this._brightnessHandle._applyRuntimeTop(vValue + this._brightnessPane.getPaddingTop()); + } + else + { + this._brightnessHandle.setTop(vValue); + } + + this.setBrightness(100-Math.round(vValue / 2.56)); + + this._updateContext = null; +} + +qx.Proto._onButtonOkExecute = function(e) { + this.createDispatchEvent("dialogok"); +} + +qx.Proto._onButtonCancelExecute = function(e) { + this.createDispatchEvent("dialogcancel"); +} + + + + + + +/* +--------------------------------------------------------------------------- + HUE/SATURATION IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._onHueSaturationHandleMouseDown = function(e) +{ + // Activate Capturing + this._hueSaturationHandle.setCapture(true); + + // Calculate subtract: Position of HueSaturation Field - Current Mouse Offset + this._hueSaturationSubtractTop = qx.html.Location.getPageOuterTop(this._hueSaturationField.getElement()) + (e.getPageY() - qx.html.Location.getPageBoxTop(this._hueSaturationHandle.getElement())); + this._hueSaturationSubtractLeft = qx.html.Location.getPageOuterLeft(this._hueSaturationField.getElement()) + (e.getPageX() - qx.html.Location.getPageBoxLeft(this._hueSaturationHandle.getElement())); + + // Block field event handling + e.setPropagationStopped(true); +} + +qx.Proto._onHueSaturationHandleMouseUp = function(e) +{ + // Disabling capturing + this._hueSaturationHandle.setCapture(false); +} + +qx.Proto._onHueSaturationHandleMouseMove = function(e) +{ + // Update if captured currently (through previous mousedown) + if (this._hueSaturationHandle.getCapture()) { + this._setHueSaturationOnFieldEvent(e); + } +} + +qx.Proto._onHueSaturationFieldMouseDown = function(e) +{ + // Calculate substract: Half width/height of handler + this._hueSaturationSubtractTop = qx.html.Location.getPageOuterTop(this._hueSaturationField.getElement()) + Math.round(qx.html.Dimension.getBoxHeight(this._hueSaturationHandle.getElement()) / 2); + this._hueSaturationSubtractLeft = qx.html.Location.getPageOuterLeft(this._hueSaturationField.getElement()) + Math.round(qx.html.Dimension.getBoxWidth(this._hueSaturationHandle.getElement()) / 2); + + // Update + this._setHueSaturationOnFieldEvent(e); + + // Afterwards: Activate Capturing for handle + this._hueSaturationHandle.setCapture(true); +} + +qx.Proto._onHueSaturationPaneMouseWheel = function(e) { + this.setSaturation(qx.lang.Number.limit(this.getSaturation() + e.getWheelDelta(), 0, 100)); +} + +qx.Proto._setHueSaturationOnFieldEvent = function(e) +{ + var vTop = qx.lang.Number.limit(e.getPageY() - this._hueSaturationSubtractTop, 0, 256); + var vLeft = qx.lang.Number.limit(e.getPageX() - this._hueSaturationSubtractLeft, 0, 256); + + if (this._hueSaturationHandle.isCreated()) + { + this._hueSaturationHandle._applyRuntimeTop(vTop + this._hueSaturationPane.getPaddingTop()); + this._hueSaturationHandle._applyRuntimeLeft(vLeft + this._hueSaturationPane.getPaddingLeft()); + } + else + { + this._hueSaturationHandle.setTop(vTop); + this._hueSaturationHandle.setLeft(vLeft); + } + + this._updateContext = "hueSaturationField"; + + this.setSaturation(100-Math.round(vTop / 2.56)); + this.setHue(Math.round(vLeft * 1.40625)); + + this._updateContext = null; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + RGB SPINNER +--------------------------------------------------------------------------- +*/ + +qx.Proto._setRedFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "rgbSpinner"; + this.setRed(this._rgbSpinRed.getValue()); + this._updateContext = null; +} + +qx.Proto._setGreenFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "rgbSpinner"; + this.setGreen(this._rgbSpinGreen.getValue()); + this._updateContext = null; +} + +qx.Proto._setBlueFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "rgbSpinner"; + this.setBlue(this._rgbSpinBlue.getValue()); + this._updateContext = null; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + HSB SPINNER +--------------------------------------------------------------------------- +*/ + +qx.Proto._setHueFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "hsbSpinner"; + this.setHue(this._hsbSpinHue.getValue()); + this._updateContext = null; +} + +qx.Proto._setSaturationFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "hsbSpinner"; + this.setSaturation(this._hsbSpinSaturation.getValue()); + this._updateContext = null; +} + +qx.Proto._setBrightnessFromSpinner = function() +{ + if (this._updateContext !== null) { + return; + } + + this._updateContext = "hsbSpinner"; + this.setBrightness(this._hsbSpinBrightness.getValue()); + this._updateContext = null; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + HEX FIELD +--------------------------------------------------------------------------- +*/ + +qx.Proto._onHexFieldChange = function(e) +{ + if (this._updateContext !== null) { + return; + } + + var vValue = this._hexField.getValue().toLowerCase(); + + var vRed = 0; + var vGreen = 0; + var vBlue = 0; + + switch(vValue.length) + { + case 3: + vRed = qx.renderer.color.Color.m_rgb[vValue.charAt(0)]; + vGreen = qx.renderer.color.Color.m_rgb[vValue.charAt(1)]; + vBlue = qx.renderer.color.Color.m_rgb[vValue.charAt(2)]; + + vRed = (vRed * 16) + vRed; + vGreen = (vGreen * 16) + vGreen; + vBlue = (vBlue * 16) + vBlue; + + break; + + case 6: + vRed = (qx.renderer.color.Color.m_rgb[vValue.charAt(0)] * 16) + qx.renderer.color.Color.m_rgb[vValue.charAt(1)]; + vGreen = (qx.renderer.color.Color.m_rgb[vValue.charAt(2)] * 16) + qx.renderer.color.Color.m_rgb[vValue.charAt(3)]; + vBlue = (qx.renderer.color.Color.m_rgb[vValue.charAt(4)] * 16) + qx.renderer.color.Color.m_rgb[vValue.charAt(5)]; + + break; + + default: + return false; + } + + this._updateContext = "hexField"; + + this.setRed(vRed); + this.setGreen(vGreen); + this.setBlue(vBlue); + + this._updateContext = null; +} + +qx.Proto._setHexFromRgb = function() { + this._hexField.setValue(qx.lang.String.pad(this.getRed().toString(16).toUpperCase(), 2) + qx.lang.String.pad(this.getGreen().toString(16).toUpperCase(), 2) + qx.lang.String.pad(this.getBlue().toString(16).toUpperCase(), 2)); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + COLOR FIELD +--------------------------------------------------------------------------- +*/ + +qx.Proto._onColorFieldClick = function(e) +{ + var vColor = e.getTarget().getBackgroundColor(); + + if (!vColor) { + return this.error("Missing backgroundColor value for field: " + e.getTarget()); + } + + this.setRed(vColor.getRed()); + this.setGreen(vColor.getGreen()); + this.setBlue(vColor.getBlue()); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + RGB/HSB SYNC +--------------------------------------------------------------------------- +*/ + +qx.Proto._setHueFromRgb = function() +{ + switch(this._updateContext) + { + case "hsbSpinner": + case "hueSaturationField": + case "brightnessField": + break; + + default: + var vHsb = qx.util.ColorUtil.rgb2hsb(this.getRed(), this.getGreen(), this.getBlue()); + + this.setHue(vHsb.hue); + this.setSaturation(vHsb.saturation); + this.setBrightness(vHsb.brightness); + } +} + +qx.Proto._setRgbFromHue = function() +{ + switch(this._updateContext) + { + case "rgbSpinner": + case "hexField": + break; + + default: + var vRgb = qx.util.ColorUtil.hsb2rgb(this.getHue(), this.getSaturation(), this.getBrightness()); + + this.setRed(vRgb.red); + this.setGreen(vRgb.green); + this.setBlue(vRgb.blue); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + PREVIEW SYNC +--------------------------------------------------------------------------- +*/ + +qx.Proto._setPreviewFromRgb = function() +{ + if (this._newColorPreview.isCreated()) + { + // faster (omit qx.renderer.color.Color instances) + this._newColorPreview._style.backgroundColor = qx.renderer.color.Color.rgb2style(this.getRed(), this.getGreen(), this.getBlue()); + } + else + { + this._newColorPreview.setBackgroundColor([this.getRed(), this.getGreen(), this.getBlue()]); + } +} + +qx.Proto.setPreviousColor = function(vRed, vGreen, vBlue) +{ + this._oldColorPreview.setBackgroundImage(null); + this._oldColorPreview.setBackgroundColor([vRed, vGreen, vBlue]); + + this.setRed(vRed); + this.setGreen(vGreen); + this.setBlue(vBlue); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._controlBar) + { + this._controlBar.dispose(); + this._controlBar = null; + } + + if (this._btnbar) + { + this._btnbar.dispose(); + this._btnbar = null; + } + + if (this._btncancel) + { + this._btncancel.dispose(); + this._btncancel = null; + } + + if (this._btnok) + { + this._btnok.dispose(); + this._btnok = null; + } + + if (this._controlPane) + { + this._controlPane.dispose(); + this._controlPane = null; + } + + if (this._hueSaturationPane) + { + this._hueSaturationPane.removeEventListener("mousewheel", this._onHueSaturationPaneMouseWheel, this); + this._hueSaturationPane.dispose(); + this._hueSaturationPane = null; + } + + if (this._hueSaturationField) + { + this._hueSaturationField.removeEventListener("mousedown", this._onHueSaturationFieldMouseDown, this); + this._hueSaturationField.dispose(); + this._hueSaturationField = null; + } + + if (this._hueSaturationHandle) + { + this._hueSaturationHandle.removeEventListener("mousedown", this._onHueSaturationHandleMouseDown, this); + this._hueSaturationHandle.removeEventListener("mouseup", this._onHueSaturationHandleMouseUp, this); + this._hueSaturationHandle.removeEventListener("mousemove", this._onHueSaturationHandleMouseMove, this); + this._hueSaturationHandle.dispose(); + this._hueSaturationHandle = null; + } + + if (this._brightnessPane) + { + this._brightnessPane.removeEventListener("mousewheel", this._onBrightnessPaneMouseWheel, this); + this._brightnessPane.dispose(); + this._brightnessPane = null; + } + + if (this._brightnessField) + { + this._brightnessField.removeEventListener("mousedown", this._onBrightnessFieldMouseDown, this); + this._brightnessField.dispose(); + this._brightnessField = null; + } + + if (this._brightnessHandle) + { + this._brightnessHandle.removeEventListener("mousedown", this._onBrightnessHandleMouseDown, this); + this._brightnessHandle.removeEventListener("mouseup", this._onBrightnessHandleMouseUp, this); + this._brightnessHandle.removeEventListener("mousemove", this._onBrightnessHandleMouseMove, this); + this._brightnessHandle.dispose(); + this._brightnessHandle = null; + } + + if (this._presetFieldSet) + { + this._presetFieldSet.dispose(); + this._presetFieldSet = null; + } + + if (this._presetGrid) + { + this._presetGrid.dispose(); + this._presetGrid = null; + } + + this._presetTable = null; + + if (this._inputFieldSet) + { + this._inputFieldSet.dispose(); + this._inputFieldSet = null; + } + + if (this._inputLayout) + { + this._inputLayout.dispose(); + this._inputLayout = null; + } + + if (this._previewFieldSet) + { + this._previewFieldSet.dispose(); + this._previewFieldSet = null; + } + + if (this._previewLayout) + { + this._previewLayout.dispose(); + this._previewLayout = null; + } + + if (this._hexLayout) + { + this._hexLayout.dispose(); + this._hexLayout = null; + } + + if (this._hexLabel) + { + this._hexLabel.dispose(); + this._hexLabel = null; + } + + if (this._hexHelper) + { + this._hexHelper.dispose(); + this._hexHelper = null; + } + + if (this._hexField) + { + this._hexField.addEventListener("changeValue", this._onHexFieldChange, this); + this._hexField.dispose(); + this._hexField = null; + } + + if (this._rgbSpinLayout) + { + this._rgbSpinLayout.dispose(); + this._rgbSpinLayout = null; + } + + if (this._rgbSpinLabel) + { + this._rgbSpinLabel.dispose(); + this._rgbSpinLabel = null; + } + + if (this._rgbSpinRed) + { + this._rgbSpinRed.removeEventListener("change", this._setRedFromSpinner, this); + this._rgbSpinRed.dispose(); + this._rgbSpinRed = null; + } + + if (this._rgbSpinGreen) + { + this._rgbSpinGreen.removeEventListener("change", this._setGreenFromSpinner, this); + this._rgbSpinGreen.dispose(); + this._rgbSpinGreen = null; + } + + if (this._rgbSpinBlue) + { + this._rgbSpinBlue.removeEventListener("change", this._setBlueFromSpinner, this); + this._rgbSpinBlue.dispose(); + this._rgbSpinBlue = null; + } + + if (this._hsbSpinLayout) + { + this._hsbSpinLayout.dispose(); + this._hsbSpinLayout = null; + } + + if (this._hsbSpinLabel) + { + this._hsbSpinLabel.dispose(); + this._hsbSpinLabel = null; + } + + if (this._hsbSpinHue) + { + this._hsbSpinHue.removeEventListener("change", this._setHueFromSpinner, this); + this._hsbSpinHue.dispose(); + this._hsbSpinHue = null; + } + + if (this._hsbSpinSaturation) + { + this._hsbSpinSaturation.removeEventListener("change", this._setSaturationFromSpinner, this); + this._hsbSpinSaturation.dispose(); + this._hsbSpinSaturation = null; + } + + if (this._hsbSpinBrightness) + { + this._hsbSpinBrightness.removeEventListener("change", this._setBrightnessFromSpinner, this); + this._hsbSpinBrightness.dispose(); + this._hsbSpinBrightness = null; + } + + if (this._oldColorPreview) + { + this._oldColorPreview.dispose(); + this._oldColorPreview = null; + } + + if (this._newColorPreview) + { + this._newColorPreview.dispose(); + this._newColorPreview = null; + } + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooser.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooser.js new file mode 100644 index 0000000000..cf32dcbbd8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooser.js @@ -0,0 +1,510 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.util.format.DateFormat) +#embed(qx.widgettheme/datechooser/*) + +************************************************************************ */ + +/** + * Shows calendar and allows choosing a date. + * + * @param date {Date ? null} The initial date to show. If <code>null</code> + * the current day (today) is shown. + * + * @event select {qx.event.type.DataEvent} Fired when a date was selected. The + * event holds the new selected date in its data property. + */ +qx.OO.defineClass("qx.ui.component.DateChooser", qx.ui.layout.BoxLayout, +function(date) { + qx.ui.layout.BoxLayout.call(this); + + this.setOrientation("vertical"); + + // Create the navigation bar + var navBar = new qx.ui.layout.BoxLayout; + navBar.set({ width:null, height:"auto", spacing:1 }); + + var lastYearBt = new qx.ui.toolbar.Button(null, "widget/datechooser/lastYear.png"); + var lastMonthBt = new qx.ui.toolbar.Button(null, "widget/datechooser/lastMonth.png"); + var monthYearLabel = new qx.ui.basic.Label; + var nextMonthBt = new qx.ui.toolbar.Button(null, "widget/datechooser/nextMonth.png"); + var nextYearBt = new qx.ui.toolbar.Button(null, "widget/datechooser/nextYear.png"); + + lastYearBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip(this.tr("Last year")), spacing:0 }); + lastMonthBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip(this.tr("Last month")) }); + nextMonthBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip(this.tr("Next month")) }); + nextYearBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip(this.tr("Next year")) }); + + lastYearBt.setAppearance("datechooser-toolbar-button"); + lastMonthBt.setAppearance("datechooser-toolbar-button"); + nextMonthBt.setAppearance("datechooser-toolbar-button"); + nextYearBt.setAppearance("datechooser-toolbar-button"); + + lastYearBt.addEventListener("click", this._onNavButtonClicked, this); + lastMonthBt.addEventListener("click", this._onNavButtonClicked, this); + nextMonthBt.addEventListener("click", this._onNavButtonClicked, this); + nextYearBt.addEventListener("click", this._onNavButtonClicked, this); + + this._lastYearBt = lastYearBt; + this._lastMonthBt = lastMonthBt; + this._nextMonthBt = nextMonthBt; + this._nextYearBt = nextYearBt; + + monthYearLabel.setAppearance("datechooser-monthyear"); + monthYearLabel.set({ width:"1*" }); + + navBar.add(lastYearBt, lastMonthBt, monthYearLabel, nextMonthBt, nextYearBt); + this._monthYearLabel = monthYearLabel; + navBar.setHtmlAttribute("id", "navBar"); + + // Calculate the cell width and height + var testLabel = new qx.ui.basic.Label; + var testParent = new qx.ui.layout.CanvasLayout; + testParent.add(testLabel); + testLabel.setHtml("Xx"); + testLabel.set({ paddingLeft : 5, paddingRight : 5 }); + testLabel.setAppearance("datechooser-weekday"); + var cellWidth = testLabel.getBoxWidth(); + var cellHeight = testLabel.getBoxHeight(); + testLabel.dispose(); + testParent.dispose(); + + // Create the date pane + var datePane = new qx.ui.layout.GridLayout; + datePane.setAppearance("datechooser-datepane"); + datePane.set({ width:"100%", height:"auto" }); + datePane.setColumnCount(8); + datePane.setRowCount(7); + for (var i = 0; i < datePane.getColumnCount(); i++) { + datePane.setColumnWidth(i, cellWidth); + } + for (var i = 0; i < datePane.getRowCount(); i++) { + datePane.setRowHeight(i, cellHeight); + } + + // Create the weekdays + // Add an empty label as spacer for the week numbers + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-week"); + label.set({ width:"100%", height:"100%" }); + label.addState("header"); + datePane.add(label, 0, 0); + + this._weekdayLabelArr = []; + for (var i = 0; i < 7; i++) { + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-weekday"); + label.set({ width:"100%", height:"100%" }); + datePane.add(label, i + 1, 0); + this._weekdayLabelArr.push(label); + } + + // Add the days + this._dayLabelArr = []; + this._weekLabelArr = []; + for (var y = 0; y < 6; y++) { + // Add the week label + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-week"); + label.set({ width:"100%", height:"100%" }); + datePane.add(label, 0, y + 1); + this._weekLabelArr.push(label); + + // Add the day labels + for (var x = 0; x < 7; x++) { + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-day"); + label.set({ width:"100%", height:"100%" }); + label.addEventListener("mousedown", this._onDayClicked, this); + label.addEventListener("dblclick", this._onDayDblClicked, this); + datePane.add(label, x + 1, y + 1); + this._dayLabelArr.push(label); + } + } + + // Make focusable + this.setTabIndex(1); + this.addEventListener("keypress", this._onkeypress); + + // Show the right date + var shownDate = (date != null) ? date : new Date(); + this.showMonth(shownDate.getMonth(), shownDate.getFullYear()); + + // listen for locale changes + qx.locale.Manager.getInstance().addEventListener("changeLocale", this._updateDatePane, this); + + // Add the main widgets + this.add(navBar); + this.add(datePane); + +}); + + +// ***** Properties ***** + +/** The currently shown month. 0 = january, 1 = february, and so on. */ +qx.OO.addProperty({ name:"shownMonth", type:"number", defaultValue:null }); +/** The currently shown year. */ +qx.OO.addProperty({ name:"shownYear", type:"number", defaultValue:null }); +/** {Date} The currently selected date. */ +qx.OO.addProperty({ name:"date", type:"object", defaultValue:null }); + + +// property checker +qx.Proto._checkDate = function(propValue, propData) { + // Use a clone of the date internally since date instances may be changed + return (propValue == null) ? null : new Date(propValue.getTime()); +} + + +// property modifier +qx.Proto._modifyDate = function(propValue, propOldValue, propData) { + var DateChooser = qx.ui.component.DateChooser; + + if ((propValue != null) && (this.getShownMonth() != propValue.getMonth() + || this.getShownYear() != propValue.getFullYear())) + { + // The new date is in another month -> Show that month + this.showMonth(propValue.getMonth(), propValue.getFullYear()); + } else { + // The new date is in the current month -> Just change the states + var newDay = (propValue == null) ? -1 : propValue.getDate(); + for (var i = 0; i < 6 * 7; i++) { + var dayLabel = this._dayLabelArr[i]; + + if (dayLabel.hasState("otherMonth")) { + if (dayLabel.hasState("selected")) { + dayLabel.removeState("selected"); + } + } else { + var day = parseInt(dayLabel.getHtml()); + if (day == newDay) { + dayLabel.addState("selected"); + } else if (dayLabel.hasState("selected")) { + dayLabel.removeState("selected"); + } + } + } + } + + return true; +} + + +/** + * Event handler. Called when a navigation button has been clicked. + * + * @param evt {Map} the event. + */ +qx.Proto._onNavButtonClicked = function(evt) { + var year = this.getShownYear(); + var month = this.getShownMonth(); + + switch(evt.getCurrentTarget()) { + case this._lastYearBt: + year--; + break; + case this._lastMonthBt: + month--; + if (month < 0) { + month = 11; + year--; + } + break; + case this._nextMonthBt: + month++; + if (month >= 12) { + month = 0; + year++; + } + break; + case this._nextYearBt: + year++; + break; + } + + this.showMonth(month, year); +} + + +/** + * Event handler. Called when a day has been clicked. + * + * @param evt {Map} the event. + */ +qx.Proto._onDayClicked = function(evt) { + var time = evt.getCurrentTarget().dateTime; + this.setDate(new Date(time)); +} + +qx.Proto._onDayDblClicked = function() { + this.createDispatchDataEvent("select", this.getDate()); +} + +/** + * Event handler. Called when a key was pressed. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeypress = function(evt) { + var dayIncrement = null; + var monthIncrement = null; + var yearIncrement = null; + if (evt.getModifiers() == 0) { + switch(evt.getKeyIdentifier()) { + case "Left": + dayIncrement = -1; + break; + case "Right": + dayIncrement = 1; + break; + case "Up": + dayIncrement = -7; + break; + case "Down": + dayIncrement = 7; + break; + case "PageUp": + monthIncrement = -1; + break; + case "PageDown": + monthIncrement = 1; + break; + case "Escape": + if (this.getDate() != null) { + this.setDate(null); + return true; + } + break; + case "Enter": + case "Space": + if (this.getDate() != null) { + this.createDispatchDataEvent("select", this.getDate()); + } + return; + } + } else if (evt.isShiftPressed()) { + switch(evt.getKeyIdentifier()) { + case "PageUp": + yearIncrement = -1; + break; + case "PageDown": + yearIncrement = 1; + break; + } + } + + if (dayIncrement != null || monthIncrement != null || yearIncrement != null) { + var date = this.getDate(); + if (date != null) { + date = new Date(date.getTime()); // TODO: Do cloning in getter + } + if (date == null) { + date = new Date(); + } else { + if (dayIncrement != null) date.setDate(date.getDate() + dayIncrement); + if (monthIncrement != null) date.setMonth(date.getMonth() + monthIncrement); + if (yearIncrement != null) date.setFullYear(date.getFullYear() + yearIncrement); + } + this.setDate(date); + } +} + + +// ***** Methods ***** + + +/** + * Shows a certain month. + * + * @param month {Integer ? null} the month to show (0 = january). If not set the month + * will remain the same. + * @param year {Integer ? null} the year to show. If not set the year will remain the + * same. + */ +qx.Proto.showMonth = function(month, year) { + if ((month != null && month != this.getShownMonth()) + || (year != null && year != this.getShownYear())) + { + if (month != null) { + this.setShownMonth(month); + } + if (year != null) { + this.setShownYear(year); + } + + this._updateDatePane(); + } +} + + +/** + * Updates the date pane. + */ +qx.Proto._updateDatePane = function() { + var DateChooser = qx.ui.component.DateChooser; + + var today = new Date(); + var todayYear = today.getFullYear(); + var todayMonth = today.getMonth(); + var todayDayOfMonth = today.getDate(); + + var selDate = this.getDate(); + var selYear = (selDate == null) ? -1 : selDate.getFullYear(); + var selMonth = (selDate == null) ? -1 : selDate.getMonth(); + var selDayOfMonth = (selDate == null) ? -1 : selDate.getDate(); + + var shownMonth = this.getShownMonth(); + var shownYear = this.getShownYear(); + + var startOfWeek = qx.locale.Date.getWeekStart(); + + // Create a help date that points to the first of the current month + var helpDate = new Date(this.getShownYear(), this.getShownMonth(), 1); + + this._monthYearLabel.setHtml((new qx.util.format.DateFormat(DateChooser.MONTH_YEAR_FORMAT)).format(helpDate)); + + // Show the day names + var firstDayOfWeek = helpDate.getDay(); + var firstSundayInMonth = (1 + 7 - firstDayOfWeek) % 7; + for (var i = 0; i < 7; i++) { + var day = (i + startOfWeek) % 7; + + var dayLabel = this._weekdayLabelArr[i]; + + helpDate.setDate(firstSundayInMonth + day); + dayLabel.setHtml(DateChooser.WEEKDAY_FORMAT.format(helpDate)); + + if (qx.locale.Date.isWeekend(day)) { + dayLabel.addState("weekend"); + } else { + dayLabel.removeState("weekend"); + } + } + + // Show the days + helpDate = new Date(shownYear, shownMonth, 1); + var nrDaysOfLastMonth = (7 + firstDayOfWeek - startOfWeek) % 7; + helpDate.setDate(helpDate.getDate() - nrDaysOfLastMonth); + for (var week = 0; week < 6; week++) { + this._weekLabelArr[week].setHtml(DateChooser.WEEK_FORMAT.format(helpDate)); + + for (var i = 0; i < 7; i++) { + var dayLabel = this._dayLabelArr[week * 7 + i]; + + var year = helpDate.getFullYear(); + var month = helpDate.getMonth(); + var dayOfMonth = helpDate.getDate(); + + var isSelectedDate = (selYear == year && selMonth == month && selDayOfMonth == dayOfMonth); + if (isSelectedDate) { + dayLabel.addState("selected"); + } else { + dayLabel.removeState("selected"); + } + + if (month != shownMonth) { + dayLabel.addState("otherMonth"); + } else { + dayLabel.removeState("otherMonth"); + } + + var isToday = (year == todayYear && month == todayMonth && dayOfMonth == todayDayOfMonth); + if (isToday) { + dayLabel.addState("today"); + } else { + dayLabel.removeState("today"); + } + + dayLabel.setHtml("" + dayOfMonth); + dayLabel.dateTime = helpDate.getTime(); + + // Go to the next day + helpDate.setDate(helpDate.getDate() + 1); + } + } +} + + +/** + * {string} The format for the date year + * label at the top center. + */ +qx.Class.MONTH_YEAR_FORMAT = qx.locale.Date.getDateTimeFormat("yyyyMMMM", "MMMM yyyy"); + +/** + * {qx.util.format.DateFormat} The format for the weekday + * labels (the headers of the date table). + */ +qx.Class.WEEKDAY_FORMAT = new qx.util.format.DateFormat("EE"); + +/** + * {qx.util.format.DateFormat} The format for the week labels. + */ +qx.Class.WEEK_FORMAT = new qx.util.format.DateFormat("ww"); + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + this._lastYearBt.removeEventListener("click", this._onNavButtonClicked, this); + this._lastMonthBt.removeEventListener("click", this._onNavButtonClicked, this); + this._nextMonthBt.removeEventListener("click", this._onNavButtonClicked, this); + this._nextYearBt.removeEventListener("click", this._onNavButtonClicked, this); + + this._lastYearBt.dispose(); + this._lastMonthBt.dispose(); + this._nextMonthBt.dispose(); + this._nextYearBt.dispose(); + + this._lastYearBt = null; + this._lastMonthBt = null; + this._nextMonthBt = null; + this._nextYearBt = null; + + this._monthYearLabel.dispose(); + this._monthYearLabel = null; + + for (var i = 0; i < this._weekdayLabelArr.length; i++) { + this._weekdayLabelArr[i].dispose(); + } + this._weekdayLabelArr = null; + + for (var i = 0; i < this._dayLabelArr.length; i++) { + this._dayLabelArr[i].dispose(); + this._dayLabelArr[i].removeEventListener("mousedown", this._onDayClicked, this); + this._dayLabelArr[i].removeEventListener("dblclick", this._onDayDblClicked, this); + } + this._dayLabelArr = null; + + for (var i = 0; i < this._weekLabelArr.length; i++) { + this._weekLabelArr[i].dispose(); + } + this._weekLabelArr = null; + + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooserButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooserButton.js new file mode 100644 index 0000000000..6b19884fb8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/component/DateChooserButton.js @@ -0,0 +1,356 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 Visionet GmbH, Germany, http://www.visionet.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Dietrich Streifert (level420) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.ui.component.DateChooser) +#require(qx.util.format.DateFormat) + +************************************************************************ */ + +/** + * A date chooser button widget which can be associated to a widget where the date value is synchronized + * whith the selected date. + * + * @param vTargetWidget {qx.ui.core.Widget} the widget which is the target for the date value selection. The target widget must have a setValue and getValue method. + * @param vChooserTitle {String} the title of the chooser window. The default value is held in property chooserTitle. + * @param vButtonLabel {String} the label of the button. The default is null. + * @param vIcon {String} the icon of the button. The default is 'icon/16/apps/accessories-date.png'. + * @param vIconWidth {String} derived from qx.ui.form.Button. + * @param vIconHeight {String} derived from qx.ui.form.Button. + * @param vFlash {String} derived from qx.ui.form.Button. + */ +qx.OO.defineClass("qx.ui.component.DateChooserButton", qx.ui.form.Button, function(vTargetWidget, vChooserTitle, vButtonLabel, vIcon, vIconWidth, vIconHeight, vFlash) +{ + if (!vIcon) { + vIcon = 'icon/16/apps/accessories-date.png'; + } + + qx.ui.form.Button.call(this, vButtonLabel, vIcon, vIconWidth, vIconHeight, vFlash); + this.set({ height : 20 }); + + // create the subwidgets + // + this._createChooser(); + this._createChooserWindow(); + + // create dateFormat instance + // + this._dateFormat = new qx.util.format.DateFormat(qx.locale.Date.getDateFormat("short")); + qx.locale.Manager.getInstance().addEventListener("changeLocale", this._changeLocale, this); + + if (vTargetWidget) { + this.setTargetWidget(vTargetWidget); + } + + if (vChooserTitle) { + this.setChooserTitle(vChooserTitle); + } + + this.addEventListener("execute", this._executeHandler, this); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** The target widget the selected Date should be synchronized with. */ +qx.OO.addProperty( +{ + name : "targetWidget", + type : "object", + instance : "qx.ui.core.Widget", + defaultValue : null +}); + +/** The title of the date chooser window. */ +qx.OO.addProperty( +{ + name : "chooserTitle", + defaultValue : qx.locale.Manager.tr("Choose a date") +}); + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +/** + * Modifier for property targetWidget. + * + * @type member + * @name _modifyTargetWidget + * @access protected + * @param propValue {var} Current value + * @param propOldValue {var} Previous value + * @param propData {var} Property configuration map + * @return {Boolean} true if modification succeeded + * @throws exception if propValue is not instance of qx.ui.core.Widget or does not have setter and getter for property value + */ +qx.Proto._modifyTargetWidget = function(propValue, propOldValue, propData) +{ + if (propValue instanceof qx.ui.core.Widget && qx.util.Validation.isValidFunction(propValue.setValue) && qx.util.Validation.isValidFunction(propValue.getValue)) { + return true; + } else { + throw new error("TargetWidget must be an instance of qx.ui.core.Widget and has setValue and getValue methods"); + } +}; + +/** + * Modifier for property chooserTitle. + * + * @type member + * @name _modifyChooserTitle + * @access protected + * @param propValue {var} Current value + * @param propOldValue {var} Previous value + * @param propData {var} Property configuration map + * @return {Boolean} true if modification succeeded + */ +qx.Proto._modifyChooserTitle = function(propValue, propOldValue, propData) +{ + this._chooserWindow.setCaption(propValue); + return true; +}; + + + + +/* +--------------------------------------------------------------------------- + SUB WIDGET CREATION +--------------------------------------------------------------------------- +*/ + +/** + * Create the popup window with for the date chooser and add the date chooser to it. + * + * @type member + * @name _createChooserWindow + * @access protected + * @return {void} + */ +qx.Proto._createChooserWindow = function() +{ + var win = this._chooserWindow = new qx.ui.window.Window(this.getChooserTitle()); + + win.addEventListener("keydown", this._chooserWindowKeydownHandler, this); + win.addEventListener("appear", this._chooserWindowAppearHandler, this); + + win.set( + { + top : 50, + left : 50, + modal : true, + minWidth : null, + minHeight : null, + resizeable : false, + allowMinimize : false, + allowMaximize : false, + showMaximize : false, + showMinimize : false + }); + + win.auto(); + win.add(this._chooser); + win.addToDocument(); +}; + +/** + * Create the date chooser + * + * @type member + * @name _createChooser + * @access protected + * @return {void} + */ +qx.Proto._createChooser = function() +{ + var cp = this._chooser = new qx.ui.component.DateChooser; + cp.auto(); + cp.setBorder(null); + + cp.addEventListener("select", this._chooserSelectHandler, this); +}; + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +/** + * Event hanlder for the execute event of the date chooser button. + * + * @type member + * @name _executeHandler + * @access protected + * @param e {Event} the received event + * @return {void} + * @throws exception if the target widget is not instance of qx.ui.core.Widget or does not have setter and getter for property value + */ +qx.Proto._executeHandler = function(e) +{ + if (qx.util.Validation.isInvalidObject(this.getTargetWidget())) { + throw new error("TargetWidget must be set which must be an instance of qx.ui.core.Widget and has setValue and getValue method."); + } + + var date = null; + + try { + date = this._dateFormat.parse(this.getTargetWidget().getValue()); + } catch(ex) {} + + // value from taget widget could not be parsed. + this._chooser.setDate(date); + this._chooserWindow.open(); +}; + + +/** + * Handle locale changes. Update the date format of the target widget. + * + * @param e {Event} the received event + */ +qx.Proto._changeLocale = function(e) { + if (qx.util.Validation.isInvalidObject(this.getTargetWidget())) { + throw new error("TargetWidget must be set which must be an instance of qx.ui.core.Widget and has setValue and getValue method."); + } + + var date = null; + + try { + date = this._dateFormat.parse(this.getTargetWidget().getValue()); + } catch(ex) {} + + + this._dateFormat = new qx.util.format.DateFormat(qx.locale.Date.getDateFormat("short")); + + if (!date) { + return; + } + + this._chooser.setDate(date); + this.getTargetWidget().setValue(this._dateFormat.format(date)); +}; + + +/** + * Event handler for keydown events of the chooser window. Closes the window on hitting the 'Escape' key. + * + * @type member + * @name _chooserWindowKeydownHandler + * @access protected + * @param e {Event} the received key event + * @return {void} + */ +qx.Proto._chooserWindowKeydownHandler = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Escape": + this._chooserWindow.close(); + this.getTargetWidget().focus(); + break; + } +}; + +/** + * Event handler for chooser window appear event. Positions the window above the target widget. + * + * @type member + * @name _chooserWindowAppearHandler + * @access protected + * @param e {Event} the received appear event + * @return {void} + */ +qx.Proto._chooserWindowAppearHandler = function(e) +{ + this._chooserWindow.positionRelativeTo(this.getTargetWidget()); + this._chooser.focus(); +}; + +/** + * Event handler for the date chooser select event. Formats the selected date as string and sets the target widgets value. + * + * @type member + * @name _chooserSelectHandler + * @access protected + * @param e {Event} the select event + * @return {void} + */ +qx.Proto._chooserSelectHandler = function(e) +{ + target = this.getTargetWidget(); + target.setValue(this._dateFormat.format(this._chooser.getDate())); + this._chooserWindow.close(); + target.focus(); +}; + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +/** + * Disposer. Removes all assigned event listeners and disposes the subwidgets. + * + * @type member + * @name dispose + * @access public + * @return {void | call} + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._dateFormat.dispose(); + this._dateFormat = null; + + this._chooser.removeEventListener("select", this._chooserSelectHandler); + this._chooser.dispose(); + this._chooser = null; + + this._chooserWindow.removeEventListener("appear", this._chooserWindowAppearHandler); + this._chooserWindow.removeEventListener("keydown", this._chooserWindowKeydownHandler); + this._chooserWindow.dispose(); + this._chooserWindow = null; + + this.removeEventListener("execute", this._executeHandler); + + return qx.ui.form.Button.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js new file mode 100644 index 0000000000..e074cfb6e0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js @@ -0,0 +1,452 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.html.StyleSheet) +#require(qx.event.handler.EventHandler) +#optional(qx.client.NativeWindow) +#optional(qx.ui.window.Window) +#optional(qx.manager.object.PopupManager) + +************************************************************************ */ + +/** + * This is the basic widget of all qooxdoo applications. + * + * qx.ui.core.ClientDocument is the parent of all children inside your application. It + * also handles their resizing and focus navigation. + * + * @event windowblur {qx.event.type.Event} Fired when the window looses the + * focus. (Fired by {@link qx.event.handler.EventHandler}) + * @event windowfocus {qx.event.type.Event} Fired when the window gets the + * focus. (Fired by {@link qx.event.handler.EventHandler}) + * @event windowresize {qx.event.type.Event} Fired when the window has been + * resized. (Fired by {@link qx.event.handler.EventHandler}) + */ +qx.OO.defineClass("qx.ui.core.ClientDocument", qx.ui.layout.CanvasLayout, +function() +{ + this._window = window; + this._document = window.document; + + // Init element + this.setElement(this._document.body); + + // Needed hard-coded because otherwise the client document + // would not be added initially to the state queue + this.addToStateQueue(); + + qx.ui.layout.CanvasLayout.call(this); + + // Don't use widget styles + this._styleProperties = {}; + + // Configure as focus root + this.activateFocusRoot(); + + // Cache current size + this._cachedInnerWidth = this._document.body.offsetWidth; + this._cachedInnerHeight = this._document.body.offsetHeight; + + // Add Resize Handler + this.addEventListener("windowresize", this._onwindowresize); + + // Dialog Support + this._modalWidgets = []; + this._modalNativeWindow = null; + + // Register as focus root + qx.event.handler.EventHandler.getInstance().setFocusRoot(this); + + + // Init Resize Helper + /* + if (qx.core.Client.getInstance().isGecko()) + { + var o = this; + this._resizeHelper = window.setInterval(function() { o._onresizehelper() }, 100); + } + */ +}); + +qx.OO.addProperty({ name : "globalCursor", type : "string" }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "client-document" }); + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableApplicationLayout", true); +qx.Settings.setDefault("boxModelCorrection", true); + + + + + + +/* +--------------------------------------------------------------------------- + OVERWRITE WIDGET FUNCTIONS/PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyParent = qx.lang.Function.returnTrue; +qx.Proto._modifyVisible = qx.lang.Function.returnTrue; + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + this._isCreated = qx.util.Validation.isValidElement(propValue); + + if (propOldValue) + { + propOldValue.qx_Widget = null; + } + + if (propValue) + { + // add reference to widget instance + propValue.qx_Widget = this; + + // link element and style reference + this._element = propValue; + this._style = propValue.style; + } + else + { + this._element = null; + this._style = null; + } + + return true; +} + +qx.Proto.getTopLevelWidget = qx.lang.Function.returnThis; +qx.Proto.getWindowElement = function() { return this._window; } +qx.Proto.getDocumentElement = function() { return this._document; } + +qx.Proto.getParent = qx.Proto.getToolTip = qx.lang.Function.returnNull; +qx.Proto.isMaterialized = qx.Proto.isSeeable = qx.lang.Function.returnTrue; + +qx.Proto._isDisplayable = true; +qx.Proto._hasParent = false; +qx.Proto._initialLayoutDone = true; + + + + + + + + + +/* +--------------------------------------------------------------------------- + BLOCKER AND DIALOG SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Returns the blocker widget if already created; otherwise create it first + * + * @return {ClientDocumentBlocker} the blocker widget. + */ +qx.Proto._getBlocker = function() +{ + if (!this._blocker) + { + // Create blocker instance + this._blocker = new qx.ui.core.ClientDocumentBlocker; + + // Add blocker events + this._blocker.addEventListener("mousedown", this.blockHelper, this); + this._blocker.addEventListener("mouseup", this.blockHelper, this); + + // Add blocker to client document + this.add(this._blocker); + } + + return this._blocker; +}; + +qx.Proto.blockHelper = function(e) +{ + if (this._modalNativeWindow) + { + try + { + this._modalNativeWindow._window.focus(); + } + catch(ex) + { + this.debug("Window seems to be closed already! => Releasing Blocker: (" + e.getType() + ")", ex); + this.release(this._modalNativeWindow); + } + } +} + +qx.Proto.block = function(vActiveChild) +{ + // this.debug("BLOCK: " + vActiveChild.toHashCode()); + + this._getBlocker().show(); + + if (qx.OO.isAvailable("qx.ui.window.Window") && vActiveChild instanceof qx.ui.window.Window) + { + this._modalWidgets.push(vActiveChild); + + var vOrigIndex = vActiveChild.getZIndex(); + this._getBlocker().setZIndex(vOrigIndex); + vActiveChild.setZIndex(vOrigIndex+1); + } + else if (qx.OO.isAvailable("qx.client.NativeWindow") && vActiveChild instanceof qx.client.NativeWindow) + { + this._modalNativeWindow = vActiveChild; + this._getBlocker().setZIndex(1e7); + } +} + +qx.Proto.release = function(vActiveChild) +{ + // this.debug("RELEASE: " + vActiveChild.toHashCode()); + + if (vActiveChild) + { + if (qx.OO.isAvailable("qx.client.NativeWindow") && vActiveChild instanceof qx.client.NativeWindow) + { + this._modalNativeWindow = null; + } + else + { + qx.lang.Array.remove(this._modalWidgets, vActiveChild); + } + } + + var l = this._modalWidgets.length; + if (l == 0) + { + this._getBlocker().hide(); + } + else + { + var oldActiveChild = this._modalWidgets[l-1]; + + var o = oldActiveChild.getZIndex(); + this._getBlocker().setZIndex(o); + oldActiveChild.setZIndex(o+1); + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CSS API +--------------------------------------------------------------------------- +*/ + +qx.Proto.createStyleElement = function(vCssText) { + return qx.html.StyleSheet.createElement(vCssText); +} + +qx.Proto.addCssRule = function(vSheet, vSelector, vStyle) { + return qx.html.StyleSheet.addRule(vSheet, vSelector, vStyle); +} + +qx.Proto.removeCssRule = function(vSheet, vSelector) { + return qx.html.StyleSheet.removeRule(vSheet, vSelector); +} + +qx.Proto.removeAllCssRules = function(vSheet) { + return qx.html.StyleSheet.removeAllRules(vSheet); +} + + + + + + +/* +--------------------------------------------------------------------------- + CSS FIX +--------------------------------------------------------------------------- +*/ +if (qx.Settings.getValueOfClass("qx.ui.core.ClientDocument", "boxModelCorrection")) { + qx.html.StyleSheet.createElement("html,body{margin:0;border:0;padding:0;}" + + " html{border:0 none;} *{" + qx.core.Client.getInstance().getEngineBoxSizingAttribute() + + ":border-box;} img{" + qx.core.Client.getInstance().getEngineBoxSizingAttribute() + + ":content-box;}"); +} +if (qx.Settings.getValueOfClass("qx.ui.core.ClientDocument", "enableApplicationLayout")) { + qx.html.StyleSheet.createElement("html,body{width:100%;height:100%;overflow:hidden;}"); +} + + + + + +/* +--------------------------------------------------------------------------- + GLOBAL CURSOR SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyGlobalCursor = function(propValue, propOldValue, propData) +{ + if (!this._globalCursorStyleSheet) { + this._globalCursorStyleSheet = this.createStyleElement(); + } + + // Selector based remove does not work with the "*" selector in mshtml + // this.removeCssRule(this._globalCursorStyleSheet, "*"); + + this.removeAllCssRules(this._globalCursorStyleSheet); + + if (propValue) { + this.addCssRule(this._globalCursorStyleSheet, "*", "cursor:" + propValue + " !important"); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + WINDOW RESIZE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onwindowresize = function(e) +{ + // Hide popups, tooltips, ... + if (qx.OO.isAvailable("qx.manager.object.PopupManager")) { + qx.manager.object.PopupManager.getInstance().update(); + } + + // Update children + this._recomputeInnerWidth(); + this._recomputeInnerHeight(); + + // Flush queues + qx.ui.core.Widget.flushGlobalQueues(); +} + +// This was an idea to allow mozilla more realtime document resize updates +// but it seems so, that mozilla stops javascript execution while the user +// resize windows. Bad. + +/* +qx.Proto._onwindowresizehelper = function() +{ + // Test for changes + var t1 = this._recomputeInnerWidth(); + var t2 = this._recomputeInnerHeight(); + + // Flush queues + if (t1 || t2) { + qx.ui.core.Widget.flushGlobalQueues(); + } +} +*/ + +qx.Proto._computeInnerWidth = function() { + return this._document.body.offsetWidth; +} + +qx.Proto._computeInnerHeight = function() { + return this._document.body.offsetHeight; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._document; + delete this._modalWidgets; + delete this._modalNativeWindow; + + // Remove Resize Handler + this.removeEventListener("windowresize", this._onwindowresize); + + this._globalCursorStyleSheet = null; + + if (this._blocker) + { + this._blocker.removeEventListener("mousedown", this.blockHelper, this); + this._blocker.removeEventListener("mouseup", this.blockHelper, this); + + this._blocker.dispose(); + this._blocker = null; + } + + /* + if (this._resizeHelper) + { + window.clearInterval(this._resizeHelper); + this._resizeHelper = null; + } + */ + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js new file mode 100644 index 0000000000..a49b894009 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js @@ -0,0 +1,41 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + qx.ui.core.ClientDocumentBlocker blocks the inputs from the user. + This will be used internally to allow better modal dialogs for example. +*/ +qx.OO.defineClass("qx.ui.core.ClientDocumentBlocker", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setEdge(0); + this.setZIndex(1e8); + this.setDisplay(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "blocker" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Parent.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Parent.js new file mode 100644 index 0000000000..649971b448 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Parent.js @@ -0,0 +1,1255 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#optional(qx.event.handler.FocusHandler) +#optional(qx.manager.object.ToolTipManager) +#optional(qx.manager.object.PopupManager) +#optional(qx.html.ElementFromPoint) + +************************************************************************ */ + +/** + * Abstract base class for all widget which have child widgets (e.g. layout manager) + * + * Don't instantiate this class directly. + */ +qx.OO.defineClass("qx.ui.core.Parent", qx.ui.core.Widget, +function() +{ + if (this.classname == qx.ui.core.Parent.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.core.Parent directly. Choose between any widget which inherits from qx.ui.core.Parent and so comes with a layout implementation!"); + } + + qx.ui.core.Widget.call(this); + + // Contains all children + this._children = []; + + // Create instanceof layout implementation + this._layoutImpl = this._createLayoutImpl(); +}); + +qx.ui.core.Parent.ABSTRACT_CLASS = "qx.ui.core.Parent"; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** Individual focus handler for all child elements. */ +qx.OO.addProperty({ name : "focusHandler", type : "object", instance : "qx.event.handler.FocusHandler" }); + +/** The current active child. */ +qx.OO.addProperty({ name : "activeChild", type : "object", instance : "qx.ui.core.Widget" }); + +/** The current focused child. */ +qx.OO.addProperty({ name : "focusedChild", type : "object", instance : "qx.ui.core.Widget" }); + + + + + +/* +--------------------------------------------------------------------------- + CACHED PRIVATE PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** all visible child widgets */ +qx.OO.addCachedProperty({ name : "visibleChildren", defaultValue : null }); + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +/** + * Wether the widget has its own focus handler or uses one of its parent's + * focus handler. + * + * @return {Boolean} wether the widget has its own focus handler + */ +qx.Proto.isFocusRoot = function() { + return this.getFocusHandler() != null; +} + + +/** + * Return the responsible focus handler + * + * @return {qx.event.handler.FocusHandler} + */ +qx.Proto.getFocusRoot = function() +{ + if (this.isFocusRoot()) { + return this; + } + + if(this._hasParent) { + return this.getParent().getFocusRoot(); + } + + return null; +} + + +/** + * Let the widget use its own focus handler + */ +qx.Proto.activateFocusRoot = function() { + this.setFocusHandler(new qx.event.handler.FocusHandler(this)); +} + + +/** + * Delegate keyevent to the focus handler + */ +qx.Proto._onfocuskeyevent = function(e) { + this.getFocusHandler()._onkeyevent(this, e); +} + +qx.Proto._modifyFocusHandler = function(propValue, propOldValue, propData) +{ + if (propValue) + { + // Add Key Handler + this.addEventListener("keydown", this._onfocuskeyevent); + 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(-1); + + // Don't hide focus outline + this.setHideFocus(false); + } + + return true; +} + +qx.Proto._modifyFocusedChild = function(propValue, propOldValue, propData) +{ + // this.debug("FocusedChild: " + propValue); + + var vFocusValid = propValue != null; + var vBlurValid = propOldValue != null; + + if (qx.OO.isAvailable("qx.manager.object.PopupManager") && vFocusValid) + { + var vMgr = qx.manager.object.PopupManager.getInstance(); + if (vMgr) { + vMgr.update(propValue); + } + } + + if (vBlurValid) + { + // Dispatch FocusOut + if (propOldValue.hasEventListeners("focusout")) + { + var vEventObject = new qx.event.type.FocusEvent("focusout", propOldValue); + + if (vFocusValid) { + vEventObject.setRelatedTarget(propValue); + } + + propOldValue.dispatchEvent(vEventObject); + vEventObject.dispose(); + } + } + + if (vFocusValid) + { + if (propValue.hasEventListeners("focusin")) + { + // Dispatch FocusIn + var vEventObject = new qx.event.type.FocusEvent("focusin", propValue); + + if (vBlurValid) { + vEventObject.setRelatedTarget(propOldValue); + } + + propValue.dispatchEvent(vEventObject); + vEventObject.dispose(); + } + } + + if (vBlurValid) + { + if (this.getActiveChild() == propOldValue && !vFocusValid) { + this.setActiveChild(null); + } + + propOldValue.setFocused(false); + + // Dispatch Blur + var vEventObject = new qx.event.type.FocusEvent("blur", propOldValue); + + if (vFocusValid) { + vEventObject.setRelatedTarget(propValue); + } + + propOldValue.dispatchEvent(vEventObject); + + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) + { + var vMgr = qx.manager.object.ToolTipManager.getInstance(); + if (vMgr) { + vMgr.handleBlur(vEventObject); + } + } + + vEventObject.dispose(); + } + + if (vFocusValid) + { + this.setActiveChild(propValue); + propValue.setFocused(true); + qx.event.handler.EventHandler.getInstance().setFocusRoot(this); + + // Dispatch Focus + var vEventObject = new qx.event.type.FocusEvent("focus", propValue); + + if (vBlurValid) { + vEventObject.setRelatedTarget(propOldValue); + } + + propValue.dispatchEvent(vEventObject); + + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) + { + var vMgr = qx.manager.object.ToolTipManager.getInstance(); + if (vMgr) { + vMgr.handleFocus(vEventObject); + } + } + + vEventObject.dispose(); + } + + // Flush Queues + // Do we really need this? + // qx.ui.core.Widget.flushGlobalQueues(); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._layoutImpl = null; + + +/** + * abstract method. Create layout implementation. + * + * This method must be overwritten by all subclasses + * + * return {qx.renderer.layout.LayoutImpl} + */ +qx.Proto._createLayoutImpl = function() { + return null; +} + +/** + * Return the layout implementation. + * + * return {qx.renderer.layout.LayoutImpl} + */ +qx.Proto.getLayoutImpl = function() { + return this._layoutImpl; +} + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: MANAGE ALL +--------------------------------------------------------------------------- +*/ + +/** + * Return the array of all children + * + * @return {qx.ui.core.Widget[]} all children + */ +qx.Proto.getChildren = function() { + return this._children; +} + +/** + * Get number of children + * + * @return {Integer} number of children + */ +qx.Proto.getChildrenLength = function() { + return this.getChildren().length; +} + +/** + * Check if the widget has children + * + * @retun {boolean} wether the widget has children + */ +qx.Proto.hasChildren = function() { + return this.getChildrenLength() > 0; +} + +/** + * Check if there are any childrens inside + * + * @return {Boolean} wether the number of children is 0 + */ +qx.Proto.isEmpty = function() { + return this.getChildrenLength() == 0; +} + +/** + * Get the index of a child widget. + * + * @param vChild {qx.ui.core.Widget} + * @return {Integer} index of the child widget + */ +qx.Proto.indexOf = function(vChild) { + return this.getChildren().indexOf(vChild); +} + +/** + * Check if the given widget is a child + * + * @param vWidget {qx.ui.core.Widget} The widget which should be checked. + */ +qx.Proto.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) + * + * @return {qx.ui.core.Widget[]} all visible children + */ +qx.Proto._computeVisibleChildren = function() +{ + var vVisible = []; + var vChildren = this.getChildren(); + var vLength = vChildren.length; + + for (var i=0; i<vLength; i++) + { + var vChild = vChildren[i]; + if (vChild._isDisplayable) { + vVisible.push(vChild); + } + } + + return vVisible; +} + +/*! + Get length of visible children +*/ +qx.Proto.getVisibleChildrenLength = function() { + return this.getVisibleChildren().length; +} + +/*! + Check if the widget has any visible children +*/ +qx.Proto.hasVisibleChildren = function() { + return this.getVisibleChildrenLength() > 0; +} + +/*! + Check if there are any visible childrens inside +*/ +qx.Proto.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. +*/ +qx.Proto.add = function() +{ + var vWidget; + + for (var i=0, l=arguments.length; i<l; i++) + { + vWidget = arguments[i]; + + if (!(vWidget instanceof qx.ui.core.Parent) && !(vWidget instanceof qx.ui.basic.Terminator)) + { + throw new Error("Invalid Widget: " + vWidget); + } + else + { + vWidget.setParent(this); + } + } + + return this; +} + +qx.Proto.addAt = function(vChild, vIndex) +{ + if (vIndex == null || vIndex < 0) { + throw new Error("Not a valid index for addAt(): " + vIndex); + } + + if (vChild.getParent() == this) + { + var vChildren = this.getChildren(); + var vOldIndex = vChildren.indexOf(vChild); + + if (vOldIndex != vIndex) + { + if (vOldIndex != -1) { + qx.lang.Array.removeAt(vChildren, vOldIndex); + } + + qx.lang.Array.insertAt(vChildren, vChild, vIndex); + + if (this._initialLayoutDone) + { + this._invalidateVisibleChildren(); + this.getLayoutImpl().updateChildrenOnMoveChild(vChild, vIndex, vOldIndex); + } + } + } + else + { + vChild._insertIndex = vIndex; + vChild.setParent(this); + } +} + +qx.Proto.addAtBegin = function(vChild) { + return this.addAt(vChild, 0); +} + +qx.Proto.addAtEnd = function(vChild) +{ + // we need to fix here, when the child is already inside myself, but + // want to change its position + var vLength = this.getChildrenLength(); + return this.addAt(vChild, vChild.getParent() == this ? vLength - 1 : vLength); +} + +/*! + Add a widget before another already inserted child +*/ +qx.Proto.addBefore = function(vChild, vBefore) +{ + var vChildren = this.getChildren(); + var vTargetIndex = vChildren.indexOf(vBefore); + + if (vTargetIndex == -1) { + throw new Error("Child to add before: " + vBefore + " is not inside this parent."); + } + + var vSourceIndex = vChildren.indexOf(vChild); + + if (vSourceIndex == -1 || vSourceIndex > vTargetIndex) { + vTargetIndex++; + } + + return this.addAt(vChild, Math.max(0, vTargetIndex-1)); +} + +/*! + Add a widget after another already inserted child +*/ +qx.Proto.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. +*/ +qx.Proto.remove = function() +{ + var vWidget; + + for (var i=0, l=arguments.length; i<l; i++) + { + vWidget = arguments[i]; + + if (!(vWidget instanceof qx.ui.core.Parent) && !(vWidget instanceof qx.ui.basic.Terminator)) + { + throw new Error("Invalid Widget: " + vWidget); + } + else if (vWidget.getParent() == this) + { + vWidget.setParent(null); + } + } +} + +qx.Proto.removeAt = function(vIndex) +{ + var vChild = this.getChildren()[vIndex]; + + if (vChild) + { + delete vChild._insertIndex; + + vChild.setParent(null); + } +} + +/*! + Remove all childrens. +*/ +qx.Proto.removeAll = function() +{ + var cs = this.getChildren(); + var co = cs[0]; + + while (co) + { + this.remove(co); + co = cs[0]; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: FIRST CHILD +--------------------------------------------------------------------------- +*/ + +qx.Proto.getFirstChild = function() { + return qx.lang.Array.getFirst(this.getChildren()); +} + +qx.Proto.getFirstVisibleChild = function() { + return qx.lang.Array.getFirst(this.getVisibleChildren()); +} + +qx.Proto.getFirstActiveChild = function(vIgnoreClasses) { + return qx.ui.core.Widget.getActiveSiblingHelper(null, this, 1, vIgnoreClasses, "first"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: LAST CHILD +--------------------------------------------------------------------------- +*/ + +qx.Proto.getLastChild = function() { + return qx.lang.Array.getLast(this.getChildren()); +} + +qx.Proto.getLastVisibleChild = function() { + return qx.lang.Array.getLast(this.getVisibleChildren()); +} + +qx.Proto.getLastActiveChild = function(vIgnoreClasses) { + return qx.ui.core.Widget.getActiveSiblingHelper(null, this, -1, vIgnoreClasses, "last"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: LOOP UTILS +--------------------------------------------------------------------------- +*/ + +qx.Proto.forEachChild = function(vFunc) +{ + var ch=this.getChildren(), chc, i=-1; + while(chc=ch[++i]) { + vFunc.call(chc, i); + } +} + +qx.Proto.forEachVisibleChild = function(vFunc) +{ + var ch=this.getVisibleChildren(), chc, i=-1; + while(chc=ch[++i]) { + vFunc.call(chc, i); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR MESSAGES FOR CHILDREN +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + qx.ui.core.Widget.prototype._beforeAppear.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._beforeAppear(); + } + }); +} + +qx.Proto._afterAppear = function() +{ + qx.ui.core.Widget.prototype._afterAppear.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._afterAppear(); + } + }); +} + +qx.Proto._beforeDisappear = function() +{ + qx.ui.core.Widget.prototype._beforeDisappear.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._beforeDisappear(); + } + }); +} + +qx.Proto._afterDisappear = function() +{ + qx.ui.core.Widget.prototype._afterDisappear.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._afterDisappear(); + } + }); +} + + + + + + + +/* +--------------------------------------------------------------------------- + INSERTDOM/REMOVEDOM MESSAGES FOR CHILDREN +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeInsertDom = function() +{ + qx.ui.core.Widget.prototype._beforeInsertDom.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._beforeInsertDom(); + } + }); +} + +qx.Proto._afterInsertDom = function() +{ + qx.ui.core.Widget.prototype._afterInsertDom.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._afterInsertDom(); + } + }); +} + +qx.Proto._beforeRemoveDom = function() +{ + qx.ui.core.Widget.prototype._beforeRemoveDom.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._beforeRemoveDom(); + } + }); +} + +qx.Proto._afterRemoveDom = function() +{ + qx.ui.core.Widget.prototype._afterRemoveDom.call(this); + + this.forEachVisibleChild(function() { + if (this.isAppearRelevant()) { + this._afterRemoveDom(); + } + }); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + this.forEachChild(function() { + this._handleDisplayable(); + }); +} + + + + + + + +/* +--------------------------------------------------------------------------- + STATE QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto._addChildrenToStateQueue = function() +{ + this.forEachVisibleChild(function() { + this.addToStateQueue(); + }); +} + +qx.Proto.recursiveAddToStateQueue = function() +{ + this.addToStateQueue(); + + this.forEachVisibleChild(function() { + this.recursiveAddToStateQueue(); + }); +} + +qx.Proto._recursiveAppearanceThemeUpdate = function(vNewAppearanceTheme, vOldAppearanceTheme) +{ + qx.ui.core.Widget.prototype._recursiveAppearanceThemeUpdate.call(this, vNewAppearanceTheme, vOldAppearanceTheme); + + this.forEachVisibleChild(function() { + this._recursiveAppearanceThemeUpdate(vNewAppearanceTheme, vOldAppearanceTheme); + }); +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto._addChildToChildrenQueue = function(vChild) +{ + if (!vChild._isInParentChildrenQueue && !vChild._isDisplayable) { + this.warn("Ignoring invisible child: " + vChild); + } + + if (!vChild._isInParentChildrenQueue && vChild._isDisplayable) + { + qx.ui.core.Widget.addToGlobalLayoutQueue(this); + + if (!this._childrenQueue) { + this._childrenQueue = {}; + } + + this._childrenQueue[vChild.toHashCode()] = vChild; + } +} + +qx.Proto._removeChildFromChildrenQueue = function(vChild) +{ + if (this._childrenQueue && vChild._isInParentChildrenQueue) + { + delete this._childrenQueue[vChild.toHashCode()]; + + if (qx.lang.Object.isEmpty(this._childrenQueue)) { + qx.ui.core.Widget.removeFromGlobalLayoutQueue(this); + } + } +} + +qx.Proto._flushChildrenQueue = function() +{ + if (!qx.lang.Object.isEmpty(this._childrenQueue)) + { + this.getLayoutImpl().flushChildrenQueue(this._childrenQueue); + delete this._childrenQueue; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto._addChildrenToLayoutQueue = function(p) +{ + this.forEachChild(function() { + this.addToLayoutChanges(p); + }); +} + +qx.Proto._layoutChild = function(vChild) +{ + if (!vChild._isDisplayable) + { + this.warn("Want to render an invisible child: " + vChild + " -> omitting!"); + return; + } + + // APPLY LAYOUT + var vChanges = vChild._layoutChanges; + + // this.debug("Layouting " + vChild + ": " + qx.lang.Object.getKeysAsString(vChanges)); + + try + { + if (vChanges.borderX) { + this._applyBorderX(vChild, vChanges); + } + + if (vChanges.borderY) { + this._applyBorderY(vChild, vChanges); + } + } + catch(ex) + { + this.error("Could not apply border to child " + vChild, ex); + } + + try + { + if (vChanges.paddingLeft || vChanges.paddingRight) { + vChild._applyPaddingX(this, vChanges); + } + + if (vChanges.paddingTop || vChanges.paddingBottom) { + vChild._applyPaddingY(this, vChanges); + } + } + catch(ex) + { + this.error("Could not apply padding to child " + vChild, ex); + } + + + // WRAP TO LAYOUT ENGINE + try + { + this.getLayoutImpl().layoutChild(vChild, vChanges); + } + catch(ex) + { + this.error("Could not layout child " + vChild + " through layout handler", ex); + } + + + // POST LAYOUT + try + { + vChild._layoutPost(vChanges); + } + catch(ex) + { + this.error("Could not post layout child " + vChild, ex); + } + + + // DISPLAY DOM NODE + try + { + // insert dom node (if initial flag enabled) + if (vChanges.initial) + { + vChild._initialLayoutDone = true; + qx.ui.core.Widget.addToGlobalDisplayQueue(vChild); + } + } + catch(ex) + { + this.error("Could not handle display updates from layout flush for child " + vChild, ex); + } + + + // CLEANUP + vChild._layoutChanges = {}; + + delete vChild._isInParentLayoutQueue; + delete this._childrenQueue[vChild.toHashCode()]; +} + +qx.Proto._layoutPost = qx.lang.Function.returnTrue; + +/*! + Fix Operas Rendering Bugs +*/ +if (qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._layoutChildOrig = qx.Proto._layoutChild; + + qx.Proto._layoutChild = function(vChild) + { + if (!vChild._initialLayoutDone || !vChild._layoutChanges.borderX || !vChild._layoutChanges.borderY) { + return this._layoutChildOrig(vChild); + } + + var vStyle = vChild.getElement().style; + + var vOldDisplay = vStyle.display; + vStyle.display = "none"; + var vRet = this._layoutChildOrig(vChild); + vStyle.display = vOldDisplay; + + return vRet; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() { + return this.getLayoutImpl().computeChildrenNeededWidth(); +} + +qx.Proto._computePreferredInnerHeight = function() { + return this.getLayoutImpl().computeChildrenNeededHeight(); +} + +qx.Proto._changeInnerWidth = function(vNew, vOld) +{ + var vLayout = this.getLayoutImpl(); + + if (vLayout.invalidateChildrenFlexWidth) { + vLayout.invalidateChildrenFlexWidth(); + } + + this.forEachVisibleChild(function() + { + if (vLayout.updateChildOnInnerWidthChange(this) && this._recomputeBoxWidth()) + { + this._recomputeOuterWidth(); + this._recomputeInnerWidth(); + } + }); +} + +qx.Proto._changeInnerHeight = function(vNew, vOld) +{ + var vLayout = this.getLayoutImpl(); + + if (vLayout.invalidateChildrenFlexHeight) { + vLayout.invalidateChildrenFlexHeight(); + } + + this.forEachVisibleChild(function() + { + if (vLayout.updateChildOnInnerHeightChange(this) && this._recomputeBoxHeight()) + { + this._recomputeOuterHeight(); + this._recomputeInnerHeight(); + } + }); +} + +qx.Proto.getInnerWidthForChild = function(vChild) { + return this.getInnerWidth(); +} + +qx.Proto.getInnerHeightForChild = function(vChild) { + return this.getInnerHeight(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET FROM POINT SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWidgetFromPointHelper = function(x, y) +{ + var ch = this.getChildren(); + + for (var chl=ch.length, i=0; i<chl; i++) { + if (qx.html.ElementFromPoint.getElementAbsolutePointChecker(ch[i].getElement(), x, y)) { + return ch[i].getWidgetFromPointHelper(x, y); + } + } + + return this; +} + + + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +qx.Proto._cloneRecursive = function(cloneInstance) +{ + var ch = this.getChildren(); + var chl = ch.length; + var cloneChild; + + for (var i=0; i<chl; i++) + { + cloneChild = ch[i].clone(true); + cloneInstance.add(cloneChild); + } +} + + + + + +/* +--------------------------------------------------------------------------- + REMAPPING +--------------------------------------------------------------------------- +*/ + +qx.Proto._remappingChildTable = [ "add", "remove", "addAt", "addAtBegin", "addAtEnd", "removeAt", "addBefore", "addAfter", "removeAll" ]; +qx.Proto._remapStart = "return this._remappingChildTarget."; +qx.Proto._remapStop = ".apply(this._remappingChildTarget, arguments)"; + +qx.Proto.remapChildrenHandlingTo = function(vTarget) +{ + var t = this._remappingChildTable; + + this._remappingChildTarget = vTarget; + + for (var i=0, l=t.length, s; i<l; i++) { + s = t[i]; this[s] = new Function(qx.ui.core.Parent.prototype._remapStart + s + qx.ui.core.Parent.prototype._remapStop); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._layoutImpl) + { + this._layoutImpl.dispose(); + this._layoutImpl = null; + } + + for (var i in this._childrenQueue) { + delete this._childrenQueue[i]; + } + + this._childrenQueue = null; + this._remappingChildTable = null; + this._remappingChildTarget = null; + + if (this._children) + { + var chl = this._children.length; + + for (var i=chl-1; i>=0; i--) + { + this._children[i].dispose(); + this._children[i] = null; + } + + this._children = null; + } + + delete this._cachedVisibleChildren; + + // Remove Key Handler + if (this.getFocusHandler()) + { + this.removeEventListener("keydown", this._onfocuskeyevent); + this.removeEventListener("keypress", this._onfocuskeyevent); + + this.forceFocusHandler(null); + } + + return qx.ui.core.Widget.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js new file mode 100644 index 0000000000..51337b36a9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js @@ -0,0 +1,262 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * A scroll bar. + * + * @param horizontal {Boolean ? false} whether the scroll bar should be + * horizontal. If false it will be vertical. + */ +qx.OO.defineClass("qx.ui.core.ScrollBar", qx.ui.layout.BoxLayout, +function(horizontal) { + qx.ui.layout.BoxLayout.call(this, horizontal ? "horizontal" : "vertical"); + + this._horizontal = (horizontal == true); + + this._scrollBar = new qx.ui.layout.CanvasLayout; + if (qx.core.Client.getInstance().isGecko()) { + // NOTE: We have to force not using position:absolute, because this causes + // strange looking scrollbars in some cases (e.g. in Firefox under + // Linux the horizontal scrollbar is too high) + this._scrollBar.setStyleProperty("position", ""); + } + this._scrollBar.setOverflow(horizontal ? "scrollX" : "scrollY"); + this._scrollBar.enableInlineEvent("scroll"); + this._scrollBar.addEventListener("scroll", this._onscroll, this); + + this._scrollContent = new qx.ui.basic.Terminator; + if (qx.core.Client.getInstance().isGecko()) { + this._scrollContent.setStyleProperty("position", ""); + } + this._scrollBar.add(this._scrollContent); + + if (this._horizontal) { + this._scrollContent.setHeight(5); + this._scrollBar.setWidth("100%"); + this._scrollBar.setHeight(this._getScrollBarWidth()); + + // IE needs that the scrollbar element has a width of +1 + if (qx.core.Client.getInstance().isMshtml()) { + this.setHeight(this._getScrollBarWidth()); + this.setOverflow("hidden"); + this._scrollBar.setHeight(this._getScrollBarWidth() + 1); + this._scrollBar.setTop(-1); + } + } else { + this._scrollContent.setWidth(5); + this._scrollBar.setHeight("100%"); + this._scrollBar.setWidth(this._getScrollBarWidth()); + + // IE needs that the scrollbar element has a width of +1 + if (qx.core.Client.getInstance().isMshtml()) { + this.setWidth(this._getScrollBarWidth()); + this.setOverflow("hidden"); + this._scrollBar.setWidth(this._getScrollBarWidth() + 1); + this._scrollBar.setLeft(-1); + } + } + + this.add(this._scrollBar); + + this.setMaximum(0); +}); + +/** + * The current value of the scroll bar. This value is between 0 and + * (maxium - size), where size is the width of a horizontal resp. the height of + * a vertical scroll bar in pixels. + * + * @see #maximum + */ +qx.OO.addProperty({ name:"value", type:"number", defaultValue:0, allowNull:false }); + +/** + * The maximum value of the scroll bar. Note that the size of the scroll bar is + * substracted. + * + * @see #value + */ +qx.OO.addProperty({ name:"maximum", type:"number", allowNull:false }); + +/** + * Whether to merge consecutive scroll event. If true, events will be collected + * until the user stops scrolling, so the scroll bar itself will move smoothly + * and the scrolled content will update asynchroniously. + */ +qx.OO.addProperty({ name:"mergeEvents", type:"boolean", defaultValue:false, allowNull:false }); + + +// property checker +qx.Proto._checkValue = function(propValue, propData) { + var innerSize = !this.getElement() ? 0 : + (this._horizontal ? this.getInnerWidth() : this.getInnerHeight()); + + // NOTE: We can't use Number.limit here because our maximum may get negative + // (when the scrollbar isn't needed). In this case Number.limit returns + // this negative maximum instead of 0. But we need that the minimum is + // stronger than the maximum. + // -> We use Math.max and Math.min + return Math.max(0, Math.min(this.getMaximum() - innerSize, propValue)); +} + + +// property modifier +qx.Proto._modifyValue = function(propValue, propOldValue, propData) { + if (! this._internalValueChange && this._isCreated) { + this._positionKnob(propValue); + } + return true; +} + + +// property modifier +qx.Proto._modifyMaximum = function(propValue, propOldValue, propData) { + if (this._horizontal) { + this._scrollContent.setWidth(propValue); + } else { + this._scrollContent.setHeight(propValue); + } + + // recheck the value + this.setValue(this._checkValue(this.getValue())); + + return true; +} + + +// property modifier +qx.Proto._modifyVisibility = function(propValue, propOldValue, propData) { + if (! propValue) { + this._positionKnob(0); + } else { + this._positionKnob(this.getValue()); + } + + return qx.ui.layout.BoxLayout.prototype._modifyVisibility.call(this, propValue, propOldValue, propData); +}; + + +// overridden +qx.Proto._computePreferredInnerWidth = function() { + return this._horizontal ? 0 : this._getScrollBarWidth(); +} + + +// overridden +qx.Proto._computePreferredInnerHeight = function() { + return this._horizontal ? this._getScrollBarWidth() : 0; +} + + +/** + * Gets the width of vertical scroll bar. + * + * @return {Integer} the width in pixels. + */ +qx.Proto._getScrollBarWidth = function() { + // Auto-detect the scrollbar width + if (qx.ui.core.ScrollBar._scrollBarWidth == null) { + var dummy = document.createElement("div"); + dummy.style.width = "100px"; + dummy.style.height = "100px"; + dummy.style.overflow = "scroll"; + dummy.style.visibility = "hidden"; + document.body.appendChild(dummy); + qx.ui.core.ScrollBar._scrollBarWidth = dummy.offsetWidth - dummy.clientWidth; + document.body.removeChild(dummy); + } + return qx.ui.core.ScrollBar._scrollBarWidth; +} + + +/** + * Event handler. Called when the user scrolled. + * + * @param evt {Map} the event. + */ +qx.Proto._onscroll = function(evt) { + var value = this._horizontal ? this._scrollBar.getScrollLeft() : this._scrollBar.getScrollTop(); + if (this.getMergeEvents()) { + this._lastScrollEventValue = value; + window.clearTimeout(this._setValueTimerId); + var self = this; + this._setValueTimerId = window.setTimeout(function() { + self._internalValueChange = true; + self.setValue(self._lastScrollEventValue); + self._internalValueChange = false; + qx.ui.core.Widget.flushGlobalQueues(); + }, qx.ui.core.ScrollBar.EVENT_DELAY); + } else { + this._internalValueChange = true; + this.setValue(value); + this._internalValueChange = false; + qx.ui.core.Widget.flushGlobalQueues(); + } +} + + +/** + * Positions the scroll bar knob at a certain value. + * + * @param value {Integer} The value where to postion the scroll bar. + */ +qx.Proto._positionKnob = function(value) { + if (this._horizontal) { + this._scrollBar.setScrollLeft(value); + } else { + this._scrollBar.setScrollTop(value); + } +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.BoxLayout.prototype._afterAppear.call(this); + + //this.debug("Setting to value: " + this.getValue()); + this._positionKnob(this.getValue()); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + if (this._scrollContent) { + this._scrollContent.dispose(); + this._scrollContent = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} + + +/** + * The delay when to update the scroll bar value after a scroll event if + * {@link #mergeEvents} is true (in milliseconds). All scroll events that arrive + * in shorter time will be merged. + */ +qx.Class.EVENT_DELAY = 250; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Widget.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Widget.js new file mode 100644 index 0000000000..4ee1b97b55 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/core/Widget.js @@ -0,0 +1,5726 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.renderer.color.ColorCache) +#require(qx.renderer.border.BorderCache) +#require(qx.manager.object.AppearanceManager) +#after(qx.component.init.InterfaceInitComponent) +#optional(qx.ui.core.Parent) +#optional(qx.ui.form.Button) +#optional(qx.client.Timer) +#optional(qx.client.Command) +#optional(qx.ui.popup.ToolTip) +#optional(qx.ui.menu.Menu) +#optional(qx.ui.basic.Inline) + +************************************************************************ */ + +/** + * This is the main widget, all visible objects in the application extend this. + * + * @event beforeAppear {qx.event.type.Event} + * @event appear {qx.event.type.Event} + * @event beforeDisappear {qx.event.type.Event} + * @event disappear {qx.event.type.Event} + * @event beforeInsertDom {qx.event.type.Event} + * @event insertDom {qx.event.type.Event} + * @event beforeRemoveDom {qx.event.type.Event} + * @event removeDom {qx.event.type.Event} + * @event create {qx.event.type.Event} + * @event execute {qx.event.type.Event} + * @event FADE_FINISHED {qx.event.type.DataEvent} + * @event mouseover {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousemove {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mouseout {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousedown {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mouseup {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousewheel {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event click {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event dblclick {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event contextmenu {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keydown {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keypress {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keyinput {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keyup {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event focusout {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event focusin {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event blur {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event focus {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event dragdrop {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + * @event dragout {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + * @event dragover {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + * @event dragmove {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + * @event dragstart {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + * @event dragend {qx.event.type.DragEvent} (Fired by {@link qx.event.handler.DragAndDropHandler}) + */ +qx.OO.defineClass("qx.ui.core.Widget", qx.core.Target, +function() +{ + if (this.classname == qx.ui.core.Widget.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.core.Widget directly. Choose between qx.ui.core.Parent and qx.ui.basic.Terminator instead!"); + } + + qx.core.Target.call(this, true); + + + // ************************************************************************ + // HTML MAPPING DATA STRUCTURES + // ************************************************************************ + // Allows the user to setup styles and attributes without a + // need to have the target element created already. + /* + this._htmlProperties = { className : this.classname } + this._htmlAttributes = { qxhashcode : this._hashCode } + */ + this._styleProperties = { position : "absolute" } + + + // ************************************************************************ + // LAYOUT CHANGES + // ************************************************************************ + this._layoutChanges = {}; + + + // ************************************************************************ + // APPEARANCE + // ************************************************************************ + this._states = {}; + this._applyInitialAppearance(); +}); + +qx.Class.ABSTRACT_CLASS = "qx.ui.core.Widget"; + +// Will be calculated later (TODO: Move to qx.Dom?) +qx.Class.SCROLLBAR_SIZE = 16; + + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableQueueDebug", false); + + + + + + +/* +--------------------------------------------------------------------------- + BASIC PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The parent widget (the real object, no ID or something) +*/ +qx.OO.addProperty({ name : "parent", type : "object", instance : "qx.ui.core.Parent", defaultValue : null }); + +/*! + The element node (if the widget is created, otherwise null) +*/ +qx.OO.addProperty({ name : "element" }); + +/*! + Simple and fast switch of the visibility of a widget. +*/ +qx.OO.addProperty({ name : "visibility", type : "boolean", defaultValue : true }); + +/*! + If the widget should be displayed. Use this property instead of visibility if the change + in visibility should have effects on the parent widget. +*/ +qx.OO.addProperty({ name : "display", type : "boolean", defaultValue : true }); + +/*! + If you switch this to true, the widget doesn't handle + events directly. It will redirect them to the parent + widget. +*/ +qx.OO.addProperty({ name : "anonymous", type : "boolean", defaultValue : false, getAlias : "isAnonymous" }); + +/*! + The tagname of the element which should automatically be created +*/ +qx.OO.addProperty({ name : "tagName", type : "string", defaultValue : "div" }); + +/*! + This is used by many layout managers to control the individual horizontal alignment of this widget inside this parent. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "horizontalAlign", type : "string" }); + +/*! + This is used by many layout managers to control the individual vertical alignment of this widget inside this parent. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "verticalAlign", type : "string" }); + +/*! + Should this widget be stretched on the x-axis if the layout handler will do this? + Used by some layout handlers (qx.ui.layout.BoxLayout, ...). +*/ +qx.OO.addProperty({ name : "allowStretchX", type : "boolean", defaultValue : true }); + +/*! + Should this widget be stretched on the y-axis if the layout handler will do this? + Used by some layout handlers (qx.ui.layout.BoxLayout, ...). +*/ +qx.OO.addProperty({ name : "allowStretchY", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + STYLE PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Mapping to native style property z-index. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "zIndex", type : "number" }); + +/*! + The backgroundColor style property of the rendered widget. + As input are allowed any instance of qx.renderer.color.Color or a string which defines the color itself. +*/ +qx.OO.addProperty({ name : "backgroundColor", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache, allowMultipleArguments : true }); + +/*! + The color style property of the rendered widget. + As input are allowed any instance of qx.renderer.color.Color or a string which defines the color itself. +*/ +qx.OO.addProperty({ name : "color", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache, allowMultipleArguments : true }); + +/*! + The border property describes how to paint the border on the widget. + + This should be used with caution since in some cases (mostly complex widgets) + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "border", type : "object", instance : "qx.renderer.border.Border", convert : qx.renderer.border.BorderCache, allowMultipleArguments : true }); + +/*! + Mapping to native style property opacity. + + The uniform opacity setting to be applied across an entire object. Behaves like the new CSS-3 Property. + Any values outside the range 0.0 (fully transparent) to 1.0 (fully opaque) will be clamped to this range. +*/ +qx.OO.addProperty({ name : "opacity", type : "number" }); + +/*! + Mapping to native style property cursor. + + The name of the cursor to show when the mouse pointer is over the widget. + This is any valid CSS2 cursor name defined by W3C. + + The following values are possible: + <ul><li>default</li> + <li>crosshair</li> + <li>pointer (hand is the ie name and will mapped to pointer in non-ie).</li> + <li>move</li> + <li>n-resize</li> + <li>ne-resize</li> + <li>e-resize</li> + <li>se-resize</li> + <li>s-resize</li> + <li>sw-resize</li> + <li>w-resize</li> + <li>nw-resize</li> + <li>text</li> + <li>wait</li> + <li>help </li> + <li>url([file]) = self defined cursor, file should be an ANI- or CUR-type</li> + </ul> +*/ +qx.OO.addProperty({ name : "cursor", type : "string" }); + +/*! + Mapping to native style property background-image. + + The URI of the image file to use as background image. +*/ +qx.OO.addProperty({ name : "backgroundImage", type : "string" }); + +/** + * Describes how to handle content that is too large to fit inside the widget. + * + * Overflow modes: + * <table> + * <tr><th>hidden</th><td>The content is clipped</td></tr> + * <tr><th>auto</th><td>Scroll bars are shown as needed</td></tr> + * <tr><th>scroll</th><td>Scroll bars are always shown. Even if there is enough room for the content inside the widget.</td></tr> + * <tr><th>scrollX</th><td>Scroll bars for the X-Axis are always shown. Even if there is enough room for the content inside the widget.</td></tr> + * <tr><th>scrollY</th><td>Scroll bars for the Y-Axis are always shown. Even if there is enough room for the content inside the widget.</td></tr> + * </table> + */ +qx.OO.addProperty({ name : "overflow", type : "string", addToQueue : true }); + +/*! + Clipping of the widget (left) +*/ +qx.OO.addProperty({ name : "clipLeft", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (top) +*/ +qx.OO.addProperty({ name : "clipTop", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (width) +*/ +qx.OO.addProperty({ name : "clipWidth", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (height) +*/ +qx.OO.addProperty({ name : "clipHeight", type : "number", impl : "clip" }); + + + + + + + +/* +--------------------------------------------------------------------------- + MANAGMENT PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Set this to a positive value makes the widget able to get the focus. + It even is reachable through the usage of the tab-key. + + Widgets with the same tabIndex are handled through there position + in the document. +*/ +qx.OO.addProperty({ name : "tabIndex", type : "number", defaultValue : -1 }); + +/*! + If the focus outline should be hidden. +*/ +qx.OO.addProperty({ name : "hideFocus", type : "boolean", defaultValue : false }); + +/*! + Use DOM focussing (focus() and blur() methods of DOM nodes) +*/ +qx.OO.addProperty({ name : "enableElementFocus", type : "boolean", defaultValue : true }); + +/*! + Handle focus state of this widget. + + someWidget.setFocused(true) set the current focus to this widget. + someWidget.setFocused(false) remove the current focus and leave it blank. + + Normally you didn't need to set this directly. +*/ +qx.OO.addProperty({ name : "focused", type : "boolean", defaultValue : false }); + +/*! + Toggle the possibility to select the element of this widget. +*/ +qx.OO.addProperty({ name : "selectable", type : "boolean", defaultValue : true, getAlias : "isSelectable" }); + +/*! + Contains the tooltip object connected to the widget. +*/ +qx.OO.addProperty({ name : "toolTip", type : "object", instance : "qx.ui.popup.ToolTip" }); + +/*! + Contains the context menu object connected to the widget. (Need real implementation) +*/ +qx.OO.addProperty({ name : "contextMenu", type : "object", instance : "qx.ui.menu.Menu" }); + +/*! + Capture all events and map them to this widget +*/ +qx.OO.addProperty({ name : "capture", type : "boolean", defaultValue : false }); + +/*! + Contains the support drop types for drag and drop support +*/ +qx.OO.addProperty({ name : "dropDataTypes" }); + +/*! + A command called if the widget should be excecuted (a placeholder for buttons, ...) +*/ +qx.OO.addProperty({ name : "command", type : "object", instance : "qx.client.Command" }); + +/*! + Appearance of the widget +*/ +qx.OO.addProperty({ name : "appearance", type : "string" }); + + + + + + +/* +--------------------------------------------------------------------------- + MARGIN/PADDING PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Margin of the widget (top) +*/ +qx.OO.addProperty({ name : "marginTop", type : "number", addToQueue : true, impl : "marginY" }); + +/*! + Margin of the widget (right) +*/ +qx.OO.addProperty({ name : "marginRight", type : "number", addToQueue : true, impl : "marginX" }); + +/*! + Margin of the widget (bottom) +*/ +qx.OO.addProperty({ name : "marginBottom", type : "number", addToQueue : true, impl : "marginY" }); + +/*! + Margin of the widget (left) +*/ +qx.OO.addProperty({ name : "marginLeft", type : "number", addToQueue : true, impl : "marginX" }); + + +/*! + Padding of the widget (top) +*/ +qx.OO.addProperty({ name : "paddingTop", type : "number", addToQueue : true, impl : "paddingY" }); + +/*! + Padding of the widget (right) +*/ +qx.OO.addProperty({ name : "paddingRight", type : "number", addToQueue : true, impl : "paddingX" }); + +/*! + Padding of the widget (bottom) +*/ +qx.OO.addProperty({ name : "paddingBottom", type : "number", addToQueue : true, impl : "paddingY" }); + +/*! + Padding of the widget (left) +*/ +qx.OO.addProperty({ name : "paddingLeft", type : "number", addToQueue : true, impl : "paddingX" }); + + + + + + + +/* +--------------------------------------------------------------------------- + HORIZONAL DIMENSION PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The distance from the outer left border to the parent left area edge. + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "left", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The distance from the outer right border to the parent right area edge. + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "right", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The width of the box (including padding and border). + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "width", addToQueue : true, unitDetection : "pixelPercentAutoFlex" }); + +/*! + The minimum width of the box (including padding and border). + + Set this to omit the shrinking of the box width under this value. +*/ +qx.OO.addProperty({ name : "minWidth", addToQueue : true, unitDetection : "pixelPercentAuto" }); + +/*! + The maximum width of the box (including padding and border). + + Set this to omit the expanding of the box width above this value. +*/ +qx.OO.addProperty({ name : "maxWidth", addToQueue : true, unitDetection : "pixelPercentAuto" }); + + + + + + + +/* +--------------------------------------------------------------------------- + VERTICAL DIMENSION PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The distance from the outer top border to the parent top area edge. + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "top", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The distance from the outer bottom border to the parent bottom area edge. + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "bottom", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The height of the box (including padding and border). + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "height", addToQueue : true, unitDetection : "pixelPercentAutoFlex" }); + +/*! + The minimum height of the box (including padding and border). + + Set this to omit the shrinking of the box height under this value. +*/ +qx.OO.addProperty({ name : "minHeight", addToQueue : true, unitDetection : "pixelPercentAuto" }); + +/*! + The maximum height of the box (including padding and border). + + Set this to omit the expanding of the box height above this value. +*/ +qx.OO.addProperty({ name : "maxHeight", addToQueue : true, unitDetection : "pixelPercentAuto" }); + + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTY GROUPS +--------------------------------------------------------------------------- +*/ + +qx.OO.addPropertyGroup({ name : "location", members : [ "left", "top" ]}); +qx.OO.addPropertyGroup({ name : "dimension", members : [ "width", "height" ]}); + +qx.OO.addPropertyGroup({ name : "space", members : [ "left", "width", "top", "height" ]}); +qx.OO.addPropertyGroup({ name : "edge", members : [ "top", "right", "bottom", "left" ], mode : "shorthand" }); + +qx.OO.addPropertyGroup({ name : "padding", members : [ "paddingTop", "paddingRight", "paddingBottom", "paddingLeft" ], mode: "shorthand" }); +qx.OO.addPropertyGroup({ name : "margin", members : [ "marginTop", "marginRight", "marginBottom", "marginLeft" ], mode: "shorthand" }); + +qx.OO.addPropertyGroup({ name : "heights", members : [ "minHeight", "height", "maxHeight" ]}); +qx.OO.addPropertyGroup({ name : "widths", members : [ "minWidth", "width", "maxWidth" ]}); + +qx.OO.addPropertyGroup({ name : "align", members : [ "horizontalAlign", "verticalAlign" ]}); +qx.OO.addPropertyGroup({ name : "stretch", members : [ "stretchX", "stretchY" ]}); + +qx.OO.addPropertyGroup({ name : "clipLocation", members : [ "clipLeft", "clipTop" ]}); +qx.OO.addPropertyGroup({ name : "clipDimension", members : [ "clipWidth", "clipHeight" ]}); +qx.OO.addPropertyGroup({ name : "clip", members : [ "clipLeft", "clipTop", "clipWidth", "clipHeight" ]}); + + + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + ALL QUEUES +--------------------------------------------------------------------------- +*/ + +/** + * Flush all global queues + */ +qx.ui.core.Widget.flushGlobalQueues = function() {}; + +if (qx.Settings.getValueOfClass("qx.ui.core.Widget", "enableQueueDebug")) +{ + qx.ui.core.Widget.flushGlobalQueues = function() + { + if (qx.ui.core.Widget._inFlushGlobalQueues || !qx.core.Init.getInstance().getComponent().isUiReady()) { + return; + } + + if (!(qx.ui.core.Widget._globalWidgetQueue.length > 0 || qx.ui.core.Widget._globalElementQueue.length > 0 || + qx.ui.core.Widget._globalStateQueue.length > 0 || qx.ui.core.Widget._globalJobQueue.length > 0 || + qx.ui.core.Widget._globalLayoutQueue.length > 0 || qx.ui.core.Widget._fastGlobalDisplayQueue.length > 0 || + !qx.lang.Object.isEmpty(qx.ui.core.Widget._lazyGlobalDisplayQueue))) { + return; + } + + var globalWidgetQueueLength = qx.ui.core.Widget._globalWidgetQueue.length; + var globalElementQueueLength = qx.ui.core.Widget._globalElementQueue.length; + var globalStateQueueLength = qx.ui.core.Widget._globalStateQueue.length; + var globalJobQueueLength = qx.ui.core.Widget._globalJobQueue.length; + var globalLayoutQueueLength = qx.ui.core.Widget._globalLayoutQueue.length; + var fastGlobalDisplayQueueLength = qx.ui.core.Widget._fastGlobalDisplayQueue.length; + var lazyGlobalDisplayQueueLength = qx.ui.core.Widget._lazyGlobalDisplayQueue ? qx.ui.core.Widget._lazyGlobalDisplayQueue.length : 0; + + // Also used for inline event handling to seperate 'real' events + qx.ui.core.Widget._inFlushGlobalQueues = true; + + var vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalWidgetQueue(); + var vWidgetDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalStateQueue(); + var vStateDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalElementQueue(); + var vElementDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalJobQueue(); + var vJobDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalLayoutQueue(); + var vLayoutDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalDisplayQueue(); + var vDisplayDuration = (new Date).valueOf() - vStart; + + var vSum = vWidgetDuration + vStateDuration + vElementDuration + vJobDuration + vLayoutDuration + vDisplayDuration; + + if (vSum > 0) + { + var logger = qx.log.Logger.getClassLogger(qx.ui.core.Widget); + logger.debug("Flush Global Queues"); + logger.debug("Widgets: " + vWidgetDuration + "ms (" + globalWidgetQueueLength + ")"); + logger.debug("State: " + vStateDuration + "ms (" + globalStateQueueLength + ")"); + logger.debug("Element: " + vElementDuration + "ms (" + globalElementQueueLength + ")"); + logger.debug("Job: " + vJobDuration + "ms (" + globalJobQueueLength + ")"); + logger.debug("Layout: " + vLayoutDuration + "ms (" + globalLayoutQueueLength + ")"); + logger.debug("Display: " + vDisplayDuration + "ms (fast:" + fastGlobalDisplayQueueLength + ",lazy:" + lazyGlobalDisplayQueueLength + ")"); + + window.status = "Flush: Widget:" + vWidgetDuration + " State:" + vStateDuration + " Element:" + vElementDuration + " Job:" + vJobDuration + " Layout:" + vLayoutDuration + " Display:" + vDisplayDuration; + } + + delete qx.ui.core.Widget._inFlushGlobalQueues; + } +} +else +{ + qx.ui.core.Widget.flushGlobalQueues = function() + { + if (qx.ui.core.Widget._inFlushGlobalQueues || !qx.core.Init.getInstance().getComponent().isUiReady()) { + return; + } + + // Also used for inline event handling to seperate 'real' events + qx.ui.core.Widget._inFlushGlobalQueues = true; + + qx.ui.core.Widget.flushGlobalWidgetQueue(); + qx.ui.core.Widget.flushGlobalStateQueue(); + qx.ui.core.Widget.flushGlobalElementQueue(); + qx.ui.core.Widget.flushGlobalJobQueue(); + qx.ui.core.Widget.flushGlobalLayoutQueue(); + qx.ui.core.Widget.flushGlobalDisplayQueue(); + + delete qx.ui.core.Widget._inFlushGlobalQueues; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET QUEUE + + Allows widgets to register to the widget queue to do multiple things + before the other queues will be flushed +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalWidgetQueue = []; + +qx.ui.core.Widget.addToGlobalWidgetQueue = function(vWidget) +{ + if (!vWidget._isInGlobalWidgetQueue && vWidget._isDisplayable) + { + qx.ui.core.Widget._globalWidgetQueue.push(vWidget); + vWidget._isInGlobalWidgetQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalWidgetQueue = function(vWidget) +{ + if (vWidget._isInGlobalWidgetQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalWidgetQueue, vWidget); + delete vWidget._isInGlobalWidgetQueue; + } +} + +qx.ui.core.Widget.flushGlobalWidgetQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalWidgetQueue, vLength, vWidget; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i<vLength; i++) + { + vWidget = vQueue[i]; + + vWidget.flushWidgetQueue(); + delete vWidget._isInGlobalWidgetQueue; + } + + vQueue.splice(0, vLength); + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT QUEUE + + Contains the widgets which should be (dom-)created +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalElementQueue = []; + +qx.ui.core.Widget.addToGlobalElementQueue = function(vWidget) +{ + if (!vWidget._isInGlobalElementQueue && vWidget._isDisplayable) + { + qx.ui.core.Widget._globalElementQueue.push(vWidget); + vWidget._isInGlobalElementQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalElementQueue = function(vWidget) +{ + if (vWidget._isInGlobalElementQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalElementQueue, vWidget); + delete vWidget._isInGlobalElementQueue; + } +} + +qx.ui.core.Widget.flushGlobalElementQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalElementQueue, vLength, vWidget; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i<vLength; i++) + { + vWidget = vQueue[i]; + + vWidget._createElementImpl(); + delete vWidget._isInGlobalElementQueue; + } + + vQueue.splice(0, vLength); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + STATE QUEUE + + Contains the widgets which recently changed their state +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalStateQueue = []; + +qx.ui.core.Widget.addToGlobalStateQueue = function(vWidget) +{ + if (!vWidget._isInGlobalStateQueue && vWidget._isDisplayable) + { + qx.ui.core.Widget._globalStateQueue.push(vWidget); + vWidget._isInGlobalStateQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalStateQueue = function(vWidget) +{ + if (vWidget._isInGlobalStateQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalStateQueue, vWidget); + delete vWidget._isInGlobalStateQueue; + } +} + +qx.ui.core.Widget.flushGlobalStateQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalStateQueue, vLength, vWidget; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i<vLength; i++) + { + vWidget = vQueue[i]; + + vWidget._applyStateAppearance(); + + delete vWidget._isInGlobalStateQueue; + } + + vQueue.splice(0, vLength); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + JOBS QUEUE + + Contains the widgets which need a update after they were visible before +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalJobQueue = []; + +qx.ui.core.Widget.addToGlobalJobQueue = function(vWidget) +{ + if (!vWidget._isInGlobalJobQueue && vWidget._isDisplayable) + { + qx.ui.core.Widget._globalJobQueue.push(vWidget); + vWidget._isInGlobalJobQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalJobQueue = function(vWidget) +{ + if (vWidget._isInGlobalJobQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalJobQueue, vWidget); + delete vWidget._isInGlobalJobQueue; + } +} + +qx.ui.core.Widget.flushGlobalJobQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalJobQueue, vLength, vWidget; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i<vLength; i++) + { + vWidget = vQueue[i]; + + vWidget._flushJobQueue(vWidget._jobQueue); + delete vWidget._isInGlobalJobQueue; + } + + vQueue.splice(0, vLength); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT QUEUE + + Contains the parents (qx.ui.core.Parent) of the children which needs layout updates +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalLayoutQueue = []; + +qx.ui.core.Widget.addToGlobalLayoutQueue = function(vParent) +{ + if (!vParent._isInGlobalLayoutQueue && vParent._isDisplayable) + { + qx.ui.core.Widget._globalLayoutQueue.push(vParent); + vParent._isInGlobalLayoutQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalLayoutQueue = function(vParent) +{ + if (vParent._isInGlobalLayoutQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalLayoutQueue, vParent); + delete vParent._isInGlobalLayoutQueue; + } +} + +qx.ui.core.Widget.flushGlobalLayoutQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalLayoutQueue, vLength, vParent; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i<vLength; i++) + { + vParent = vQueue[i]; + + vParent._flushChildrenQueue(); + delete vParent._isInGlobalLayoutQueue; + } + + vQueue.splice(0, vLength); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAY QUEUE + + Contains the widgets which should initially become visible +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._fastGlobalDisplayQueue = []; +qx.ui.core.Widget._lazyGlobalDisplayQueues = {}; + +qx.ui.core.Widget.addToGlobalDisplayQueue = function(vWidget) +{ + if (!vWidget._isInGlobalDisplayQueue && vWidget._isDisplayable) + { + var vParent = vWidget.getParent(); + + if (vParent.isSeeable()) + { + var vKey = vParent.toHashCode(); + + if (qx.ui.core.Widget._lazyGlobalDisplayQueues[vKey]) + { + qx.ui.core.Widget._lazyGlobalDisplayQueues[vKey].push(vWidget); + } + else + { + qx.ui.core.Widget._lazyGlobalDisplayQueues[vKey] = [vWidget]; + } + } + else + { + qx.ui.core.Widget._fastGlobalDisplayQueue.push(vWidget); + } + + vWidget._isInGlobalDisplayQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalDisplayQueue = function(vWidget) {} + +qx.ui.core.Widget.flushGlobalDisplayQueue = function() +{ + var vKey, vLazyQueue, vWidget, vFragment; + + var vFastQueue = qx.ui.core.Widget._fastGlobalDisplayQueue; + var vLazyQueues = qx.ui.core.Widget._lazyGlobalDisplayQueues; + + + + + /* ----------------------------------------------- + Flush display queues + ----------------------------------------------- */ + + // Work on fast queue + for (var i=0, l=vFastQueue.length; i<l; i++) + { + vWidget = vFastQueue[i]; + vWidget.getParent()._getTargetNode().appendChild(vWidget.getElement()); + } + + + // Work on lazy queues: Inline widgets + if (qx.OO.isAvailable("qx.ui.basic.Inline")) + { + for (vKey in vLazyQueues) + { + vLazyQueue = vLazyQueues[vKey]; + + for (var i=0; i<vLazyQueue.length; i++) + { + vWidget = vLazyQueue[i]; + + if (vWidget instanceof qx.ui.basic.Inline) + { + vWidget._beforeInsertDom(); + + try + { + document.getElementById(vWidget.getInlineNodeId()).appendChild(vWidget.getElement()); + } + catch(ex) + { + vWidget.debug("Could not append to inline id: " + vWidget.getInlineNodeId(), ex); + } + + vWidget._afterInsertDom(); + vWidget._afterAppear(); + + // Remove inline widget from queue and fix iterator position + qx.lang.Array.remove(vLazyQueue, vWidget); + i--; + + // Reset display queue flag + delete vWidget._isInGlobalDisplayQueue; + } + } + } + } + + + // Work on lazy queues: Other widgets + for (vKey in vLazyQueues) + { + vLazyQueue = vLazyQueues[vKey]; + + // Speed enhancement: Choose a fairly small arbitrary value for the number + // of elements that should be added to the parent individually. If more + // than this number of elements is to be added to the parent, we'll create + // a document fragment, add the elements to the document fragment, and + // then add the whole fragment to the parent en mass (assuming that + // creation of a document fragment is supported by the browser). + if (document.createDocumentFragment && vLazyQueue.length >= 3) + { + // creating new document fragment + vFragment = document.createDocumentFragment(); + + // appending all widget elements to fragment + for (var i=0, l=vLazyQueue.length; i<l; i++) + { + vWidget = vLazyQueue[i]; + + vWidget._beforeInsertDom(); + vFragment.appendChild(vWidget.getElement()); + } + + // append all fragment data at once to + // the already visible parent widget element + vLazyQueue[0].getParent()._getTargetNode().appendChild(vFragment); + + for (var i=0, l=vLazyQueue.length; i<l; i++) + { + vWidget = vLazyQueue[i]; + vWidget._afterInsertDom(); + } + } + else + { + // appending all widget elements (including previously added children) + // to the already visible parent widget element + for (var i=0, l=vLazyQueue.length; i<l; i++) + { + vWidget = vLazyQueue[i]; + + vWidget._beforeInsertDom(); + vWidget.getParent()._getTargetNode().appendChild(vWidget.getElement()); + vWidget._afterInsertDom(); + } + } + } + + + + + + + /* ----------------------------------------------- + Cleanup and appear signals + ----------------------------------------------- */ + + // Only need to do this with the lazy queues + // because through the recursion from qx.ui.core.Parent + // all others get also informed. + for (vKey in vLazyQueues) + { + vLazyQueue = vLazyQueues[vKey]; + + for (var i=0, l=vLazyQueue.length; i<l; i++) + { + vWidget = vLazyQueue[i]; + + if (vWidget.getVisibility()) { + vWidget._afterAppear(); + } + + // Reset display queue flag + delete vWidget._isInGlobalDisplayQueue; + } + + delete vLazyQueues[vKey]; + } + + // Reset display queue flag for widgets in fastQueue + for (var i=0, l=vFastQueue.length; i<l; i++) { + delete vFastQueue[i]._isInGlobalDisplayQueue; + } + + // Remove fast queue entries + qx.lang.Array.removeAll(vFastQueue); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + GLOBAL HELPERS +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget.getActiveSiblingHelperIgnore = function(vIgnoreClasses, vInstance) +{ + for (var j=0; j<vIgnoreClasses.length; j++) { + if (vInstance instanceof vIgnoreClasses[j]) { + return true; + } + } + + return false; +} + +qx.ui.core.Widget.getActiveSiblingHelper = function(vObject, vParent, vCalc, vIgnoreClasses, vMode) +{ + if (!vIgnoreClasses) { + vIgnoreClasses = []; + } + + var vChilds = vParent.getChildren(); + var vPosition = vMode == null ? vChilds.indexOf(vObject) + vCalc : vMode === "first" ? 0 : vChilds.length-1; + var vInstance = vChilds[vPosition]; + + while(vInstance && (!vInstance.isEnabled() || qx.ui.core.Widget.getActiveSiblingHelperIgnore(vIgnoreClasses, vInstance))) + { + vPosition += vCalc; + vInstance = vChilds[vPosition]; + + if (!vInstance) { + return null; + } + } + + return vInstance; +} + + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +/*! + If the widget is visible and rendered on the screen. +*/ +qx.Proto.isMaterialized = function() { + var el=this._element; + return (this._initialLayoutDone && + this._isDisplayable && + qx.html.Style.getStyleProperty(el, "display") != "none" && + qx.html.Style.getStyleProperty(el, "visibility") != "hidden" && + el.offsetWidth > 0 && el.offsetHeight > 0); +} + +/*! + A single setup to the current preferred pixel values of the widget +*/ +qx.Proto.pack = function() +{ + this.setWidth(this.getPreferredBoxWidth()); + this.setHeight(this.getPreferredBoxHeight()); +} + +/*! + A bounded setup to the preferred width/height of the widget. Keeps in + sync if the content or requirements of the widget changes +*/ +qx.Proto.auto = function() +{ + this.setWidth("auto"); + this.setHeight("auto"); +} + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING: ALL +--------------------------------------------------------------------------- +*/ + +/*! + Get an array of the current children +*/ +qx.Proto.getChildren = qx.lang.Function.returnNull; + +/*! + Get the number of children +*/ +qx.Proto.getChildrenLength = qx.lang.Function.returnZero; + +/*! + Get if the widget has any children +*/ +qx.Proto.hasChildren = qx.lang.Function.returnFalse; + +/*! + Get if the widget has no children +*/ +qx.Proto.isEmpty = qx.lang.Function.returnTrue; + +/*! + Return the position of the child inside +*/ +qx.Proto.indexOf = qx.lang.Function.returnNegativeIndex; + +/*! + Test if this widget contains the given widget +*/ +qx.Proto.contains = qx.lang.Function.returnFalse; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING: VISIBLE ONES +--------------------------------------------------------------------------- +*/ + +/*! + Get an array of the current visible children +*/ +qx.Proto.getVisibleChildren = qx.lang.Function.returnNull; + +/*! + Get the number of children +*/ +qx.Proto.getVisibleChildrenLength = qx.lang.Function.returnZero; + +/*! + If this widget has visible children +*/ +qx.Proto.hasVisibleChildren = qx.lang.Function.returnFalse; + +/*! + Check if there are any visible children inside +*/ +qx.Proto.isVisibleEmpty = qx.lang.Function.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + CORE MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._hasParent = false; +qx.Proto._isDisplayable = false; + +qx.Proto.isDisplayable = function() { + return this._isDisplayable; +} + +qx.Proto._checkParent = function(propValue, propOldValue, propData) +{ + if (this.contains(propValue)) { + throw new Error("Could not insert myself into a child " + propValue + "!"); + } + + return propValue; +} + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + var vOldIndex = propOldValue.getChildren().indexOf(this); + + // Reset cached dimension and location values + this._computedWidthValue = this._computedMinWidthValue = this._computedMaxWidthValue = this._computedLeftValue = this._computedRightValue = null; + this._computedHeightValue = this._computedMinHeightValue = this._computedMaxHeightValue = this._computedTopValue = this._computedBottomValue = null; + + this._cachedBoxWidth = this._cachedInnerWidth = this._cachedOuterWidth = null; + this._cachedBoxHeight = this._cachedInnerHeight = this._cachedOuterHeight = null; + + // Finally remove from children array + qx.lang.Array.removeAt(propOldValue.getChildren(), vOldIndex); + + // Invalidate visible children cache + propOldValue._invalidateVisibleChildren(); + + // Remove child from old parent's children queue + propOldValue._removeChildFromChildrenQueue(this); + + // The layouter adds some layout jobs + propOldValue.getLayoutImpl().updateChildrenOnRemoveChild(this, vOldIndex); + + // Inform job queue + propOldValue.addToJobQueue("removeChild"); + + // Invalidate inner preferred dimensions + propOldValue._invalidatePreferredInnerDimensions(); + + // Store old parent (needed later by _handleDisplayable) + this._oldParent = propOldValue; + } + + if (propValue) + { + this._hasParent = true; + + if (typeof this._insertIndex == "number") + { + qx.lang.Array.insertAt(propValue.getChildren(), this, this._insertIndex); + delete this._insertIndex; + } + else + { + propValue.getChildren().push(this); + } + } + else + { + this._hasParent = false; + } + + return this._handleDisplayable("parent"); +} + +qx.Proto._modifyDisplay = function(propValue, propOldValue, propData) { + return this._handleDisplayable("display"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleDisplayable = function(vHint) +{ + // Detect changes. Return if there is no change. + // Also handle the case if the displayable keeps true and the parent + // was changed then we must not return here. + var vDisplayable = this._computeDisplayable(); + if (this._isDisplayable == vDisplayable && !(vDisplayable && vHint == "parent")) { + return true; + } + + this._isDisplayable = vDisplayable; + + var vParent = this.getParent(); + + // Invalidate visible children + if (vParent) + { + vParent._invalidateVisibleChildren(); + vParent._invalidatePreferredInnerDimensions(); + } + + // Remove old parent's elements from DOM and delete old parent + if (vHint && this._oldParent && this._oldParent._initialLayoutDone) + { + var vElement = this.getElement(); + if(vElement) + { + if (this.getVisibility()) { + this._beforeDisappear(); + } + + this._beforeRemoveDom(); + + this._oldParent._getTargetNode().removeChild(vElement); + + this._afterRemoveDom(); + + if (this.getVisibility()) { + this._afterDisappear(); + } + } + + delete this._oldParent; + } + + // Handle 'show' + if (vDisplayable) + { + /* -------------------------------- + Update current parent + -------------------------------- */ + + // The layouter added some layout jobs + if (vParent._initialLayoutDone) + { + vParent.getLayoutImpl().updateChildrenOnAddChild(this, vParent.getChildren().indexOf(this)); + + // Inform parents job queue + vParent.addToJobQueue("addChild"); + } + + // Add to parents children queue + // (indirectly with a new layout request) + this.addToLayoutChanges("initial"); + + // Add to custom queues + this.addToCustomQueues(vHint); + + // Handle beforeAppear signals + if (this.getVisibility()) { + this._beforeAppear(); + } + + + + /* -------------------------------- + Add to global Queues + -------------------------------- */ + + // Add element (and create if not ready) + if (!this._isCreated) { + qx.ui.core.Widget.addToGlobalElementQueue(this); + } + + // Add to global queues + qx.ui.core.Widget.addToGlobalStateQueue(this); + + if (!qx.lang.Object.isEmpty(this._jobQueue)) { + qx.ui.core.Widget.addToGlobalJobQueue(this); + } + + if (!qx.lang.Object.isEmpty(this._childrenQueue)) { + qx.ui.core.Widget.addToGlobalLayoutQueue(this); + } + } + + // Handle 'hide' + else + { + // Removing from global queues + qx.ui.core.Widget.removeFromGlobalElementQueue(this); + qx.ui.core.Widget.removeFromGlobalStateQueue(this); + qx.ui.core.Widget.removeFromGlobalJobQueue(this); + qx.ui.core.Widget.removeFromGlobalLayoutQueue(this); + + // Add to top-level tree queue + this.removeFromCustomQueues(vHint); + + // only remove when itself want to be removed + // through a property change - not a parent signal + if (vParent && vHint) + { + if (this.getVisibility()) { + this._beforeDisappear(); + } + + // The layouter added some layout jobs + if (vParent._initialLayoutDone && this._initialLayoutDone) + { + vParent.getLayoutImpl().updateChildrenOnRemoveChild(this, vParent.getChildren().indexOf(this)); + + // Inform parent's job queue + vParent.addToJobQueue("removeChild"); + + // Before Remove DOM Event + this._beforeRemoveDom(); + + // DOM action + vParent._getTargetNode().removeChild(this.getElement()); + + // After Remove DOM Event + this._afterRemoveDom(); + } + + // Remove from parents children queue + vParent._removeChildFromChildrenQueue(this); + + if (this.getVisibility()) { + this._afterDisappear(); + } + } + } + + this._handleDisplayableCustom(vDisplayable, vParent, vHint); + + return true; +} + +qx.Proto.addToCustomQueues = qx.lang.Function.returnTrue; +qx.Proto.removeFromCustomQueues = qx.lang.Function.returnTrue; + +qx.Proto._handleDisplayableCustom = qx.lang.Function.returnTrue; + +qx.Proto._computeDisplayable = function() { + return this.getDisplay() && this._hasParent && this.getParent()._isDisplayable ? true : false; +} + +qx.Proto._beforeAppear = function() +{ + // this.debug("_beforeAppear"); + this.createDispatchEvent("beforeAppear"); +} + +qx.Proto._afterAppear = function() +{ + // this.debug("_afterAppear"); + this._isSeeable = true; + this.createDispatchEvent("appear"); +} + +qx.Proto._beforeDisappear = function() +{ + // this.debug("_beforeDisappear"); + + // Remove any hover/pressed styles + this.removeState("over"); + + if (qx.OO.isAvailable("qx.ui.form.Button")) + { + this.removeState("pressed"); + this.removeState("abandoned"); + } + + // this.debug("_beforeDisappear"); + this.createDispatchEvent("beforeDisappear"); +} + +qx.Proto._afterDisappear = function() +{ + // this.debug("_afterDisappear"); + this._isSeeable = false; + this.createDispatchEvent("disappear"); +} + +qx.Proto._isSeeable = false; + +/** + * If the widget is currently seeable which means that it: + * + * * has a also seeable parent + * * visibility is true + * * display is true + */ +qx.Proto.isSeeable = function() { + return this._isSeeable; +} + +qx.Proto.isAppearRelevant = function() { + return this.getVisibility() && this._isDisplayable; +} + + + + + +/* +--------------------------------------------------------------------------- + DOM SIGNAL HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeInsertDom = function() +{ + // this.debug("_beforeInsertDom"); + this.createDispatchEvent("beforeInsertDom"); +} + +qx.Proto._afterInsertDom = function() +{ + // this.debug("_afterInsertDom"); + this.createDispatchEvent("insertDom"); +} + +qx.Proto._beforeRemoveDom = function() +{ + // this.debug("_beforeRemoveDom"); + this.createDispatchEvent("beforeRemoveDom"); +} + +qx.Proto._afterRemoveDom = function() +{ + // this.debug("_afterRemoveDom"); + this.createDispatchEvent("removeDom"); +} + + + + + + +/* +--------------------------------------------------------------------------- + VISIBILITY HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyVisibility = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (this._isDisplayable) { + this._beforeAppear(); + } + + this.removeStyleProperty("display"); + + if (this._isDisplayable) { + this._afterAppear(); + } + } + else + { + if (this._isDisplayable) { + this._beforeDisappear(); + } + + this.setStyleProperty("display", "none"); + + if (this._isDisplayable) { + this._afterDisappear(); + } + } + + return true; +} + +qx.Proto.show = function() +{ + this.setVisibility(true); + this.setDisplay(true); +} + +qx.Proto.hide = function() { + this.setVisibility(false); +} + +qx.Proto.connect = function() { + this.setDisplay(true); +} + +qx.Proto.disconnect = function() { + this.setDisplay(false); +} + + + + + +/* +--------------------------------------------------------------------------- + ENHANCED BORDER SUPPORT +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._createElementForEnhancedBorder = qx.lang.Function.returnTrue; +} +else +{ + qx.Proto._createElementForEnhancedBorder = function() + { + // Enhanced Border Test (for IE and Opera) + if (qx.renderer.border.Border.enhancedCrossBrowserMode && + this.getTagName() == "div" && + !this._borderElement) + { + var el = this.getElement(); + var cl = this._borderElement = document.createElement("div"); + + var es = el.style; + var cs = this._borderStyle = cl.style; + + cs.width = cs.height = "100%"; + cs.position = "absolute"; + + for (var i in this._styleProperties) + { + switch(i) + { + case "position": + case "zIndex": + case "filter": + case "display": + break; + + default: + cs[i] = this._styleProperties[i]; + es[i] = ""; + } + } + + for (var i in this._htmlProperties) + { + switch(i) + { + case "unselectable": + cl.unselectable = this._htmlProperties[i]; + } + } + + // Move existing children + while(el.firstChild) { + cl.appendChild(el.firstChild); + } + + el.appendChild(cl); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DOM ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._isCreated = false; + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._getTargetNode = function() { + return this._element; + } +} +else +{ + qx.Proto._getTargetNode = function() { + return this._borderElement || this._element; + } +} + +qx.Proto.addToDocument = function() { + qx.ui.core.ClientDocument.getInstance().add(this); +} + +/** + * Check if the widget is created (or the element is already available). + * + * @return {Boolean} whether the widget is already created. + */ +qx.Proto.isCreated = function() { + return this._isCreated; +} + +/*! + Create widget with empty element (of specified tagname). +*/ +qx.Proto._createElementImpl = function() { + this.setElement(this.getTopLevelWidget().getDocumentElement().createElement(this.getTagName())); +} + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + this._isCreated = propValue != null; + + if (propOldValue) + { + // reset reference to widget instance + propOldValue.qx_Widget = null; + + // remove events + this._removeInlineEvents(propOldValue); + } + + if (propValue) + { + // add reference to widget instance + propValue.qx_Widget = this; + + // link element and style reference + this._element = propValue; + this._style = propValue.style; + + this._applyStyleProperties(propValue); + this._applyHtmlProperties(propValue); + this._applyHtmlAttributes(propValue); + this._applyElementData(propValue); + + // attach inline events + this._addInlineEvents(propValue); + + // send out create event + this.createDispatchEvent("create"); + } + else + { + this._element = this._style = null; + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + JOBS QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto.addToJobQueue = function(p) +{ + if (this._hasParent) { + qx.ui.core.Widget.addToGlobalJobQueue(this); + } + + if (!this._jobQueue) { + this._jobQueue = {}; + } + + this._jobQueue[p] = true; + return true; +} + +qx.Proto._flushJobQueue = function(q) +{ + /* -------------------------------------------------------------------------------- + 1. Pre checks + -------------------------------------------------------------------------------- */ + + try + { + var vQueue = this._jobQueue; + var vParent = this.getParent(); + + if (!vParent || qx.lang.Object.isEmpty(vQueue)) { + return; + } + + var vLayoutImpl = this instanceof qx.ui.core.Parent ? this.getLayoutImpl() : null; + + if (vLayoutImpl) { + vLayoutImpl.updateSelfOnJobQueueFlush(vQueue); + } + } + catch(ex) + { + this.error("Flushing job queue (prechecks#1) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 2. Recompute dimensions + -------------------------------------------------------------------------------- */ + + try + { + var vFlushParentJobQueue = false; + var vRecomputeOuterWidth = vQueue.marginLeft || vQueue.marginRight; + var vRecomputeOuterHeight = vQueue.marginTop || vQueue.marginBottom; + var vRecomputeInnerWidth = vQueue.frameWidth; + var vRecomputeInnerHeight = vQueue.frameHeight; + var vRecomputeParentPreferredInnerWidth = (vQueue.frameWidth || vQueue.preferredInnerWidth) && this._recomputePreferredBoxWidth(); + var vRecomputeParentPreferredInnerHeight = (vQueue.frameHeight || vQueue.preferredInnerHeight) && this._recomputePreferredBoxHeight(); + + if (vRecomputeParentPreferredInnerWidth) + { + var vPref = this.getPreferredBoxWidth(); + + if (this._computedWidthTypeAuto) + { + this._computedWidthValue = vPref; + vQueue.width = true; + } + + if (this._computedMinWidthTypeAuto) + { + this._computedMinWidthValue = vPref; + vQueue.minWidth = true; + } + + if (this._computedMaxWidthTypeAuto) + { + this._computedMaxWidthValue = vPref; + vQueue.maxWidth = true; + } + } + + if (vRecomputeParentPreferredInnerHeight) + { + var vPref = this.getPreferredBoxHeight(); + + if (this._computedHeightTypeAuto) + { + this._computedHeightValue = vPref; + vQueue.height = true; + } + + if (this._computedMinHeightTypeAuto) + { + this._computedMinHeightValue = vPref; + vQueue.minHeight = true; + } + + if (this._computedMaxHeightTypeAuto) + { + this._computedMaxHeightValue = vPref; + vQueue.maxHeight = true; + } + } + + if ((vQueue.width || vQueue.minWidth || vQueue.maxWidth || vQueue.left || vQueue.right) && this._recomputeBoxWidth()) { + vRecomputeOuterWidth = vRecomputeInnerWidth = true; + } + + if ((vQueue.height || vQueue.minHeight || vQueue.maxHeight || vQueue.top || vQueue.bottom) && this._recomputeBoxHeight()) { + vRecomputeOuterHeight = vRecomputeInnerHeight = true; + } + } + catch(ex) + { + this.error("Flushing job queue (recompute#2) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 3. Signals to parent widgets + -------------------------------------------------------------------------------- */ + + try + { + if ((vRecomputeOuterWidth && this._recomputeOuterWidth()) || + vRecomputeParentPreferredInnerWidth) + { + vParent._invalidatePreferredInnerWidth(); + vParent.getLayoutImpl().updateSelfOnChildOuterWidthChange(this); + + vFlushParentJobQueue = true; + } + + if ((vRecomputeOuterHeight && this._recomputeOuterHeight()) || + vRecomputeParentPreferredInnerHeight) + { + vParent._invalidatePreferredInnerHeight(); + vParent.getLayoutImpl().updateSelfOnChildOuterHeightChange(this); + + vFlushParentJobQueue = true; + } + + if (vFlushParentJobQueue) { + vParent._flushJobQueue(); + } + } + catch(ex) + { + this.error("Flushing job queue (parentsignals#3) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 4. Add layout jobs + -------------------------------------------------------------------------------- */ + + try + { + // add to layout queue + vParent._addChildToChildrenQueue(this); + + // convert jobs to layout jobs + for (var i in vQueue) { + this._layoutChanges[i] = true; + } + } + catch(ex) + { + this.error("Flushing job queue (addjobs#4) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 5. Signals to children + -------------------------------------------------------------------------------- */ + + try + { + // inform children about padding change + if (this instanceof qx.ui.core.Parent && + (vQueue.paddingLeft || + vQueue.paddingRight || + vQueue.paddingTop || + vQueue.paddingBottom)) + { + var ch=this.getChildren(), chl=ch.length; + + if (vQueue.paddingLeft) { + for (var i=0; i<chl; i++) { + ch[i].addToLayoutChanges("parentPaddingLeft"); + } + } + + if (vQueue.paddingRight) { + for (var i=0; i<chl; i++) { + ch[i].addToLayoutChanges("parentPaddingRight"); + } + } + + if (vQueue.paddingTop) { + for (var i=0; i<chl; i++) { + ch[i].addToLayoutChanges("parentPaddingTop"); + } + } + + if (vQueue.paddingBottom) { + for (var i=0; i<chl; i++) { + ch[i].addToLayoutChanges("parentPaddingBottom"); + } + } + } + + if (vRecomputeInnerWidth) { + this._recomputeInnerWidth(); + } + + if (vRecomputeInnerHeight) { + this._recomputeInnerHeight(); + } + + if (this._initialLayoutDone) + { + if (vLayoutImpl) { + vLayoutImpl.updateChildrenOnJobQueueFlush(vQueue); + } + } + } + catch(ex) + { + this.error("Flushing job queue (childrensignals#5) failed", ex); + } + + + + /* -------------------------------------------------------------------------------- + 5. Cleanup + -------------------------------------------------------------------------------- */ + + delete this._jobQueue; +} + + + + + +/* +--------------------------------------------------------------------------- + METHODS TO GIVE THE LAYOUTERS INFORMATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._isWidthEssential = qx.lang.Function.returnTrue; +qx.Proto._isHeightEssential = qx.lang.Function.returnTrue; + + + + + + + +/* +--------------------------------------------------------------------------- + APPLY LAYOUT STYLES +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget.initApplyMethods = function() +{ + var f = "_applyRuntime"; + var r = "_resetRuntime"; + var s = "this._style."; + var e = "=''"; + var v = "=((v==null)?0:v)+'px'"; + var vpar = "v"; + + var props = ["left", "right", "top", "bottom", "width", "height", + "minWidth", "maxWidth", "minHeight", "maxHeight"]; + var propsup = ["Left", "Right", "Top", "Bottom", "Width", "Height", + "MinWidth", "MaxWidth", "MinHeight", "MaxHeight"]; + + for (var i=0, fn=f+"Margin", rn=r+"Margin", sp=s+"margin"; i<4; i++) + { + qx.Proto[fn+propsup[i]] = new Function(vpar, sp + propsup[i] + v); + qx.Proto[rn+propsup[i]] = new Function(sp + propsup[i] + e); + } + + var pad = "padding"; + var upad = "Padding"; + + if (qx.core.Client.getInstance().isGecko()) + { + for (var i=0, fn=f+upad, rn=r+upad, sp=s+pad; i<4; i++) + { + qx.Proto[fn+propsup[i]] = new Function(vpar, sp + propsup[i] + v); + qx.Proto[rn+propsup[i]] = new Function(sp + propsup[i] + e); + } + } + else + { + // need to use setStyleProperty to keep compatibility with enhanced cross browser borders + var s1="this.setStyleProperty('padding"; + var s2="', ((v==null)?0:v)+'px')"; + var s3="this.removeStyleProperty('padding"; + var s4="')"; + + for (var i=0, fn=f+upad, rn=r+upad, sp=s+pad; i<4; i++) + { + qx.Proto[fn+propsup[i]] = new Function(vpar, s1 + propsup[i] + s2); + qx.Proto[rn+propsup[i]] = new Function(s3 + propsup[i] + s4); + } + } + + /* + Use optimized method for internet explorer + to omit string concat and directly setup + the new layout property. + + We could not use this to reset the value however. + It seems that is just doesn't work this way. And the + left/top always get priority. Tried: "", null, "auto". + Nothing helps. + + Now I've switched back to the conventional method + to reset the value. This seems to work again. + */ + if (qx.core.Client.getInstance().isMshtml()) + { + for (var i=0, tpos="pos", vset="=v"; i<6; i++) + { + // to debug the values which will be applied use this instead of the + // first line: + // qx.Proto[f+propsup[i]] = new Function(vpar, "this.debug('v: ' + v); " + s + tpos + propsup[i] + vset); + + qx.Proto[f+propsup[i]] = new Function(vpar, s + tpos + propsup[i] + vset); + qx.Proto[r+propsup[i]] = new Function(s + props[i] + e); + } + } + else + { + for (var i=0; i<10; i++) + { + // to debug the values which will be applied use this instead of the + // first line: + // qx.Proto[f+propsup[i]] = new Function(vpar, "this.debug('v: ' + v); " + s + props[i] + v); + + qx.Proto[f+propsup[i]] = new Function(vpar, s + props[i] + v); + qx.Proto[r+propsup[i]] = new Function(s + props[i] + e); + } + } +} + +qx.ui.core.Widget.initApplyMethods(); + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +/* + Add basic setter/getters +*/ + +qx.OO.addCachedProperty({ name : "innerWidth", defaultValue : null }); +qx.OO.addCachedProperty({ name : "innerHeight", defaultValue : null }); +qx.OO.addCachedProperty({ name : "boxWidth", defaultValue : null }); +qx.OO.addCachedProperty({ name : "boxHeight", defaultValue : null }); +qx.OO.addCachedProperty({ name : "outerWidth", defaultValue : null }); +qx.OO.addCachedProperty({ name : "outerHeight", defaultValue : null }); + +qx.Proto._computeBoxWidthFallback = function() { + return 0; +} + +qx.Proto._computeBoxHeightFallback = function() { + return 0; +} + +qx.Proto._computeBoxWidth = function() { + var vLayoutImpl = this.getParent().getLayoutImpl(); + return Math.max(0, + qx.lang.Number.limit(vLayoutImpl.computeChildBoxWidth(this), + this.getMinWidthValue(), + this.getMaxWidthValue())); +} + +qx.Proto._computeBoxHeight = function() { + var vLayoutImpl = this.getParent().getLayoutImpl(); + return Math.max(0, + qx.lang.Number.limit(vLayoutImpl.computeChildBoxHeight(this), + this.getMinHeightValue(), + this.getMaxHeightValue())); +} + +qx.Proto._computeOuterWidth = function() { + return Math.max(0, + (this.getMarginLeft() + + this.getBoxWidth() + + this.getMarginRight())); +} + +qx.Proto._computeOuterHeight = function() { + return Math.max(0, + (this.getMarginTop() + + this.getBoxHeight() + + this.getMarginBottom())); +} + +qx.Proto._computeInnerWidth = function() { + return Math.max(0, this.getBoxWidth() - this.getFrameWidth()); +} + +qx.Proto._computeInnerHeight = function() { + return Math.max(0, this.getBoxHeight() - this.getFrameHeight()); +} + +qx.Proto.getNeededWidth = function() { + var vLayoutImpl = this.getParent().getLayoutImpl(); + return Math.max(0, vLayoutImpl.computeChildNeededWidth(this)); +} + +qx.Proto.getNeededHeight = function() { + var vLayoutImpl = this.getParent().getLayoutImpl(); + return Math.max(0, vLayoutImpl.computeChildNeededHeight(this)); +} + + + + + + + +/* +--------------------------------------------------------------------------- + RECOMPUTE FLEX VALUES +--------------------------------------------------------------------------- +*/ + +qx.Proto._recomputeFlexX = function() +{ + if (!this.getHasFlexX()) { + return false; + } + + if (this._computedWidthTypeFlex) + { + this._computedWidthValue = null; + this.addToLayoutChanges("width"); + } + + return true; +} + +qx.Proto._recomputeFlexY = function() +{ + if (!this.getHasFlexY()) { + return false; + } + + if (this._computedHeightTypeFlex) + { + this._computedHeightValue = null; + this.addToLayoutChanges("height"); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + RECOMPUTE PERCENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._recomputePercentX = function() +{ + if (!this.getHasPercentX()) { + return false; + } + + if (this._computedWidthTypePercent) + { + this._computedWidthValue = null; + this.addToLayoutChanges("width"); + } + + if (this._computedMinWidthTypePercent) + { + this._computedMinWidthValue = null; + this.addToLayoutChanges("minWidth"); + } + + if (this._computedMaxWidthTypePercent) + { + this._computedMaxWidthValue = null; + this.addToLayoutChanges("maxWidth"); + } + + if (this._computedLeftTypePercent) + { + this._computedLeftValue = null; + this.addToLayoutChanges("left"); + } + + if (this._computedRightTypePercent) + { + this._computedRightValue = null; + this.addToLayoutChanges("right"); + } + + return true; +} + +qx.Proto._recomputePercentY = function() +{ + if (!this.getHasPercentY()) { + return false; + } + + if (this._computedHeightTypePercent) + { + this._computedHeightValue = null; + this.addToLayoutChanges("height"); + } + + if (this._computedMinHeightTypePercent) + { + this._computedMinHeightValue = null; + this.addToLayoutChanges("minHeight"); + } + + if (this._computedMaxHeightTypePercent) + { + this._computedMaxHeightValue = null; + this.addToLayoutChanges("maxHeight"); + } + + if (this._computedTopTypePercent) + { + this._computedTopValue = null; + this.addToLayoutChanges("top"); + } + + if (this._computedBottomTypePercent) + { + this._computedBottomValue = null; + this.addToLayoutChanges("bottom"); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + RECOMPUTE RANGES +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._recomputeRangeX = function() + { + if (this._computedLeftTypeNull || this._computedRightTypeNull) { + return false; + } + + this.addToLayoutChanges("width"); + return true; + } + + qx.Proto._recomputeRangeY = function() + { + if (this._computedTopTypeNull || this._computedBottomTypeNull) { + return false; + } + + this.addToLayoutChanges("height"); + return true; + } +} +else +{ + qx.Proto._recomputeRangeX = function() { + return !(this._computedLeftTypeNull || this._computedRightTypeNull); + } + + qx.Proto._recomputeRangeY = function() { + return !(this._computedTopTypeNull || this._computedBottomTypeNull); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + RECOMPUTE STRETCHING +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml() || qx.core.Client.getInstance().isOpera()) +{ + qx.Proto._recomputeStretchingX = function() + { + if (this.getAllowStretchX() && this._computedWidthTypeNull) + { + this._computedWidthValue = null; + this.addToLayoutChanges("width"); + + return true; + } + + return false; + } + + qx.Proto._recomputeStretchingY = function() + { + if (this.getAllowStretchY() && this._computedHeightTypeNull) + { + this._computedHeightValue = null; + this.addToLayoutChanges("height"); + + return true; + } + + return false; + } +} +else +{ + qx.Proto._recomputeStretchingX = function() + { + if (this.getAllowStretchX() && this._computedWidthTypeNull) { + return true; + } + + return false; + } + + qx.Proto._recomputeStretchingY = function() + { + if (this.getAllowStretchY() && this._computedHeightTypeNull) { + return true; + } + + return false; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + INTELLIGENT GETTERS FOR STANDALONE DIMENSIONS: HELPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeValuePixel = function(v) { + return Math.round(v); +} + +qx.Proto._computeValuePixelLimit = function(v) { + return Math.max(0, this._computeValuePixel(v)); +} + +qx.Proto._computeValuePercentX = function(v) { + return Math.round(this.getParent().getInnerWidthForChild(this) * v * 0.01); +} + +qx.Proto._computeValuePercentXLimit = function(v) { + return Math.max(0, this._computeValuePercentX(v)); +} + +qx.Proto._computeValuePercentY = function(v) { + return Math.round(this.getParent().getInnerHeightForChild(this) * v * 0.01); +} + +qx.Proto._computeValuePercentYLimit = function(v) { + return Math.max(0, this._computeValuePercentY(v)); +} + + + + + +/* +--------------------------------------------------------------------------- + INTELLIGENT GETTERS FOR STANDALONE DIMENSIONS: X-AXIS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWidthValue = function() +{ + if (this._computedWidthValue != null) { + return this._computedWidthValue; + } + + switch(this._computedWidthType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedWidthValue = this._computeValuePixelLimit(this._computedWidthParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedWidthValue = this._computeValuePercentXLimit(this._computedWidthParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedWidthValue = this.getPreferredBoxWidth(); + + case qx.ui.core.Widget.TYPE_FLEX: + try{ + this.getParent().getLayoutImpl().computeChildrenFlexWidth(); + } catch (e){ + if (this.getParent().getLayoutImpl()["computeChildrenFlexWidth"] == null){ + throw new Error("Widget " + this + ": having flex size but parent layout does not support it"); + } else { + throw e; + } + } + return this._computedWidthValue = this._computedWidthFlexValue; + } + + return null; +} + +qx.Proto.getMinWidthValue = function() +{ + if (this._computedMinWidthValue != null) { + return this._computedMinWidthValue; + } + + switch(this._computedMinWidthType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedWidthValue = this._computeValuePixelLimit(this._computedMinWidthParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedWidthValue = this._computeValuePercentXLimit(this._computedMinWidthParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedMinWidthValue = this.getPreferredBoxWidth(); + } + + return null; +} + +qx.Proto.getMaxWidthValue = function() +{ + if (this._computedMaxWidthValue != null) { + return this._computedMaxWidthValue; + } + + switch(this._computedMaxWidthType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedWidthValue = this._computeValuePixelLimit(this._computedMaxWidthParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedWidthValue = this._computeValuePercentXLimit(this._computedMaxWidthParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedMaxWidthValue = this.getPreferredBoxWidth(); + } + + return null; +} + +qx.Proto.getLeftValue = function() +{ + if (this._computedLeftValue != null) { + return this._computedLeftValue; + } + + switch(this._computedLeftType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedLeftValue = this._computeValuePixel(this._computedLeftParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedLeftValue = this._computeValuePercentX(this._computedLeftParsed); + } + + return null; +} + +qx.Proto.getRightValue = function() +{ + if (this._computedRightValue != null) { + return this._computedRightValue; + } + + switch(this._computedRightType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedRightValue = this._computeValuePixel(this._computedRightParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedRightValue = this._computeValuePercentX(this._computedRightParsed); + } + + return null; +} + + + + + + + +/* +--------------------------------------------------------------------------- + INTELLIGENT GETTERS FOR STANDALONE DIMENSIONS: Y-AXIS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getHeightValue = function() +{ + if (this._computedHeightValue != null) { + return this._computedHeightValue; + } + + switch(this._computedHeightType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedHeightValue = this._computeValuePixelLimit(this._computedHeightParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedHeightValue = this._computeValuePercentYLimit(this._computedHeightParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedHeightValue = this.getPreferredBoxHeight(); + + case qx.ui.core.Widget.TYPE_FLEX: + try{ + this.getParent().getLayoutImpl().computeChildrenFlexHeight(); + } catch (e){ + if (this.getParent().getLayoutImpl()["computeChildrenFlexHeight"] == null){ + throw new Error("Widget " + this + ": having flex size but parent layout does not support it"); + } else { + throw e; + } + } + return this._computedHeightValue = this._computedHeightFlexValue; + } + + return null; +} + +qx.Proto.getMinHeightValue = function() +{ + if (this._computedMinHeightValue != null) { + return this._computedMinHeightValue; + } + + switch(this._computedMinHeightType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedMinHeightValue = this._computeValuePixelLimit(this._computedMinHeightParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedMinHeightValue = this._computeValuePercentYLimit(this._computedMinHeightParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedMinHeightValue = this.getPreferredBoxHeight(); + } + + return null; +} + +qx.Proto.getMaxHeightValue = function() +{ + if (this._computedMaxHeightValue != null) { + return this._computedMaxHeightValue; + } + + switch(this._computedMaxHeightType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedMaxHeightValue = this._computeValuePixelLimit(this._computedMaxHeightParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedMaxHeightValue = this._computeValuePercentYLimit(this._computedMaxHeightParsed); + + case qx.ui.core.Widget.TYPE_AUTO: + return this._computedMaxHeightValue = this.getPreferredBoxHeight(); + } + + return null; +} + +qx.Proto.getTopValue = function() +{ + if (this._computedTopValue != null) { + return this._computedTopValue; + } + + switch(this._computedTopType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedTopValue = this._computeValuePixel(this._computedTopParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedTopValue = this._computeValuePercentY(this._computedTopParsed); + } + + return null; +} + +qx.Proto.getBottomValue = function() +{ + if (this._computedBottomValue != null) { + return this._computedBottomValue; + } + + switch(this._computedBottomType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + return this._computedBottomValue = this._computeValuePixel(this._computedBottomParsed); + + case qx.ui.core.Widget.TYPE_PERCENT: + return this._computedBottomValue = this._computeValuePercentY(this._computedBottomParsed); + } + + return null; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + FRAME DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "frameWidth", defaultValue : null, addToQueueRuntime : true }); +qx.OO.addCachedProperty({ name : "frameHeight", defaultValue : null, addToQueueRuntime : true }); + +qx.Proto._computeFrameWidth = function() +{ + var fw = this._cachedBorderLeft + this.getPaddingLeft() + this.getPaddingRight() + this._cachedBorderRight; + + switch(this.getOverflow()) + { + case "scroll": + case "scrollY": + qx.ui.core.Widget.initOverflow(); + fw += qx.ui.core.Widget.SCROLLBAR_SIZE; + break; + + case "auto": + // This seems to be really hard to implement + // this.debug("Check Auto Scroll-X: " + this.getPreferredBoxHeight() + " :: " + this.getBoxHeight()); + break; + } + + return fw; +} + +qx.Proto._computeFrameHeight = function() +{ + var fh = this._cachedBorderTop + this.getPaddingTop() + this.getPaddingBottom() + this._cachedBorderBottom; + + switch(this.getOverflow()) + { + case "scroll": + case "scrollX": + qx.ui.core.Widget.initOverflow(); + fh += qx.ui.core.Widget.SCROLLBAR_SIZE; + break; + + case "auto": + // This seems to be really hard to implement + // this.debug("Check Auto Scroll-Y: " + this.getPreferredBoxWidth() + " :: " + this.getBoxWidth()); + break; + } + + return fh; +} + +qx.Proto._invalidateFrameDimensions = function() +{ + this._invalidateFrameWidth(); + this._invalidateFrameHeight(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS: INNER +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "preferredInnerWidth", defaultValue : null, addToQueueRuntime : true }); +qx.OO.addCachedProperty({ name : "preferredInnerHeight", defaultValue : null, addToQueueRuntime : true }); + +qx.Proto._invalidatePreferredInnerDimensions = function() +{ + this._invalidatePreferredInnerWidth(); + this._invalidatePreferredInnerHeight(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS: BOX +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "preferredBoxWidth", defaultValue : null }); +qx.OO.addCachedProperty({ name : "preferredBoxHeight", defaultValue : null }); + +qx.Proto._computePreferredBoxWidth = function() +{ + try { + return Math.max(0, this.getPreferredInnerWidth() + this.getFrameWidth()); + } catch(ex) { + this.error("_computePreferredBoxWidth failed", ex); + } +} + +qx.Proto._computePreferredBoxHeight = function() +{ + try { + return Math.max(0, this.getPreferredInnerHeight() + this.getFrameHeight()); + } catch(ex) { + this.error("_computePreferredBoxHeight failed", ex); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto._initialLayoutDone = false; + +qx.Proto.addToLayoutChanges = function(p) +{ + if (this._isDisplayable) { + this.getParent()._addChildToChildrenQueue(this); + } + + return this._layoutChanges[p] = true; +} + +qx.Proto.addToQueue = function(p) { + this._initialLayoutDone ? this.addToJobQueue(p) : this.addToLayoutChanges(p); +} + +qx.Proto.addToQueueRuntime = function(p) { + return !this._initialLayoutDone || this.addToJobQueue(p); +} + + + + + + + +/* +--------------------------------------------------------------------------- + BORDER/MARGIN/PADDING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyBorderX = function(vChild, vChanges, vStyle) +{ + var vBorder = vChild.getBorder(); + vBorder ? vBorder._applyWidgetX(vChild) : qx.renderer.border.Border._resetBorderX(vChild); +} + +qx.Proto._applyBorderY = function(vChild, vChanges, vStyle) +{ + var vBorder = vChild.getBorder(); + vBorder ? vBorder._applyWidgetY(vChild) : qx.renderer.border.Border._resetBorderY(vChild); +} + +qx.Proto._applyPaddingX = qx.lang.Function.returnTrue; +qx.Proto._applyPaddingY = qx.lang.Function.returnTrue; + + + + + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT AUTO/PERCENT CACHE +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "hasPercentX", defaultValue : false }); +qx.OO.addCachedProperty({ name : "hasPercentY", defaultValue : false }); +qx.OO.addCachedProperty({ name : "hasAutoX", defaultValue : false }); +qx.OO.addCachedProperty({ name : "hasAutoY", defaultValue : false }); +qx.OO.addCachedProperty({ name : "hasFlexX", defaultValue : false }); +qx.OO.addCachedProperty({ name : "hasFlexY", defaultValue : false }); + +qx.Proto._computeHasPercentX = function() { + return (this._computedLeftTypePercent || + this._computedWidthTypePercent || + this._computedMinWidthTypePercent || + this._computedMaxWidthTypePercent || + this._computedRightTypePercent); +} + +qx.Proto._computeHasPercentY = function() { + return (this._computedTopTypePercent || + this._computedHeightTypePercent || + this._computedMinHeightTypePercent || + this._computedMaxHeightTypePercent || + this._computedBottomTypePercent); +} + +qx.Proto._computeHasAutoX = function() { + return (this._computedWidthTypeAuto || + this._computedMinWidthTypeAuto || + this._computedMaxWidthTypeAuto); +} + +qx.Proto._computeHasAutoY = function() { + return (this._computedHeightTypeAuto || + this._computedMinHeightTypeAuto || + this._computedMaxHeightTypeAuto); +} + +qx.Proto._computeHasFlexX = function() { + return this._computedWidthTypeFlex; +} + +qx.Proto._computeHasFlexY = function() { + return this._computedHeightTypeFlex; +} + + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT TYPE INDENTIFY HELPER METHODS +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget.TYPE_NULL = 0; +qx.ui.core.Widget.TYPE_PIXEL = 1; +qx.ui.core.Widget.TYPE_PERCENT = 2; +qx.ui.core.Widget.TYPE_AUTO = 3; +qx.ui.core.Widget.TYPE_FLEX = 4; + +qx.Proto._evalUnitsPixelPercentAutoFlex = function(propValue) +{ + switch(propValue) + { + case "auto": + return qx.ui.core.Widget.TYPE_AUTO; + + case Infinity: + case -Infinity: + return qx.ui.core.Widget.TYPE_NULL; + } + + switch(typeof propValue) + { + case "number": + return isNaN(propValue) ? qx.ui.core.Widget.TYPE_NULL : qx.ui.core.Widget.TYPE_PIXEL; + + case "string": + return propValue.indexOf("%") != -1 ? qx.ui.core.Widget.TYPE_PERCENT : propValue.indexOf("*") != -1 ? qx.ui.core.Widget.TYPE_FLEX : qx.ui.core.Widget.TYPE_NULL; + } + + return qx.ui.core.Widget.TYPE_NULL; +} + +qx.Proto._evalUnitsPixelPercentAuto = function(propValue) +{ + switch(propValue) + { + case "auto": + return qx.ui.core.Widget.TYPE_AUTO; + + case Infinity: + case -Infinity: + return qx.ui.core.Widget.TYPE_NULL; + } + + switch(typeof propValue) + { + case "number": + return isNaN(propValue) ? qx.ui.core.Widget.TYPE_NULL : qx.ui.core.Widget.TYPE_PIXEL; + + case "string": + return propValue.indexOf("%") != -1 ? qx.ui.core.Widget.TYPE_PERCENT : qx.ui.core.Widget.TYPE_NULL; + } + + return qx.ui.core.Widget.TYPE_NULL; +} + +qx.Proto._evalUnitsPixelPercent = function(propValue) +{ + switch(propValue) + { + case Infinity: + case -Infinity: + return qx.ui.core.Widget.TYPE_NULL; + } + + switch(typeof propValue) + { + case "number": + return isNaN(propValue) ? qx.ui.core.Widget.TYPE_NULL : qx.ui.core.Widget.TYPE_PIXEL; + + case "string": + return propValue.indexOf("%") != -1 ? qx.ui.core.Widget.TYPE_PERCENT : qx.ui.core.Widget.TYPE_NULL; + } + + return qx.ui.core.Widget.TYPE_NULL; +} + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT TYPE AND VALUE KEY PRE-CACHE +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget.layoutPropertyTypes = {}; + +qx.ui.core.Widget.initLayoutProperties = function() +{ + var a = [ "width", "height", + "minWidth", "maxWidth", + "minHeight", "maxHeight", + "left", "right", "top", "bottom" ]; + + for (var i=0, l=a.length, p, b, t; i<l; i++) + { + p = a[i]; + b = "_computed" + qx.lang.String.toFirstUp(p); + t = b + "Type"; + + qx.ui.core.Widget.layoutPropertyTypes[p] = + { + dataType : t, + dataParsed : b + "Parsed", + dataValue : b + "Value", + + typePixel : t + "Pixel", + typePercent : t + "Percent", + typeAuto : t + "Auto", + typeFlex : t + "Flex", + typeNull : t + "Null" + } + } +} + +qx.ui.core.Widget.initLayoutProperties(); + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT TYPE AND VALUE STORAGE +--------------------------------------------------------------------------- +*/ + +qx.Proto._unitDetectionPixelPercentAutoFlex = function(propData, propValue) +{ + var r = qx.ui.core.Widget.layoutPropertyTypes[propData.name]; + + var s = r.dataType; + var p = r.dataParsed; + var v = r.dataValue; + + var s1 = r.typePixel; + var s2 = r.typePercent; + var s3 = r.typeAuto; + var s4 = r.typeFlex; + var s5 = r.typeNull; + + var wasPercent = this[s2]; + var wasAuto = this[s3]; + var wasFlex = this[s4]; + + switch(this[s] = this._evalUnitsPixelPercentAutoFlex(propValue)) + { + case qx.ui.core.Widget.TYPE_PIXEL: + this[s1] = true; + this[s2] = this[s3] = this[s4] = this[s5] = false; + this[p] = this[v] = Math.round(propValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + this[s2] = true; + this[s1] = this[s3] = this[s4] = this[s5] = false; + this[p] = parseFloat(propValue); + this[v] = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + this[s3] = true; + this[s1] = this[s2] = this[s4] = this[s5] = false; + this[p] = this[v] = null; + break; + + case qx.ui.core.Widget.TYPE_FLEX: + this[s4] = true; + this[s1] = this[s2] = this[s3] = this[s5] = false; + this[p] = parseFloat(propValue); + this[v] = null; + break; + + default: + this[s5] = true; + this[s1] = this[s2] = this[s3] = this[s4] = false; + this[p] = this[v] = null; + break; + } + + if (wasPercent != this[s2]) + { + switch(propData.name) + { + case "minWidth": + case "maxWidth": + case "width": + case "left": + case "right": + this._invalidateHasPercentX(); + break; + + case "maxHeight": + case "minHeight": + case "height": + case "top": + case "bottom": + this._invalidateHasPercentY(); + break; + } + } + + // No ELSE because you can also switch from percent to auto + if (wasAuto != this[s3]) + { + switch(propData.name) + { + case "minWidth": + case "maxWidth": + case "width": + this._invalidateHasAutoX(); + break; + + case "minHeight": + case "maxHeight": + case "height": + this._invalidateHasAutoY(); + break; + } + } + + // No ELSE because you can also switch from percent to auto + if (wasFlex != this[s4]) + { + switch(propData.name) + { + case "width": + this._invalidateHasFlexX(); + break; + + case "height": + this._invalidateHasFlexY(); + break; + } + } +} + +qx.Proto._unitDetectionPixelPercentAuto = function(propData, propValue) +{ + var r = qx.ui.core.Widget.layoutPropertyTypes[propData.name]; + + var s = r.dataType; + var p = r.dataParsed; + var v = r.dataValue; + + var s1 = r.typePixel; + var s2 = r.typePercent; + var s3 = r.typeAuto; + var s4 = r.typeNull; + + var wasPercent = this[s2]; + var wasAuto = this[s3]; + + switch(this[s] = this._evalUnitsPixelPercentAuto(propValue)) + { + case qx.ui.core.Widget.TYPE_PIXEL: + this[s1] = true; + this[s2] = this[s3] = this[s4] = false; + this[p] = this[v] = Math.round(propValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + this[s2] = true; + this[s1] = this[s3] = this[s4] = false; + this[p] = parseFloat(propValue); + this[v] = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + this[s3] = true; + this[s1] = this[s2] = this[s4] = false; + this[p] = this[v] = null; + break; + + default: + this[s4] = true; + this[s1] = this[s2] = this[s3] = false; + this[p] = this[v] = null; + break; + } + + if (wasPercent != this[s2]) + { + switch(propData.name) + { + case "minWidth": + case "maxWidth": + case "width": + case "left": + case "right": + this._invalidateHasPercentX(); + break; + + case "minHeight": + case "maxHeight": + case "height": + case "top": + case "bottom": + this._invalidateHasPercentY(); + break; + } + } + + // No ELSE because you can also switch from percent to auto + if (wasAuto != this[s3]) + { + switch(propData.name) + { + case "minWidth": + case "maxWidth": + case "width": + this._invalidateHasAutoX(); + break; + + case "minHeight": + case "maxHeight": + case "height": + this._invalidateHasAutoY(); + break; + } + } +} + +qx.Proto._unitDetectionPixelPercent = function(propData, propValue) +{ + var r = qx.ui.core.Widget.layoutPropertyTypes[propData.name]; + + var s = r.dataType; + var p = r.dataParsed; + var v = r.dataValue; + + var s1 = r.typePixel; + var s2 = r.typePercent; + var s3 = r.typeNull; + + var wasPercent = this[s2]; + + switch(this[s] = this._evalUnitsPixelPercent(propValue)) + { + case qx.ui.core.Widget.TYPE_PIXEL: + this[s1] = true; + this[s2] = this[s3] = false; + this[p] = this[v] = Math.round(propValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + this[s2] = true; + this[s1] = this[s3] = false; + this[p] = parseFloat(propValue); + this[v] = null; + break; + + default: + this[s3] = true; + this[s1] = this[s2] = false; + this[p] = this[v] = null; + break; + } + + if (wasPercent != this[s2]) + { + switch(propData.name) + { + case "minWidth": + case "maxWidth": + case "width": + case "left": + case "right": + this._invalidateHasPercentX(); + break; + + case "minHeight": + case "maxHeight": + case "height": + case "top": + case "bottom": + this._invalidateHasPercentY(); + break; + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + INLINE EVENTS +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.ui.core.Widget.inlineEventMap = + { + input : "onpropertychange", + select : "onselect", + scroll : "onscroll", + focus : "onfocus", + blur : "onblur" + } + + qx.Proto.enableInlineEvent = function(vEventName) + { + var vEventType = qx.ui.core.Widget.inlineEventMap[vEventName]; + + if (!this._inlineEvents) + { + this._inlineEvents = [vEventType]; + } + else + { + this._inlineEvents.push(vEventType); + } + + if (this._isCreated) { + this.getElement()[vEventType] = qx.ui.core.Widget.__oninlineevent; + } + } + + qx.Proto.disableInlineEvent = function(vEventName) + { + var vEventType = qx.ui.core.Widget.inlineEventMap[vEventName]; + + if (this._inlineEvents) { + qx.lang.Array.remove(this._inlineEvents, vEventType); + } + + if (this._isCreated) { + this.getElement()[vEventType] = null; + } + } + + qx.Proto._addInlineEvents = function(vElement) + { + if (this._inlineEvents) + { + for (var i=0, a=this._inlineEvents, l=a.length; i<l; i++) { + vElement[a[i]] = qx.ui.core.Widget.__oninlineevent; + } + } + } + + qx.Proto._removeInlineEvents = function(vElement) + { + if (this._inlineEvents) + { + for (var i=0, a=this._inlineEvents, l=a.length; i<l; i++) { + vElement[a[i]] = null; + } + } + } +} +else +{ + qx.Proto.enableInlineEvent = function(vEventName) + { + if (!this._inlineEvents) + { + this._inlineEvents = [vEventName]; + } + else + { + this._inlineEvents.push(vEventName); + } + + if (this._isCreated) { + this.getElement().addEventListener(vEventName, qx.ui.core.Widget.__oninlineevent, false); + } + } + + qx.Proto.disableInlineEvent = function(vEventName) + { + if (this._inlineEvents) { + qx.lang.Array.remove(this._inlineEvents, vEventName); + } + + if (this._isCreated) { + this.getElement().removeEventListener(vEventName, qx.ui.core.Widget.__oninlineevent, false); + } + } + + qx.Proto._addInlineEvents = function(vElement) + { + if (this._inlineEvents) + { + for (var i=0, a=this._inlineEvents, l=a.length; i<l; i++) { + vElement.addEventListener(a[i], qx.ui.core.Widget.__oninlineevent, false); + } + } + } + + qx.Proto._removeInlineEvents = function(vElement) + { + if (this._inlineEvents) + { + for (var i=0, a=this._inlineEvents, l=a.length; i<l; i++) { + vElement.removeEventListener(a[i], qx.ui.core.Widget.__oninlineevent, false); + } + } + } +} + +qx.ui.core.Widget.__oninlineevent = function(e) +{ + if (!e) { + e = window.event; + } + + if (this.qx_Widget) { + return this.qx_Widget._oninlineevent(e); + } +} + +qx.Proto._oninlineevent = function(e) +{ + if (qx.ui.core.Widget._inFlushGlobalQueues) { + return; + } + + // this.debug("Inlineevent: " + e.type); + + switch(e.type) + { + case "propertychange": + this._oninlineproperty(e); + break; + + case "input": + this._oninlineinput(e); + break; + + default: + this.createDispatchEvent(e.type); + } +} + +qx.Proto._oninlineinput = function(e) +{ + this.createDispatchDataEvent("input", this.getComputedValue()); + + // Block parents from this event + if (e.stopPropagation) { + e.stopPropagation(); + } + + e.returnValue = -1; +} + +qx.Proto._oninlineproperty = function(e) +{ + switch(e.propertyName) + { + case "value": + if (!this._inValueProperty) { + this._oninlineinput(e); + } + + break; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT +--------------------------------------------------------------------------- +*/ + +/*! + The widget which is at the top level, + which contains all others (normally a + instance of qx.ui.core.ClientDocument). +*/ +qx.Proto.getTopLevelWidget = function() { + return this._hasParent ? this.getParent().getTopLevelWidget() : null; +} + +/*! + Move myself to immediately before another child of the same parent. +*/ +qx.Proto.moveSelfBefore = function(vBefore) { + this.getParent().addBefore(this, vBefore); +} + +/*! + Move myself to immediately after another child of the same parent. +*/ +qx.Proto.moveSelfAfter = function(vAfter) { + this.getParent().addAfter(this, vAfter); +} + +/*! + Move myself to the head of the list: make me the first child. +*/ +qx.Proto.moveSelfToBegin = function() { + this.getParent().addAtBegin(this); +} + +/*! + Move myself to the end of the list: make me the last child. +*/ +qx.Proto.moveSelfToEnd = function() { + this.getParent().addAtEnd(this); +} + +/*! + Returns the previous sibling. +*/ +qx.Proto.getPreviousSibling = function() +{ + var p = this.getParent(); + + if(p == null) { + return null; + } + + var cs = p.getChildren(); + return cs[cs.indexOf(this) - 1]; +} + +/*! + Returns the next sibling. +*/ +qx.Proto.getNextSibling = function() +{ + var p = this.getParent(); + + if(p == null) { + return null; + } + + var cs = p.getChildren(); + return cs[cs.indexOf(this) + 1]; +} + +/*! + Returns the previous visible sibling. +*/ +qx.Proto.getPreviousVisibleSibling = function() +{ + if(!this._hasParent) { + return null; + } + + var vChildren = this.getParent().getVisibleChildren(); + return vChildren[vChildren.indexOf(this) - 1]; +} + +/*! + Returns the next visible sibling. +*/ +qx.Proto.getNextVisibleSibling = function() +{ + if(!this._hasParent) { + return null; + } + + var vChildren = this.getParent().getVisibleChildren(); + return vChildren[vChildren.indexOf(this) + 1]; +} + +qx.Proto.getPreviousActiveSibling = function(vIgnoreClasses) +{ + var vPrev = qx.ui.core.Widget.getActiveSiblingHelper(this, this.getParent(), -1, vIgnoreClasses, null); + return vPrev ? vPrev : this.getParent().getLastActiveChild(); +} + +qx.Proto.getNextActiveSibling = function(vIgnoreClasses) +{ + var vNext = qx.ui.core.Widget.getActiveSiblingHelper(this, this.getParent(), 1, vIgnoreClasses, null); + return vNext ? vNext : this.getParent().getFirstActiveChild(); +} + +qx.Proto.isFirstChild = function() { + return this._hasParent && this.getParent().getFirstChild() == this; +} + +qx.Proto.isLastChild = function() { + return this._hasParent && this.getParent().getLastChild() == this; +} + +qx.Proto.isFirstVisibleChild = function() { + return this._hasParent && this.getParent().getFirstVisibleChild() == this; +} + +qx.Proto.isLastVisibleChild = function() { + return this._hasParent && this.getParent().getLastVisibleChild() == this; +} + + + + + + + +/* +--------------------------------------------------------------------------- + ENABLED MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this.removeState("disabled"); + } + else + { + this.addState("disabled"); + + // Also reset some states to be sure a pressed/hovered button gets reset + this.removeState("over"); + + if (qx.OO.isAvailable("qx.ui.form.Button")) + { + this.removeState("abandoned"); + this.removeState("pressed"); + } + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + STATE HANDLING +--------------------------------------------------------------------------- +*/ + +/** + * Returns whether a state is set. + * + * @param vState {String} the state to check. + * @return {Boolean} whether the state is set. + */ +qx.Proto.hasState = function(vState) { + return this._states[vState] ? true : false; +} + +/** + * Sets a state. + * + * @param state {String} the state to set. + */ +qx.Proto.addState = function(vState) +{ + if (! this._states[vState]) { + this._states[vState] = true; + + if (this._hasParent) { + qx.ui.core.Widget.addToGlobalStateQueue(this); + } + } +} + +/** + * Clears a state. + * + * @param vState {String} the state to clear. + */ +qx.Proto.removeState = function(vState) +{ + if (this._states[vState]) { + delete this._states[vState]; + + if (this._hasParent) { + qx.ui.core.Widget.addToGlobalStateQueue(this); + } + } +} + +/** + * Sets or clears a state. + * + * @param state {String} the state to set or clear. + * @param enabled {Boolean} whether the state should be set. + * If false it will be cleared. + */ +qx.Proto.setState = function(state, enabled) { + if (enabled) { + this.addState(state); + } else { + this.removeState(state); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyInitialAppearance = function() +{ + var vAppearance = this.getAppearance(); + + if (vAppearance) + { + try + { + var r = qx.manager.object.AppearanceManager.getInstance().getAppearanceTheme().initialFrom(vAppearance); + if (r) { + this.set(r); + } + } + catch(ex) + { + this.error("Could not apply initial appearance", ex); + } + } +} + +qx.Proto._applyStateAppearance = function() +{ + // HACK: Is there a cleaner way to implement this? + // Maybe not use the appearance for this, but a simple property and event handler combination? + this._applyStateStyleFocus(this._states); + + var vAppearance = this.getAppearance(); + + if (vAppearance) + { + try + { + var r = qx.manager.object.AppearanceManager.getInstance().getAppearanceTheme().stateFrom(vAppearance, this._states); + if (r) { + this.set(r); + } + } + catch(ex) + { + this.error("Could not apply state appearance", ex); + } + } +} + +qx.Proto._resetAppearanceThemeWrapper = function(vNewAppearanceTheme, vOldAppearanceTheme) +{ + var vAppearance = this.getAppearance(); + + if (vAppearance) + { + var vOldAppearanceThemeObject = qx.manager.object.AppearanceManager.getInstance().getThemeById(vOldAppearanceTheme); + var vNewAppearanceThemeObject = qx.manager.object.AppearanceManager.getInstance().getThemeById(vNewAppearanceTheme); + + var vOldAppearanceProperties = qx.lang.Object.mergeWith(vOldAppearanceThemeObject.initialFrom(vAppearance), vOldAppearanceThemeObject.stateFrom(vAppearance, this._states)); + var vNewAppearanceProperties = qx.lang.Object.mergeWith(vNewAppearanceThemeObject.initialFrom(vAppearance), vNewAppearanceThemeObject.stateFrom(vAppearance, this._states)); + + for (var vProp in vOldAppearanceProperties) + { + if (!(vProp in vNewAppearanceProperties)) { + this[qx.OO.resetter[vProp]](); + } + } + + this.set(vNewAppearanceProperties); + } +} + +if (qx.core.Client.getInstance().isMshtml()) +{ + /* + Mshtml does not support outlines by css + */ + qx.Proto._applyStateStyleFocus = function(vStates) {} +} +else if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._applyStateStyleFocus = function(vStates) + { + if (vStates.focused) + { + if (!qx.event.handler.FocusHandler.mouseFocus && !this.getHideFocus()) + { + this.setStyleProperty("MozOutline", "1px dotted invert"); + } + } + else + { + this.removeStyleProperty("MozOutline"); + } + } +} +else +{ + qx.Proto._applyStateStyleFocus = function(vStates) + { + if (vStates.focused) + { + if (!qx.event.handler.FocusHandler.mouseFocus && !this.getHideFocus()) + { + this.setStyleProperty("outline", "1px dotted invert"); + } + } + else + { + this.setStyleProperty("outline", "0px none"); + } + } +} + +qx.Proto.addToStateQueue = function() { + qx.ui.core.Widget.addToGlobalStateQueue(this); +} + +qx.Proto.recursiveAddToStateQueue = function() { + this.addToStateQueue(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyAppearance = function(propValue, propOldValue, propData) +{ + var vAppearanceThemeObject = qx.manager.object.AppearanceManager.getInstance().getAppearanceTheme(); + + var vNewAppearanceProperties = vAppearanceThemeObject.initialFrom(propValue); + + if (this.isCreated()) { + qx.lang.Object.mergeWith(vNewAppearanceProperties, vAppearanceThemeObject.stateFrom(propValue, this._states)); + } + + if (propOldValue) + { + var vOldAppearanceProperties = vAppearanceThemeObject.initialFrom(propOldValue); + + if (this.isCreated()) { + qx.lang.Object.mergeWith(vOldAppearanceProperties, vAppearanceThemeObject.stateFrom(propOldValue, this._states)); + } + + for (var vProp in vOldAppearanceProperties) + { + if (!(vProp in vNewAppearanceProperties)) { + this[qx.OO.resetter[vProp]](); + } + } + } + + this.set(vNewAppearanceProperties); + + return true; +} + +qx.Proto._recursiveAppearanceThemeUpdate = function(vNewAppearanceTheme, vOldAppearanceTheme) +{ + try + { + this._resetAppearanceThemeWrapper(vNewAppearanceTheme, vOldAppearanceTheme); + } + catch(ex) + { + this.error("Failed to update appearance theme", ex); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT DATA +--------------------------------------------------------------------------- +*/ + +/*! + Placeholder method to add attributes and other content to element node +*/ +qx.Proto._applyElementData = function(el) {} + + + + + + +/* +--------------------------------------------------------------------------- + HTML PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.setHtmlProperty = function(propName, propValue) +{ + if (!this._htmlProperties) { + this._htmlProperties = {}; + } + + this._htmlProperties[propName] = propValue; + + if (this._isCreated && this.getElement()[propName] != propValue) { + this.getElement()[propName] = propValue; + } + + return true; +} + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.removeHtmlProperty = function(propName) + { + if (!this._htmlProperties) { + return; + } + + delete this._htmlProperties[propName]; + + if (this._isCreated) { + this.getElement().removeAttribute(propName); + } + + return true; + } +} +else +{ + qx.Proto.removeHtmlProperty = function(propName) + { + if (!this._htmlProperties) { + return; + } + + delete this._htmlProperties[propName]; + + if (this._isCreated) + { + this.getElement().removeAttribute(propName); + delete this.getElement()[propName]; + } + + return true; + } +} + +qx.Proto.getHtmlProperty = function(propName) +{ + if (!this._htmlProperties) { + return ""; + } + + return this._htmlProperties[propName] || ""; +} + +qx.Proto._applyHtmlProperties = function(vElement) +{ + var vProperties = this._htmlProperties; + + if (vProperties) + { + // this.debug("HTML-Properties: " + qx.lang.Object.getLength(vProperties)); + + var propName; + + for (propName in vProperties) { + vElement[propName] = vProperties[propName]; + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + HTML ATTRIBUTES +--------------------------------------------------------------------------- +*/ + +qx.Proto.setHtmlAttribute = function(propName, propValue) +{ + if (!this._htmlAttributes) { + this._htmlAttributes = {}; + } + + this._htmlAttributes[propName] = propValue; + + if (this._isCreated) { + this.getElement().setAttribute(propName, propValue); + } + + return true; +} + +qx.Proto.removeHtmlAttribute = function(propName) +{ + if (!this._htmlAttributes) { + return; + } + + delete this._htmlAttributes[propName]; + + if (this._isCreated) { + this.getElement().removeAttribute(propName); + } + + return true; +} + +qx.Proto.getHtmlAttribute = function(propName) +{ + if (!this._htmlAttributes) { + return ""; + } + + return this._htmlAttributes[propName] || ""; +} + +qx.Proto._applyHtmlAttributes = function(vElement) +{ + var vAttributes = this._htmlAttributes; + + if (vAttributes) + { + // this.debug("HTML-Attributes: " + qx.lang.Object.getLength(vAttributes)); + + var propName; + + for (propName in vAttributes) { + vElement.setAttribute(propName, vAttributes[propName]); + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + STYLE PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getStyleProperty = function(propName) { + return this._styleProperties[propName] || ""; +} + +qx.Proto.setStyleProperty = function(propName, propValue) +{ + this._styleProperties[propName] = propValue; + + if (this._isCreated) + { + /* + The zIndex and filter properties should always be + applied on the "real" element node. + */ + switch(propName) + { + case "zIndex": + case "filter": + case "display": + case "visibility": + var vElement = this.getElement(); + break; + + default: + var vElement = this._getTargetNode(); + } + + if (vElement) { + vElement.style[propName] = propValue; + } + } + + return true; +} + +qx.Proto.removeStyleProperty = function(propName) +{ + delete this._styleProperties[propName]; + + if (this._isCreated) + { + /* + The zIndex and filter properties should always be + applied on the "real" element node. + */ + switch(propName) + { + case "zIndex": + case "filter": + case "display": + case "visibility": + var vElement = this.getElement(); + break; + + default: + var vElement = this._getTargetNode(); + } + + if (vElement) { + vElement.style[propName] = ""; + } + } + + return true; +} + +qx.Proto._applyStyleProperties = function(vElement) +{ + var vProperties = this._styleProperties; + var propName; + + var vBaseElement = vElement; + var vTargetElement = this._getTargetNode(); + + for (propName in vProperties) + { + /* + The zIndex and filter properties should always be + applied on the "real" element node. + */ + switch(propName) + { + case "zIndex": + case "filter": + vElement = vBaseElement; + break; + + default: + vElement = vTargetElement; + } + + var value = vProperties[propName]; + vElement.style[propName] = (value == null) ? "" : value; + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.isFocusable = function() { + return this.isEnabled() && this.isSeeable() && this.getTabIndex() >= 0; +} + +qx.Proto.isFocusRoot = function() { + return false; +} + +qx.Proto.getFocusRoot = function() +{ + if(this._hasParent) { + return this.getParent().getFocusRoot(); + } + + return null; +} + +qx.Proto.getActiveChild = function() +{ + var vRoot = this.getFocusRoot(); + if (vRoot) { + return vRoot.getActiveChild(); + } + + return null; +} + +qx.Proto._ontabfocus = qx.lang.Function.returnTrue; + +qx.Proto._modifyFocused = function(propValue, propOldValue, propData) +{ + if (!this.isCreated()) { + return true; + } + + var vFocusRoot = this.getFocusRoot(); + + // this.debug("Focused: " + propValue); + + if (vFocusRoot) + { + // may be undefined if this widget has been removed + if (propValue) + { + vFocusRoot.setFocusedChild(this); + this._visualizeFocus(); + } + else + { + if (vFocusRoot.getFocusedChild() == this) { + vFocusRoot.setFocusedChild(null); + } + + this._visualizeBlur(); + } + } + + return true; +} + +qx.Proto._visualizeBlur = function() +{ + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (this.getEnableElementFocus() && (!this.getFocusRoot().getFocusedChild() || (this.getFocusRoot().getFocusedChild() && this.getFocusRoot().getFocusedChild().getEnableElementFocus()))) + { + try { + this.getElement().blur(); + } catch(ex) {}; + } + + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() +{ + //this.info("_visualizeFocus: " + qx.event.handler.FocusHandler.mouseFocus); + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) + { + try { + this.getElement().focus(); + } catch(ex) {}; + } + + this.addState("focused"); + return true; +} + +qx.Proto.focus = function() +{ + delete qx.event.handler.FocusHandler.mouseFocus; + this.setFocused(true); +} + +qx.Proto.blur = function() +{ + delete qx.event.handler.FocusHandler.mouseFocus; + this.setFocused(false); +} + + + + +/* +--------------------------------------------------------------------------- + CAPTURE +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCapture = function(propValue, propOldValue, propData) +{ + var vMgr = qx.event.handler.EventHandler.getInstance(); + + if (propOldValue) + { + vMgr.setCaptureWidget(null); + } + else if (propValue) + { + vMgr.setCaptureWidget(this); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ZINDEX +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyZIndex = function(propValue, propOldValue, propData) { + return this.setStyleProperty(propData.name, propValue); +} + + + + + + + +/* +--------------------------------------------------------------------------- + TAB INDEX +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + if (propValue < 0 || !this.getEnabled()) { + this.setHtmlProperty("unselectable", + "on"); + } else { + this.removeHtmlProperty("unselectable"); + } + + this.setHtmlProperty("tabIndex", + propValue < 0 ? -1 : 1); + + return true; + } +} +else if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + this.setStyleProperty("MozUserFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + // be forward compatible (CSS 3 Draft) + this.setStyleProperty("userFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + return true; + } +} +else +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + // CSS 3 Draft + this.setStyleProperty("userFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + // IE Backward Compatible + if (propValue < 0 || !this.getEnabled()) { + this.setHtmlProperty("unselectable", + "on"); + } else { + this.removeHtmlProperty("unselectable"); + } + + this.setHtmlProperty("tabIndex", + propValue < 0 ? -1 : 1); + + return true; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CSS CLASS NAME +--------------------------------------------------------------------------- +*/ + +qx.Proto.setCssClassName = function(propValue) { + this.setHtmlProperty("className", propValue); +} + +qx.Proto.getCssClassName = function() { + return this.getHtmlProperty("className"); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET FROM POINT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWidgetFromPoint = function(x, y) +{ + var ret = this.getWidgetFromPointHelper(x, y); + return ret && ret != this ? ret : null; +} + +qx.Proto.getWidgetFromPointHelper = function(x, y) { + return this; +} + + + + + + +/* +--------------------------------------------------------------------------- + CAN SELECT +--------------------------------------------------------------------------- +*/ + +if(qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + return this.removeHtmlProperty("unselectable"); + } + else + { + return this.setHtmlProperty("unselectable", "on"); + } + } +} +else if(qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + this.removeStyleProperty("MozUserSelect"); + } + else + { + this.setStyleProperty("MozUserSelect", "none"); + } + + return true; + }; +} +else if (qx.core.Client.getInstance().isOpera()) +{ + // No known method available for this client + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) { + return true; + } +} +else if (qx.core.Client.getInstance().isKhtml() || qx.core.Client.getInstance().isWebkit()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + // Be forward compatible and use both userSelect and KhtmlUserSelect + if (propValue) + { + this.removeStyleProperty("KhtmlUserSelect"); + } + else + { + this.setStyleProperty("KhtmlUserSelect", "none"); + } + + return true; + }; +} +else +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + return this.removeStyleProperty("userSelect"); + } + else + { + this.setStyleProperty("userSelect", "none"); + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + OPACITY +--------------------------------------------------------------------------- +*/ + +/*! +Sets the opacity for the widget. Any child widget inside the widget will also +become (semi-)transparent. The value should be a number between 0 and 1 +inclusive, where 1 means totally opaque and 0 invisible. +*/ +if(qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyOpacity = function(propValue, propOldValue, propData) + { + if(propValue == null || propValue >= 1 || propValue < 0) + { + this.removeStyleProperty("filter"); + } + else + { + this.setStyleProperty("filter", + ("Alpha(Opacity=" + + Math.round(propValue * 100) + + ")")); + } + + return true; + } +} +else +{ + qx.Proto._modifyOpacity = function(propValue, propOldValue, propData) + { + if(propValue == null || propValue > 1) + { + if (qx.core.Client.getInstance().isGecko()) + { + this.removeStyleProperty("MozOpacity"); + } + else if (qx.core.Client.getInstance().isKhtml()) + { + this.removeStyleProperty("KhtmlOpacity"); + } + + this.removeStyleProperty("opacity"); + } + else + { + propValue = qx.lang.Number.limit(propValue, 0, 1); + + // should we omit gecko's flickering here + // and limit the max value to 0.99? + + if (qx.core.Client.getInstance().isGecko()) + { + this.setStyleProperty("MozOpacity", propValue); + } + else if (qx.core.Client.getInstance().isKhtml()) + { + this.setStyleProperty("KhtmlOpacity", propValue); + } + + this.setStyleProperty("opacity", propValue); + } + + return true; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CURSOR +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCursor = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (propValue == "pointer" && + qx.core.Client.getInstance().isMshtml()) { + this.setStyleProperty("cursor", + "hand"); + } else { + this.setStyleProperty("cursor", + propValue); + } + } + else + { + this.removeStyleProperty("cursor"); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + BACKGROUND IMAGE +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBackgroundImage = function(propValue, propOldValue, propData) +{ + return qx.util.Validation.isValidString(propValue) ? + this.setStyleProperty("backgroundImage", + "url(" + + qx.manager.object.AliasManager.getInstance().resolvePath(propValue) + + ")") : + this.removeStyleProperty("backgroundImage"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CLIPPING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyClip = function(propValue, propOldValue, propData) { + return this._compileClipString(); +} + +qx.Proto._compileClipString = function() +{ + var vLeft = this.getClipLeft(); + var vTop = this.getClipTop(); + var vWidth = this.getClipWidth(); + var vHeight = this.getClipHeight(); + + var vRight, vBottom; + + if(vLeft == null) + { + vRight = (vWidth == null + ? "auto" + : vWidth + "px"); + vLeft = "auto"; + } + else + { + vRight = (vWidth == null + ? "auto" + : vLeft + vWidth + "px"); + vLeft = vLeft + "px"; + } + + if(vTop == null) + { + vBottom = (vHeight == null + ? "auto" + : vHeight + "px"); + vTop = "auto"; + } + else + { + vBottom = (vHeight == null + ? "auto" + : vTop + vHeight + "px"); + vTop = vTop + "px"; + } + + return this.setStyleProperty("clip", + ("rect(" + + vTop + + "," + + vRight + + "," + + vBottom + + "," + + vLeft + + ")")); +} + + + + + + +/* +--------------------------------------------------------------------------- + OVERFLOW +--------------------------------------------------------------------------- +*/ + +/* + This will measure the typical native scrollbar size in the environment +*/ +qx.ui.core.Widget.initOverflow = function() +{ + if (qx.ui.core.Widget.initOverflowDone) { + return; + } + + var t = document.createElement("div"); + var s = t.style; + + s.height = s.width = "100px"; + s.overflow = "scroll"; + + document.body.appendChild(t); + + var c = qx.html.Dimension.getScrollBarSizeRight(t); + if (c) { + qx.ui.core.Widget.SCROLLBAR_SIZE = c; + } + + document.body.removeChild(t); + + qx.ui.core.Widget.initOverflowDone = true; +} + +if (qx.core.Client.getInstance().isGecko()) +{ + qx.Proto._modifyOverflow = function(propValue, propOldValue, propData) + { + var pv = propValue; + var pn = propData.name; + + switch(pv) + { + case "hidden": + pv = "-moz-scrollbars-none"; + break; + + case "scrollX": + pv = "-moz-scrollbars-horizontal"; + break; + + case "scrollY": + pv = "-moz-scrollbars-vertical"; + break; + } + + return this._applyOverflow(pn, pv, propValue, propOldValue); + } +} + +// Mshtml conforms here to CSS3 Spec. Eventually there will be multiple +// browsers which support these new overflowX overflowY properties. +else if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyOverflow = function(propValue, propOldValue, propData) + { + var pv = propValue; + var pn = propData.name; + + switch(pv) + { + case "scrollX": + pn = "overflowX"; + pv = "scroll"; + break; + + case "scrollY": + pn = "overflowY"; + pv = "scroll"; + break; + } + + // Clear up concurrenting rules + var a = [ "overflow", + "overflowX", + "overflowY" ]; + for (var i=0; i<a.length; i++) + { + if (a[i]!=pn) { + this.removeStyleProperty(a[i]); + } + } + + return this._applyOverflow(pn, pv, propValue, propOldValue); + } +} + +// Opera/Khtml Mode... +// hopefully somewhat of this is supported in the near future. + +// overflow-x and overflow-y are also not supported by Opera 9.0 Beta1 +// and also not if we switch to IE emulation mode +else +{ + qx.Proto._modifyOverflow = function(propValue, propOldValue, propData) + { + var pv = propValue; + var pn = propData.name; + + switch(pv) + { + case "scrollX": + case "scrollY": + pv = "scroll"; + break; + } + + return this._applyOverflow(pn, pv, propValue, propOldValue); + } +} + +qx.Proto._applyOverflow = function(pn, pv, propValue, propOldValue) +{ + // Apply Style + this.setStyleProperty(pn, pv); + + // Invalidate Frame + this._invalidateFrameWidth(); + this._invalidateFrameHeight(); + + return true; +} + +qx.Proto.getOverflowX = function() +{ + var vOverflow = this.getOverflow(); + return vOverflow == "scrollY" ? "hidden" : vOverflow; +} + +qx.Proto.getOverflowY = function() +{ + var vOverflow = this.getOverflow(); + return vOverflow == "scrollX" ? "hidden" : vOverflow; +} + + + + + + +/* +--------------------------------------------------------------------------- + HIDE FOCUS +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyHideFocus = function(propValue, propOldValue, propData) + { + this.setHtmlProperty(propData.name, propValue); + return true; + } +} + +// Need no implementation for others then mshtml, because +// all these browsers support css outlines and do not +// have an attribute "hideFocus" as IE. + + + + + + +/* +--------------------------------------------------------------------------- + COLORS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBackgroundColor = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) + { + this._applyBackgroundColor(propValue.getStyle()); + propValue.add(this); + } + else + { + this._resetBackgroundColor(); + } + + return true; +} + +qx.Proto._modifyColor = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) + { + this._applyColor(propValue.getStyle()); + propValue.add(this); + } + else + { + this._resetColor(); + } + + return true; +} + +qx.Proto._updateColors = function(vColor, vNewValue) +{ + if (this.getColor() == vColor) { + this._applyColor(vNewValue); + } + + if (this.getBackgroundColor() == vColor) { + this._applyBackgroundColor(vNewValue); + } +} + +qx.Proto._applyColor = function(vNewValue) { + this.setStyleProperty("color", vNewValue); +} + +qx.Proto._applyBackgroundColor = function(vNewValue) { + this.setStyleProperty("backgroundColor", vNewValue); +} + +qx.Proto._resetColor = function(vNewValue) { + this.removeStyleProperty("color"); +} + +qx.Proto._resetBackgroundColor = function() { + this.removeStyleProperty("backgroundColor"); +} + + + + + + +/* +--------------------------------------------------------------------------- + BORDER +--------------------------------------------------------------------------- +*/ + +qx.Proto._cachedBorderTop = 0; +qx.Proto._cachedBorderRight = 0; +qx.Proto._cachedBorderBottom = 0; +qx.Proto._cachedBorderLeft = 0; + +qx.Proto._modifyBorder = function(propValue, propOldValue, propData) +{ + var vOldTop = this._cachedBorderTop; + var vOldRight = this._cachedBorderRight; + var vOldBottom = this._cachedBorderBottom; + var vOldLeft = this._cachedBorderLeft; + + if (propOldValue) { + propOldValue.removeListenerWidget(this); + } + + if (propValue) + { + propValue.addListenerWidget(this); + + this._cachedBorderTop = propValue.getTopWidth(); + this._cachedBorderRight = propValue.getRightWidth(); + this._cachedBorderBottom = propValue.getBottomWidth(); + this._cachedBorderLeft = propValue.getLeftWidth(); + } + else + { + this._cachedBorderTop = this._cachedBorderRight = this._cachedBorderBottom = this._cachedBorderLeft = 0; + } + + + + // ---------------- + // X-AXIS + // ---------------- + if ((vOldLeft + vOldRight) != (this._cachedBorderLeft + this._cachedBorderRight)) { + this._invalidateFrameWidth(); + } + + this.addToQueue("borderX"); + + + + // ---------------- + // Y-AXIS + // ---------------- + if ((vOldTop + vOldBottom) != (this._cachedBorderTop + this._cachedBorderBottom)) { + this._invalidateFrameHeight(); + } + + this.addToQueue("borderY"); + + + + + + return true; +} + +qx.Proto.getCachedBorderTop = function() { + return this._cachedBorderTop; +} + +qx.Proto.getCachedBorderRight = function() { + return this._cachedBorderRight; +} + +qx.Proto.getCachedBorderBottom = function() { + return this._cachedBorderBottom; +} + +qx.Proto.getCachedBorderLeft = function() { + return this._cachedBorderLeft; +} + +qx.Proto._updateBorder = function(vEdge) +{ + // Small hack, remove later: TODO + // ?? Anybody have an idea about this TODO? + var vBorder = this.getBorder(); + var vEdgeUp = qx.lang.String.toFirstUp(vEdge); + + var vNewValue = vBorder["get" + vEdgeUp + "Width"](); + var vCacheName = "_cachedBorder" + vEdgeUp; + var vWidthChanged = this[vCacheName] != vNewValue; + + this[vCacheName] = vNewValue; + + switch(vEdge) + { + case "left": + case "right": + if (vWidthChanged) { + this.addToJobQueue("borderWidthX"); + } + + this.addToJobQueue("borderX"); + break; + + case "top": + case "bottom": + if (vWidthChanged) { + this.addToJobQueue("borderWidthY"); + } + + this.addToJobQueue("borderY"); + break; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + PADDING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyPaddingX = function(propValue, propOldValue, propData) +{ + this._invalidateFrameWidth(); + return true; +} + +qx.Proto._modifyPaddingY = function(propValue, propOldValue, propData) +{ + this._invalidateFrameHeight(); + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +qx.Proto._clonePropertyIgnoreList = "parent,element,visible"; + + +/*! +Returns a cloned copy of the current instance of qx.ui.core.Widget. + +#param cloneRecursive[Boolean]: Should the widget cloned recursive (including all childs)? +#param customPropertyList[Array]: Optional (reduced) list of properties to copy through +*/ + +// TODO: Needs modification to work with new codebase +qx.Proto.clone = function(cloneRecursive, customPropertyList) +{ + var cloneInstance = new this.constructor; + + var propertyName; + var propertyList = []; + var propertyIngoreList = this._clonePropertyIgnoreList.split(","); + + // Build new filtered property list + var sourcePropertyList = customPropertyList != null ? customPropertyList : this._properties.split(","); + var sourcePropertyListLength = sourcePropertyList.length-1; + do { + propertyName = sourcePropertyList[sourcePropertyListLength]; + if (!qx.lang.Array.contains(propertyIngoreList, propertyName)) { + propertyList.push(propertyName); + } + } + while(sourcePropertyListLength--); + + // Apply properties to new clone instance + propertyListLength = propertyList.length-1; + do { + propertyName = qx.lang.String.toFirstUp(propertyList[propertyListLength]); + cloneInstance["set" + propertyName](this["get" + propertyName]()); + } + while(propertyListLength--); + + // post apply parent info + if (qx.lang.Array.contains(sourcePropertyList, "parent")) + { + var myParent = this.getParent(); + if (myParent) { + cloneInstance.setParent(myParent); + } + } + + // clone recursion + if (cloneRecursive) { + this._cloneRecursive(cloneInstance); + } + + return cloneInstance; +} + +qx.Proto._cloneRecursive = function(cloneInstance) {} + + + + + + +/* +--------------------------------------------------------------------------- + COMMAND INTERFACE +--------------------------------------------------------------------------- +*/ + +qx.Proto.execute = function() +{ + var vCommand = this.getCommand(); + if (vCommand) { + vCommand.execute(this); + } + + this.createDispatchEvent("execute"); +} + + + + + + +/* +--------------------------------------------------------------------------- + NODE ALIASES +--------------------------------------------------------------------------- +*/ + +qx.Proto._visualPropertyCheck = function() +{ + if (!this.isCreated()) { + throw new Error("Element must be created previously!"); + } +} + +qx.Proto.setScrollLeft = function(nScrollLeft) +{ + this._visualPropertyCheck(); + this._getTargetNode().scrollLeft = nScrollLeft; +} + +qx.Proto.setScrollTop = function(nScrollTop) +{ + this._visualPropertyCheck(); + this._getTargetNode().scrollTop = nScrollTop; +} + +qx.Proto.getOffsetLeft = function() +{ + this._visualPropertyCheck(); + return qx.html.Offset.getLeft(this.getElement()); +} + +qx.Proto.getOffsetTop = function() +{ + this._visualPropertyCheck(); + return qx.html.Offset.getTop(this.getElement()); +} + +qx.Proto.getScrollLeft = function() +{ + this._visualPropertyCheck(); + return this._getTargetNode().scrollLeft; +} + +qx.Proto.getScrollTop = function() +{ + this._visualPropertyCheck(); + return this._getTargetNode().scrollTop; +} + +qx.Proto.getClientWidth = function() +{ + this._visualPropertyCheck(); + return this._getTargetNode().clientWidth; +} + +qx.Proto.getClientHeight = function() +{ + this._visualPropertyCheck(); + return this._getTargetNode().clientHeight; +} + +qx.Proto.getOffsetWidth = function() +{ + this._visualPropertyCheck(); + return this.getElement().offsetWidth; +} + +qx.Proto.getOffsetHeight = function() +{ + this._visualPropertyCheck(); + return this.getElement().offsetHeight; +} + +qx.Proto.getScrollWidth = function() +{ + this._visualPropertyCheck(); + return this.getElement().scrollWidth; +} + +qx.Proto.getScrollHeight = function() +{ + this._visualPropertyCheck(); + return this.getElement().scrollHeight; +} + + + + + +/* +--------------------------------------------------------------------------- + SCROLL INTO VIEW +--------------------------------------------------------------------------- +*/ + +qx.Proto.scrollIntoView = function(vAlignTopLeft) +{ + this.scrollIntoViewX(vAlignTopLeft); + this.scrollIntoViewY(vAlignTopLeft); +} + +qx.Proto.scrollIntoViewX = function(vAlignLeft) +{ + if (!this._isCreated || !this._isDisplayable) { + return false; + } + + return qx.html.ScrollIntoView.scrollX(this.getElement(), vAlignLeft); +} + +qx.Proto.scrollIntoViewY = function(vAlignTop) +{ + if (!this._isCreated || !this._isDisplayable) { + return false; + } + + return qx.html.ScrollIntoView.scrollY(this.getElement(), vAlignTop); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DRAG AND DROP SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.supportsDrop = function(vDragCache) { + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + FADING PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The amount of steps for the fade. + */ +qx.OO.addProperty({ name : 'fadeSteps', type : "number", allowNull : false, defaultValue : 10}); +/*! + The duration for the fade. + */ +qx.OO.addProperty({ name : 'fadeTime', type : "number", allowNull : false, defaultValue : 400}); +/*! + The time between the fade steps. + */ +qx.OO.addProperty({ name : 'fadeInterval', type : "number", allowNull : false, defaultValue : 40}); +/*! + The current state of a fade in progress. + */ +qx.OO.addProperty({ name : 'fadeCounter', type : "number", allowNull : false, defaultValue : 0}); +/*! + The amount of oppacity changed on each fade step. + */ +qx.OO.addProperty({ name : 'fadeUnit', type : "number", allowNull : false, defaultValue : 10}); +/*! + The maximum opacity for a fadeIn. + */ +qx.OO.addProperty({ name : 'fadeMax', type : "number", allowNull : false, defaultValue : 100}); + + + + + + +/* +--------------------------------------------------------------------------- + FADING SUPPORT +--------------------------------------------------------------------------- +*/ +qx.ui.core.Widget.FADE_IN = 'FADE_IN'; +qx.ui.core.Widget.FADE_OUT = 'FADE_OUT'; +qx.ui.core.Widget.FADE_FINISHED = 'FADE_FINISHED'; + + +qx.Proto.fadeIn = function(vSteps, vTime) { + if(vSteps) this.setFadeSteps(vSteps); + if(vTime) this.setFadeTime(vTime); + this._fadeMode = qx.ui.core.Widget.FADE_IN; + var timer = this.getFadeTimer(); + timer.addEventListener("interval", this._onInterval, this); + timer.start(); +} + +qx.Proto.fadeOut = function(vSteps, vTime) { + if(vSteps) this.setFadeSteps(vSteps); + if(vTime) this.setFadeTime(vTime); + this._fadeMode = qx.ui.core.Widget.FADE_OUT; + var timer = this.getFadeTimer(); + timer.addEventListener("interval", this._onInterval, this); + timer.start(); +}; + +qx.Proto.getFadeTimer = function() { + if(this._fadeTimer){ + this._fadeTimer.setInterval(this.getFadeInterval()); + } else { + this._fadeTimer = new qx.client.Timer(this.getFadeInterval()); + }; + return this._fadeTimer; +}; + +qx.Proto.resetFader = function() { + this.setFadeCounter(0); + if(this.getFadeTimer()) { + this._fadeTimer.stop(); + this._fadeTimer.dispose(); + }; + this._fadeTimer.dispose(); + this._fadeTimer = null; +}; + +qx.Proto._onInterval = function(e) { + this.getFadeTimer().stop(); + var counter = this.getFadeCounter(); + switch (this._fadeMode){ + case qx.ui.core.Widget.FADE_IN: + this.setFadeCounter(++counter); + if(counter <= this.getFadeSteps()){ + this.setOpacity(this._computeFadeOpacity()); + this.getFadeTimer().restart(); + } else if(this.hasEventListeners(qx.ui.core.Widget.FADE_FINISHED)) { + this.createDispatchDataEvent(qx.ui.core.Widget.FADE_FINISHED, qx.ui.core.Widget.FADE_IN); + }; + break; + + case qx.ui.core.Widget.FADE_OUT: + this.setFadeCounter(--counter); + if(counter >= 0){ + this.setOpacity(this._computeFadeOpacity()); + this.getFadeTimer().restart(); + } else if(this.hasEventListeners(qx.ui.core.Widget.FADE_FINISHED)) { + this.createDispatchDataEvent(qx.ui.core.Widget.FADE_FINISHED, qx.ui.core.Widget.FADE_OUT); + }; + break; + }; + qx.ui.core.Widget.flushGlobalQueues(); +}; + +qx.Proto._modifyFadeSteps = function(propValue, propOldValue, propData) { + if(propValue < 1) return; + this.setFadeInterval(parseInt(this.getFadeTime() / propValue)); + this.setFadeUnit(Math.round(this.getFadeMax()/propValue)); + return true; +}; + +qx.Proto._modifyFadeTime = function(propValue, propOldValue, propData) { + if(propValue < 1) return; + this.setFadeInterval(parseInt(propValue / this.getFadeSteps())); + return true; +}; + +qx.Proto._modifyFadeUnit = function(propValue, propOldValue, propData) { + this.setFadeSteps(Math.round(this.getFadeMax()/propValue)); + return true; +}; + +qx.Proto._modifyFadeMax = function(propValue, propOldValue, propData) { + this.setFadeUnit(Math.round(propValue / this.getFadeSteps())); + return true; +}; + +qx.Proto._computeFadeOpacity = function() { + var op = this.getFadeUnit() * this.getFadeCounter() / 100; + return(op); +}; + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + var vElement = this.getElement(); + + if (vElement) + { + this._removeInlineEvents(vElement); + + delete this._isCreated; + + vElement.qx_Widget = null; + + this._element = null; + this._style = null; + } + + this._inlineEvents = null; + this._element = null; + this._style = null; + this._borderElement = null; + this._borderStyle = null; + this._oldParent = null; + + // should be enough to remove the hashTables + delete this._styleProperties; + delete this._htmlProperties; + delete this._htmlAttributes; + delete this._states; + + // remove queue content + for (var i in this._jobQueue) { + delete this._jobQueue[i]; + } + delete this._jobQueue; + + for (var i in this._layoutChanges) { + delete this._layoutChanges[i]; + } + delete this._layoutChanges; + + // dispose the fader + if(this._fadeTimer){ + this._fadeTimer.dispose(); + this._fadeTimer = null; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js new file mode 100644 index 0000000000..4e8f3a4ef0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js @@ -0,0 +1,529 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + ________________________________________________________________________ + + This class contains code based on the following work: + + SWFObject: Javascript Flash Player detection and embed script + http://blog.deconcept.com/swfobject/ + Version: 1.4.4 + + Copyright: + 2006 Geoff Stearns + + License: + MIT: http://www.opensource.org/licenses/mit-license.php + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + Authors: + * Geoff Stearns (geoff@deconcept.com) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Flash Player detection and embed. + * + * This class contains code based on the following work:<br/> + * SWFObject: Javascript Flash Player detection and embed script<br/> + * http://blog.deconcept.com/swfobject/</br> + * Version: 1.4.4 + * + * License:<br/> + * MIT: http://www.opensource.org/licenses/mit-license.php<br/> + * For more info, please see the corresponding source file. + * + * @param vSource {String} Url of the SWF file to embed + * @param vVersion {String} Flash version of the SWF file + */ +qx.OO.defineClass("qx.ui.embed.Flash", qx.ui.basic.Terminator, +function(vSource, vVersion) +{ + qx.ui.basic.Terminator.call(this); + + // Use background handling of qx.ui.core.Widget instead + this._params = {}; + this._variables = {}; + + if(vSource != null) { + this.setSource(vSource); + } + + this.setVersion(vVersion != null ? vVersion : qx.ui.embed.Flash.MINREQUIRED); +}); + +qx.OO.addProperty({ name : "source", type : "string" }); +qx.OO.addProperty({ name : "version" }); + +qx.OO.addProperty({ name : "enableExpressInstall", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "enableDetection", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "redirectUrl", type : "string" }); + +qx.OO.addProperty({ name : "quality", type : "string", impl : "param", defaultValue : "high", possibleValues : [ "low", "autolow", "autohigh", "medium", "high", "best" ] }); +qx.OO.addProperty({ name : "scale", type : "string", impl : "param", defaultValue : "showall", possibleValues : [ "showall", "noborder", "excactfit", "noscale" ] }); +qx.OO.addProperty({ name : "wmode", type : "string", impl : "param", defaultValue : "", possibleValues : [ "window", "opaque", "transparent" ] }); +qx.OO.addProperty({ name : "play", type : "boolean", impl : "param", defaultValue : true }); +qx.OO.addProperty({ name : "loop", type : "boolean", impl : "param", defaultValue : true }); +qx.OO.addProperty({ name : "menu", type : "boolean", impl : "param", defaultValue : true }); + +qx.ui.embed.Flash.EXPRESSINSTALL = [6,0,65]; +qx.ui.embed.Flash.MINREQUIRED = "1"; +qx.ui.embed.Flash.PLAYERVERSION = null; +qx.ui.embed.Flash.PLUGINKEY = "Shockwave Flash"; +qx.ui.embed.Flash.ACTIVEXKEY = "ShockwaveFlash.ShockwaveFlash"; + + + + + +/* +--------------------------------------------------------------------------- + PLAYER VERSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.ui.embed.Flash.getPlayerVersion = function() +{ + if (qx.ui.embed.Flash.PLAYERVERSION != null) { + return qx.ui.embed.Flash.PLAYERVERSION; + } + + var vPlayerVersion = new qx.type.Version(0,0,0); + + if(navigator.plugins && navigator.mimeTypes.length) + { + var x = navigator.plugins[qx.ui.embed.Flash.PLUGINKEY]; + + if(x && x.description) { + vPlayerVersion = new qx.type.Version(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".")); + } + } + else if (window.ActiveXObject) + { + // do minor version lookup in IE, but avoid fp6 crashing issues + // see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/ + try { + var axo = new ActiveXObject(qx.ui.embed.Flash.ACTIVEXKEY + ".7"); + } + catch(e) + { + try { + var axo = new ActiveXObject(qx.ui.embed.Flash.ACTIVEXKEY + ".6"); + vPlayerVersion = new qx.type.Version([6,0,21]); + axo.AllowScriptAccess = "always"; // throws if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code) + } + catch(e) + { + if (vPlayerVersion.major == 6) { + return vPlayerVersion; + } + } + + try { + axo = new ActiveXObject(qx.ui.embed.Flash.ACTIVEXKEY); + } catch(e) {} + } + + if (axo != null) { + vPlayerVersion = new qx.type.Version(axo.GetVariable("$version").split(" ")[1].split(",")); + } + } + + return qx.ui.embed.Flash.PLAYERVERSION = vPlayerVersion; +}; + + + + + + +/* +--------------------------------------------------------------------------- + BASICS +--------------------------------------------------------------------------- +*/ + +qx.Proto._version = null; +qx.Proto._source = ""; + +qx.Proto._applyElementData = function(el) +{ + qx.ui.basic.Terminator.prototype._applyElementData.call(this, el); + + // Check for ExpressInstall + this._expressInstall = false; + + if (this.getEnableExpressInstall()) + { + // check to see if we need to do an express install + var expressInstallReqVer = new qx.type.Version(qx.ui.embed.Flash.EXPRESSINSTALL); + var installedVer = qx.ui.embed.Flash.getPlayerVersion(); + + if (installedVer.versionIsValid(expressInstallReqVer) && !installedVer.versionIsValid(this._version)) { + this._expressInstall = true; + } + } + + // this.debug("ExpressInstall Enabled: " + this._expressInstall); + + // Apply HTML + if(!this.getEnableDetection() || this._expressInstall || qx.ui.embed.Flash.getPlayerVersion().versionIsValid(this._version)) + { + el.innerHTML = this.generateHTML(); + } + else + { + var redir = this.getRedirectUrl(); + + if(redir != "") { + document.location.replace(redir); + } + } +}; + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySource = function(propValue, propOldValue, propName) +{ + this._source = qx.util.Validation.isValidString(propValue) ? qx.manager.object.AliasManager.getInstance().resolvePath(propValue) : ""; + return true; +}; + +qx.Proto._modifyVersion = function(propValue, propOldValue, propData) +{ + if (this._version) + { + this._version.dispose(); + this._version = null; + } + + if (qx.util.Validation.isValidString(propValue)) { + this._version = new qx.type.Version(propValue); + } + + return true; +}; + +qx.Proto._modifyParam = function(propValue, propOldValue, propData) +{ + this.setParam(propData.name, propValue.toString()); + return true; +}; + + + + + +/* +--------------------------------------------------------------------------- + OVERWRITE BACKGROUND COLOR HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBackgroundColor = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) + { + this._applyBackgroundColor(propValue.getHex()); + propValue.add(this); + } + else + { + this._resetBackgroundColor(); + } + + return true; +}; + +qx.Proto._applyBackgroundColor = function(vNewValue) { + this.setParam("bgcolor", vNewValue); +}; + + + + +/* +--------------------------------------------------------------------------- + PARAMS +--------------------------------------------------------------------------- +*/ + +qx.Proto.setParam = function(name, value){ + this._params[name] = value; +}; + +qx.Proto.getParam = function(name){ + return this._params[name]; +}; + +qx.Proto.getParams = function() { + return this._params; +}; + + + + + +/* +--------------------------------------------------------------------------- + VARIABLES +--------------------------------------------------------------------------- +*/ + +qx.Proto.setVariable = function(name, value){ + this._variables[name] = value; +}; + +qx.Proto.getVariable = function(name){ + return this._variables[name]; +}; + +qx.Proto.getVariables = function(){ + return this._variables; +}; + + + + + +/* +--------------------------------------------------------------------------- + HTML UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.generateParamTags = function() +{ + var vParams = this.getParams(); + var vParamTags = []; + + for (var vKey in vParams) + { + vParamTags.push("<param name='"); + vParamTags.push(vKey); + vParamTags.push("' value='"); + vParamTags.push(vParams[vKey]); + vParamTags.push("'/>"); + } + + return vParamTags.join(""); +}; + +qx.Proto.getVariablePairs = function() +{ + var variables = this.getVariables(); + var variablePairs = []; + + for (var key in variables) { + variablePairs.push(key + "=" + variables[key]); + } + + return variablePairs.join("&"); +}; + + + + + + +/* +--------------------------------------------------------------------------- + HTML GENERATOR +--------------------------------------------------------------------------- +*/ + +// Netscape Plugin Architecture +if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) +{ + qx.Proto.generateHTML = function() + { + var html = []; + + // Express Install Handling + if (this._expressInstall) + { + document.title = document.title.slice(0, 47) + ' - Flash Player Installation'; + + this.addVariable('MMredirectURL', escape(window.location)); + this.addVariable('MMdoctitle', document.title); + this.addVariable('MMplayerType', 'PlugIn'); + } + + html.push("<embed type='application/x-shockwave-flash' width='100%' height='100%' src='"); + html.push(this._source); + html.push("'"); + + var params = this.getParams(); + + for (var key in params) + { + html.push(" "); + html.push(key); + html.push("="); + html.push("'"); + html.push(params[key]); + html.push("'"); + } + + var pairs = this.getVariablePairs(); + + if (pairs.length > 0) + { + html.push(" "); + html.push("flashvars"); + html.push("="); + html.push("'"); + html.push(pairs); + html.push("'"); + } + + html.push("></embed>"); + + return html.join(""); + }; +} +else +{ + // Internet Explorer ActiveX Architecture + qx.Proto.generateHTML = function() + { + var html = []; + + // Express Install Handling + if (this._expressInstall) + { + document.title = document.title.slice(0, 47) + ' - Flash Player Installation'; + + this.addVariable("MMredirectURL", escape(window.location)); + this.addVariable("MMdoctitle", document.title); + this.addVariable("MMplayerType", "ActiveX"); + } + + html.push("<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width='100%' height='100%'>"); + html.push("<param name='movie' value='"); + html.push(this._source); + html.push("'/>"); + + var tags = this.generateParamTags(); + + if(tags.length > 0) { + html.push(tags); + } + + var pairs = this.getVariablePairs(); + + if(pairs.length > 0) + { + html.push("<param name='flashvars' value='"); + html.push(pairs); + html.push("'/>"); + } + + html.push("</object>"); + + return html.join(""); + }; +} + + + + + + +/* +--------------------------------------------------------------------------- + METHODS TO GIVE THE LAYOUTERS INFORMATIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isWidthEssential = qx.lang.Function.returnTrue; +qx.Proto._isHeightEssential = qx.lang.Function.returnTrue; + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = qx.lang.Function.returnZero; +qx.Proto._computePreferredInnerHeight = qx.lang.Function.returnZero; + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._source; + delete this._params; + delete this._variables; + + if (this._version) + { + this._version.dispose(); + this._version = null; + } + + qx.ui.basic.Terminator.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js new file mode 100644 index 0000000000..64864d4570 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js @@ -0,0 +1,559 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * @event beforeToolTipAppear {qx.event.type.Event} + * @event loadComplete {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.embed.Gallery", qx.ui.basic.Terminator, +function(vGalleryList) +{ + qx.ui.basic.Terminator.call(this); + + this._blank = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + this._list = vGalleryList; + this._listSize = vGalleryList.length; + this._processedImages = 0; + + this.setOverflow("auto"); + + this.setHtmlProperty("className", "qx_ui_embed_Gallery"); + + this._manager = new qx.manager.selection.DomSelectionManager(this); + + this._manager.setMultiColumnSupport(true); + + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mousemove", this._onmousemove); + + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + this.addEventListener("keypress", this._onkeypress); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "thumbMaxWidth", type : "number", defaultValue : 100 }); +qx.OO.addProperty({ name : "thumbMaxHeight", type : "number", defaultValue : 100 }); +qx.OO.addProperty({ name : "decorHeight", type : "number", defaultValue : 40 }); +qx.OO.addProperty({ name : "showTitle", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "showComment", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this.getElement().appendChild(this.createView()); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.update = function(vGalleryList) +{ + this._manager.deselectAll(); + + this._list = vGalleryList; + + var el = this.getElement(); + el.replaceChild(this.createView(), el.firstChild); +} + +qx.Proto.removeAll = function() +{ + this._manager.deselectAll(); + this.getElement().innerHTML = ""; +} + +qx.Proto.updateImageById = function(vId, vSrc, vWidth, vHeight) { + this.updateImageSrcById(vId, vSrc); + this.updateImageDimensionsById(vId, vWidth, vHeight); +} + +qx.Proto.updateImageDimensionsById = function(vId, vWidth, vHeight) { + this.updateImageDimensionsByPosition(this.getPositionById(vId), vWidth, vHeight); +} + +qx.Proto.updateImageDimensionsByPosition = function(vPos, vWidth, vHeight) { + // TBD: compare dimensions with max. thumb size and scale proportionally if necessary + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var cnode = this.getNodeByPosition(vPos).getElementsByTagName("img")[0]; + + cnode.width = vWidth; + cnode.height = vHeight; + + cnode.style.marginLeft = cnode.style.marginRight = Math.floor((this.getThumbMaxWidth()-vWidth)/2) + "px"; + cnode.style.marginTop = cnode.style.marginBottom = Math.floor((this.getThumbMaxHeight()-vHeight)/2) + "px"; + + this._list[vPos].thumbWidth = vWidth; + this._list[vPos].thumbHeight = vHeight; +} + +qx.Proto.updateImageSrcById = function(vId, vSrc) { + this.updateImageSrcByPosition(this.getPositionById(vId), vSrc); +} + +qx.Proto.updateImageSrcByPosition = function(vPos, vSrc) +{ + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var vNode = this.getNodeByPosition(vPos); + + vNode.getElementsByTagName("img")[0].src = vSrc; + this._list[vPos].src = vSrc; +} + +qx.Proto.deleteById = function(vId) { + this.deleteByPosition(this.getPositionById(vId)); +} + +qx.Proto.deleteByPosition = function(vPos) +{ + this._manager.deselectAll(); + + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var vNode = this.getNodeByPosition(vPos); + + if (vNode) { + vNode.parentNode.removeChild(vNode); + } + + this._list.splice(vPos, 1); +} + +qx.Proto.getPositionById = function(vId) +{ + for (var i=0, a=this._list, l=a.length; i<l; i++) { + if (a[i].id == vId) { + return i; + } + } + + return -1; +} + +qx.Proto.getEntryById = function(vId) { + return this.getEntryByPosition(this.getPositionById(vId)); +} + +qx.Proto.getNodeById = function(vId) { + return this.getNodeByPosition(this.getPositionById(vId)); +} + +qx.Proto.getEntryByPosition = function(vPosition) { + return vPosition == -1 ? null : this._list[vPosition]; +} + +qx.Proto.getNodeByPosition = function(vPosition) { + return vPosition == -1 ? null : this._frame.childNodes[vPosition]; +} + +qx.Proto.getEntryByNode = function(vNode) { + return this.getEntryById(vNode.id); +} + +qx.Proto.addFromPartialList = function(vPartialList) +{ + this.concat(vPartialList); + + for (var i=0, a=vPartialList, l=a.length; i<l; i++) { + this._frame.appendChild(this.createCell(a[i], i)); + } +} + +qx.Proto.addFromUpdatedList = function(vNewList) +{ + for (var a=vNewList, l=a.length, i=this._list.length; i<l; i++) { + this._frame.appendChild(this.createCell(a[i], i)); + } + + this._list = vNewList; +} + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleMouseDown(vItem, e); + } +} + +qx.Proto._onmouseup = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleMouseUp(vItem, e); + } +} + +qx.Proto._onmousemove = function(e) +{ + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) { + return; + } + + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem == this._lastItem) { + return; + } + + if (this._lastItem) + { + var vEventObject = new qx.event.type.MouseEvent("mouseout", e, false, this._lastItem); + qx.manager.object.ToolTipManager.getInstance().handleMouseOut(vEventObject); + vEventObject.dispose(); + } + + if (vItem) + { + if (this.hasEventListeners("beforeToolTipAppear")) { + this.dispatchEvent(new qx.event.type.DataEvent("beforeToolTipAppear", vItem), true); + } + + if (!this.getToolTip()) { + return; + } + + var vEventObject = new qx.event.type.MouseEvent("mouseout", e, false, vItem); + qx.manager.object.ToolTipManager.getInstance().handleMouseOver(vEventObject); + vEventObject.dispose(); + + this.setToolTip(null); + } + + this._lastItem = vItem; +} + +qx.Proto._onclick = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleClick(vItem, e); + } +} + +qx.Proto._ondblclick = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleDblClick(vItem, e); + } +} + +qx.Proto._onkeypress = function(e) { + this._manager.handleKeyPress(e); +} + +qx.Proto.getListItemTarget = function(dt) +{ + while(dt.className.indexOf("galleryCell") == -1 && dt.tagName.toLowerCase() != "body") { + dt = dt.parentNode; + } + + if (dt.tagName.toLowerCase() == "body") { + return null; + } + + return dt; +} + + + + + +/* +--------------------------------------------------------------------------- + SCROLL INTO VIEW +--------------------------------------------------------------------------- +*/ + +qx.Proto.scrollItemIntoView = function(vItem) +{ + this.scrollItemIntoViewX(vItem); + this.scrollItemIntoViewY(vItem); +} + +qx.Proto.scrollItemIntoViewX = function(vItem) { + qx.html.ScrollIntoView.scrollX(vItem); +} + +qx.Proto.scrollItemIntoViewY = function(vItem) { + qx.html.ScrollIntoView.scrollY(vItem); +} + + + + + +/* +--------------------------------------------------------------------------- + MANAGER REQUIREMENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItems = function() { + return this._frame.childNodes; +} + +qx.Proto.getFirstChild = function() { + return this._frame.childNodes[0]; +} + +qx.Proto.getLastChild = function() { + return this._frame.childNodes[this._frame.childNodes.length-1]; +} + + + + + + + +/* +--------------------------------------------------------------------------- + INTERNALS +--------------------------------------------------------------------------- +*/ + +qx.Proto.createView = function() +{ + var s = (new Date).valueOf(); + + if (!this._protoCell) { + this.createProtoCell(); + } + + this._frame = document.createElement("div"); + this._frame.className = "galleryFrame clearfix"; + + for (var i=0, a=this._list, l=a.length; i<l; i++) { + this._frame.appendChild(this.createCell(a[i], i)); + } + + return this._frame; +} + +qx.Proto.createCell = function(d, i) +{ + var cframe = this._protoCell.cloneNode(true); + + cframe.id = d.id; + cframe.pos = i; + + if (this.getShowTitle()) + { + cnode = cframe.childNodes[0]; + cnode.firstChild.nodeValue = d.title; + } + + var cnode = cframe.childNodes[this.getShowTitle() ? 1 : 0]; + this.createImageCell(cnode, d); + + if (this.getShowComment()) + { + cnode = cframe.childNodes[this.getShowTitle() ? 2 : 1]; + cnode.firstChild.nodeValue = d.comment; + } + + return cframe; +} + +qx.Proto._mshtml = qx.core.Client.getInstance().isMshtml(); + +qx.Proto.createImageCell = function(inode, d) +{ + if (this.hasEventListeners("loadComplete")) + { + inode.onload = qx.ui.embed.Gallery.imageOnLoad; + inode.onerror = qx.ui.embed.Gallery.imageOnError; + inode.gallery = this; + } + + if (this._mshtml) { + inode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + d.src + "',sizingMethod='scale')"; + } else { + inode.src = d.src; + } + + inode.width = d.thumbWidth + 2; + inode.height = d.thumbHeight + 2; + inode.style.marginLeft = inode.style.marginRight = Math.floor((this.getThumbMaxWidth()-d.thumbWidth)/2) + "px"; + inode.style.marginTop = inode.style.marginBottom = Math.floor((this.getThumbMaxHeight()-d.thumbHeight)/2) + "px"; +} + +qx.Proto.imageOnComplete = function() +{ + this._processedImages++; + + if(this._processedImages == this._listSize) { + this.dispatchEvent(new qx.event.type.Event("loadComplete"), true); + } +} + +qx.ui.embed.Gallery.imageOnLoad = function() +{ + this.gallery.imageOnComplete(); + this.gallery = null; + this.onload = null; + this.onerror = null; +} + +qx.ui.embed.Gallery.imageOnError = function() +{ + this.gallery.imageOnComplete(); + this.gallery = null; + this.onload = null; + this.onerror = null; +} + +qx.Proto.createProtoCell = function() +{ + var frame = this._protoCell = document.createElement("div"); + frame.className = "galleryCell"; + frame.unselectable = "on"; + frame.style.width = (this.getThumbMaxWidth() + 2) + "px"; + frame.style.height = (this.getThumbMaxHeight() + this.getDecorHeight() + 2) + "px"; + + if (this.getShowTitle()) + { + var title = document.createElement("div"); + title.className = "galleryTitle"; + title.unselectable = "on"; + var ttext = document.createTextNode("-"); + title.appendChild(ttext); + + frame.appendChild(title); + } + + var image = new Image(); + image.src = this._blank; + frame.appendChild(image); + + if (this.getShowComment()) + { + var comment = document.createElement("div"); + comment.className = "galleryComment"; + comment.unselectable = "on"; + var ctext = document.createTextNode("-"); + comment.appendChild(ctext); + + frame.appendChild(comment); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + this._list = null; + this._protoCell = null; + this._frame = null; + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mousemove", this._onmousemove); + + this.removeEventListener("click", this._onclick); + this.removeEventListener("dblclick", this._ondblclick); + + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/GalleryList.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/GalleryList.js new file mode 100644 index 0000000000..4c56a1cb69 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/GalleryList.js @@ -0,0 +1,403 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * @event loadComplete {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.embed.GalleryList", qx.ui.basic.Terminator, +function(galleryList) +{ + qx.ui.basic.Terminator.call(this); + + this._blank = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + this._list = galleryList; + this._listSize = galleryList.length; + this._processedImages = 0; + + this.setOverflow("auto"); + + this.setHtmlProperty("className", "qx_ui_embed_GalleryList"); + + this._manager = new qx.manager.selection.DomSelectionManager(this); + + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + this.addEventListener("keypress", this._onkeypress); +}); + +qx.OO.addProperty({ name : "thumbMaxWidth", type : "number", defaultValue : 60 }); +qx.OO.addProperty({ name : "thumbMaxHeight", type : "number", defaultValue : 60 }); +qx.OO.addProperty({ name : "decorHeight", type : "number", defaultValue : 40 }); + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this.getElement().appendChild(this.createView()); +} + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + + +qx.Proto.update = function(vGalleryList) +{ + this._manager.deselectAll(); + + this._list = vGalleryList; + + var el = this.getElement(); + el.replaceChild(this.createView(), el.firstChild); +} + + +qx.Proto.removeAll = function() +{ + this._manager.deselectAll(); + this.getElement().innerHTML = ""; +} + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleMouseDown(vItem, e); + } +} + +qx.Proto._onmouseup = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleMouseUp(vItem, e); + } +} + +qx.Proto._onclick = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleClick(vItem, e); + } +} + +qx.Proto._ondblclick = function(e) +{ + var vItem = this.getListItemTarget(e.getDomTarget()); + + if (vItem) { + this._manager.handleDblClick(vItem, e); + } +} + +qx.Proto._onkeypress = function(e) { + this._manager.handleKeyPress(e); +} + +qx.Proto.getListItemTarget = function(dt) +{ + while(dt.className.indexOf("galleryCell") == -1 && dt.tagName.toLowerCase() != "body") { + dt = dt.parentNode; + } + + if (dt.tagName.toLowerCase() == "body") { + return null; + } + + return dt; +} + + + + + + + +/* +--------------------------------------------------------------------------- + SCROLL INTO VIEW +--------------------------------------------------------------------------- +*/ + +qx.Proto.scrollItemIntoView = function(vItem) +{ + this.scrollItemIntoViewX(vItem); + this.scrollItemIntoViewY(vItem); +} + +qx.Proto.scrollItemIntoViewX = function(vItem) { + qx.html.ScrollIntoView.scrollX(vItem); +} + +qx.Proto.scrollItemIntoViewY = function(vItem) { + qx.html.ScrollIntoView.scrollY(vItem); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + SELECTION MANAGER API +--------------------------------------------------------------------------- +*/ + +qx.Proto.getItems = function() { + return this._frame.childNodes; +} + +qx.Proto.getFirstChild = function() { + return this._frame.childNodes[0]; +} + +qx.Proto.getLastChild = function() { + return this._frame.childNodes[this._frame.childNodes.length-1]; +} + + + + + + +/* +--------------------------------------------------------------------------- + CREATE VIEW +--------------------------------------------------------------------------- +*/ + +qx.Proto.createView = function() +{ + var s = (new Date).valueOf(); + + var protoCell = this.createProtoCell(this.getThumbMaxHeight()); + var frame = this._frame = document.createElement("div"); + + this._frame.className = "galleryFrame clearfix"; + + var cframe, cnode; + + for (var i=0, a=this._list, l=a.length, d; i<l; i++) + { + d = a[i]; + + cframe = protoCell.cloneNode(true); + + cframe.id = d.id; + cframe.pos = i; + + cnode = cframe.childNodes[0]; + cnode.firstChild.nodeValue = d.number; + + cnode = cframe.childNodes[1].firstChild; + this.createImageCell(cnode, d); + + cnode = cframe.childNodes[2].firstChild; + cnode.firstChild.nodeValue = d.title; + + cnode = cframe.childNodes[2].lastChild; + cnode.firstChild.nodeValue = d.comment; + + frame.appendChild(cframe); + } + + return frame; +} + +qx.Proto._mshtml = qx.core.Client.getInstance().isMshtml(); + +qx.Proto.createImageCell = function(inode, d) +{ + if (this.hasEventListeners("loadComplete")) { + inode.onload = qx.ui.embed.GalleryList.imageOnLoad; + inode.onerror = qx.ui.embed.GalleryList.imageOnError; + inode.gallery = this; + } + + inode.width = d.thumbWidth; + inode.height = d.thumbHeight; + + if (this._mshtml) { + inode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + d.src + "',sizingMethod='scale')"; + } else { + inode.src = d.src; + } + + inode.style.marginLeft = inode.style.marginRight = Math.floor((this.getThumbMaxWidth()-d.thumbWidth)/2) + "px"; + inode.style.marginTop = inode.style.marginBottom = Math.floor((this.getThumbMaxHeight()-d.thumbHeight)/2) + "px"; +} + +qx.Proto.createProtoCell = function(tHeight) +{ + var frame = document.createElement("div"); + frame.className = "galleryCell"; + frame.unselectable = "on"; + frame.style.height = (tHeight + 2) + "px"; + + var number = document.createElement("div"); + number.className = "galleryNumber"; + number.unselectable = "on"; + var ntext = document.createTextNode("-"); + number.appendChild(ntext); + + var imageContainer = document.createElement("div"); + imageContainer.className = "galleryImageContainer"; + imageContainer.unselectable = "on"; + + var image = new Image(); + image.src = this._blank; + + imageContainer.appendChild(image); + + var text = document.createElement("div"); + text.className = "galleryText"; + text.unselectable = "on"; + text.style.width = (this.getWidth()-100-this.getThumbMaxWidth()) + "px"; + + var title = document.createElement("h3"); + var ttext = document.createTextNode("-"); + title.appendChild(ttext); + title.unselectable = "on"; + text.appendChild(title); + + var comment = document.createElement("p"); + var ctext = document.createTextNode("-"); + comment.appendChild(ctext); + comment.unselectable = "on"; + text.appendChild(comment); + + + frame.appendChild(number); + frame.appendChild(imageContainer); + frame.appendChild(text); + + return frame; +} + + + + + + + +/* +--------------------------------------------------------------------------- + PRELOADING +--------------------------------------------------------------------------- +*/ + +qx.Proto.imageOnComplete = function() +{ + this._processedImages++; + + if(this._processedImages == this._listSize) { + this.dispatchEvent(new qx.event.type.Event("loadComplete"), true); + } +} + +qx.ui.embed.GalleryList.imageOnLoad = function() +{ + this.gallery.imageOnComplete(); + this.gallery = null; + this.onload = null; + this.onerror = null; +} + +qx.ui.embed.GalleryList.imageOnError = function() +{ + this.gallery.imageOnComplete(); + this.gallery = null; + this.onload = null; + this.onerror = null; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + this._list = null; + this._frame = null; + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("click", this._onclick); + this.removeEventListener("dblclick", this._ondblclick); + this.removeEventListener("keydown", this._onkeydown); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/HtmlEmbed.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/HtmlEmbed.js new file mode 100644 index 0000000000..0e526f4fb7 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/HtmlEmbed.js @@ -0,0 +1,114 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.HtmlEmbed", qx.ui.basic.Terminator, +function(vHtml) +{ + qx.ui.basic.Terminator.call(this); + + if (vHtml != null) { + this.setHtml(vHtml); + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any text string which can contain HTML, too +*/ +qx.OO.addProperty({ name : "html", type : "string" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + +/*! + Wrap the text? +*/ +qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyHtml = function() +{ + if (this._isCreated) { + this._syncHtml(); + } + + return true; +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + +qx.Proto._modifyWrap = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this._syncHtml(); +} + +qx.Proto._syncHtml = function() { + this.getElement().innerHTML = this.getHtml(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/IconHtmlEmbed.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/IconHtmlEmbed.js new file mode 100644 index 0000000000..06f935b2d6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/IconHtmlEmbed.js @@ -0,0 +1,137 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.IconHtmlEmbed", qx.ui.embed.HtmlEmbed, +function(vHtml, vIcon, vIconWidth, vIconHeight) +{ + qx.ui.embed.HtmlEmbed.call(this, vHtml); + + if (vIcon != null) + { + this.setIcon(vIcon); + + if (vIconWidth != null) { + this.setIconWidth(vIconWidth); + } + + if (vIconHeight != null) { + this.setIconHeight(vIconWidth); + } + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any URI String supported by qx.ui.basic.Image to display a icon +*/ +qx.OO.addProperty({ name : "icon", type : "string", impl : "html" }); + +/*! + The width of the icon. + If configured, this makes qx.ui.embed.IconHtmlEmbed a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconWidth", type : "number", impl : "html" }); + +/*! + The height of the icon + If configured, this makes qx.ui.embed.IconHtmlEmbed a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconHeight", type : "number", impl : "html" }); + +/*! + Space in pixels between the icon and the HTML. +*/ +qx.OO.addProperty({ name : "spacing", type : "number", defaultValue : 4, impl : "html" }); + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto._mshtml = qx.core.Client.getInstance().isMshtml(); + +qx.Proto._syncHtml = function() +{ + var vHtml = []; + + if (qx.util.Validation.isValidString(this.getIcon())) + { + vHtml.push("<img src=\""); + vHtml.push(qx.manager.object.AliasManager.getInstance().resolvePath(this._mshtml ? "static/image/blank.gif" : this.getIcon())); + vHtml.push("\" style=\"vertical-align:middle;"); + + if (this.getSpacing() != null) + { + vHtml.push("margin-right:"); + vHtml.push(this.getSpacing()); + vHtml.push("px;"); + } + + if (this.getIconWidth() != null) + { + vHtml.push("width:"); + vHtml.push(this.getIconWidth()); + vHtml.push("px;"); + } + + if (this.getIconHeight() != null) + { + vHtml.push("height:"); + vHtml.push(this.getIconHeight()); + vHtml.push("px;"); + } + + if (this._mshtml) + { + vHtml.push("filter:"); + vHtml.push("progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"); + vHtml.push(qx.manager.object.AliasManager.getInstance().resolvePath(this.getIcon())); + vHtml.push("',sizingMethod='scale')"); + vHtml.push(";"); + } + + vHtml.push("\"/>"); + } + + if (qx.util.Validation.isValidString(this.getHtml())) { + vHtml.push(this.getHtml()); + } + + this.getElement().innerHTML = vHtml.join(""); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js new file mode 100644 index 0000000000..73dc8dc254 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js @@ -0,0 +1,433 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * @event load {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.embed.Iframe", qx.ui.basic.Terminator, +function(vSource) +{ + // ********************************************************************** + // INIT + // ********************************************************************** + qx.ui.basic.Terminator.call(this); + + this.setSelectable(false); + this.setTabIndex(0); + + var o = this; + this.__onreadystatechange = function(e) { return o._onreadystatechange(e); } + this.__onload = function(e) { return o._onload(e); } + + if (vSource != undefined) { + this.setSource(vSource); + } +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "iframe" }); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "source", type : "string" }); + +qx.OO.addProperty({ name : "frameName", type : "string" }); + + + + + + +/* +--------------------------------------------------------------------------- + INTERNAL PROPERTIES +--------------------------------------------------------------------------- +*/ + + +// iframe DOM node + +qx.Proto._iframeNode = null; + +qx.Proto.getIframeNode = function() { + return this._iframeNode; +} + +qx.Proto.setIframeNode = function(vIframeNode) { + return this._iframeNode = vIframeNode; +} + + +// blocker div DOM node + +qx.Proto._blockerNode = null; + +qx.Proto.getBlockerNode = function() { + return this._blockerNode; +} + +qx.Proto.setBlockerNode = function(vBlockerNode) { + return this._blockerNode = vBlockerNode; +} + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.reload = function() { + this._applySource(); +} + + +qx.Proto.block = function() +{ + if (this._blockerNode) { + this._blockerNode.style.display = ""; + } +}; + +qx.Proto.release = function() +{ + if (this._blockerNode) { + this._blockerNode.style.display = "none"; + } +}; + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + + var iframeNode = this.getIframeNode(); + + if (!iframeNode) + { + + qx.ui.embed.Iframe.initIframe(this.getFrameName()); + + // clone proto element and assign iframe + iframeNode = this.setIframeNode(qx.ui.embed.Iframe._element.cloneNode(true)); + + qx.ui.embed.Iframe.initBlocker(); + + // clone proto blocker + var blockerNode = this.setBlockerNode(qx.ui.embed.Iframe._blocker.cloneNode(true)); + + if (qx.core.Client.getInstance().isMshtml()) { + iframeNode.onreadystatechange = this.__onreadystatechange; + } else { + iframeNode.onload = this.__onload; + } + } + + this._applySource(); + + propValue.appendChild(iframeNode); + propValue.appendChild(blockerNode); + + // create basic widget + qx.ui.basic.Terminator.prototype._modifyElement.call(this, propValue, propOldValue, propData); + + return true; +} + + +qx.Proto._beforeAppear = function() { + qx.ui.basic.Terminator.prototype._beforeAppear.call(this); + + // register to iframe manager as active widget + qx.manager.object.IframeManager.getInstance().add(this); +}; + + +qx.Proto._beforeDisappear = function() { + qx.ui.basic.Terminator.prototype._beforeDisappear.call(this); + + // deregister from iframe manager + qx.manager.object.IframeManager.getInstance().remove(this); +}; + + +qx.Proto._modifySource = function(propValue, propOldValue, propData) +{ + if(this.isCreated()) { + this._applySource(); + } + + return true; +} + +qx.Proto._applySource = function() +{ + var currentSource = this.getSource(); + + if (qx.util.Validation.isInvalidString(currentSource)) { + currentSource = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + } + + this._isLoaded = false; + this.getIframeNode().src = currentSource; +} + +qx.Proto._modifyFrameName = function (propValue, propOldValue, propName, uniqModIds) +{ + if( this.isCreated()) { + throw new Error("Not allowed to set frame name after it has been created"); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onreadystatechange = function() +{ + if (this.getIframeNode().readyState == "complete") { + this.dispatchEvent(new qx.event.type.Event("load"), true); + } +} + +qx.Proto._onload = function() +{ + this._isLoaded = true; + this.dispatchEvent(new qx.event.type.Event("load"), true); +} + + + + + + +/* +--------------------------------------------------------------------------- + WINDOW & DOCUMENT ACCESS +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.getContentWindow = function() + { + if (this.isCreated()) { + try { return this.getIframeNode().contentWindow; } + catch (ex) {} + } + + return null; + } + + qx.Proto.getContentDocument = function() + { + var win = this.getContentWindow(); + if (win) { + try { return win.document; } + catch (ex) {} + } + + return null; + } +} +else +{ + qx.Proto.getContentWindow = function() + { + var doc = this.getContentDocument(); + return doc ? doc.defaultView : null; + } + + qx.Proto.getContentDocument = function() + { + if (this.isCreated()) { + try { return this.getIframeNode().contentDocument; } + catch (ex) {} + } + + return null; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOAD STATUS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isLoaded = false; + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.isLoaded = function() + { + var doc = this.getContentDocument(); + return doc ? doc.readyState == "complete" : false; + } +} +else +{ + qx.Proto.isLoaded = function() + { + return this._isLoaded; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.__onreadystatechange = this.__onload = null; + + if (this._iframeNode) + { + this._iframeNode.onreadystatechange = null; + this._iframeNode.onload = null; + + this._iframeNode = null; + } + + qx.ui.basic.Terminator.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + INIT +--------------------------------------------------------------------------- +*/ +qx.ui.embed.Iframe.initIframe = function(vFrameName) +{ + if (qx.ui.embed.Iframe._element && !vFrameName) { + return; + } + + if (vFrameName && qx.core.Client.getInstance().isMshtml()) { + var f = qx.ui.embed.Iframe._element = document.createElement('<iframe name="' + vFrameName + '"></iframe>'); + } else { + var f = qx.ui.embed.Iframe._element = document.createElement("iframe"); + if (vFrameName) { + f.name = vFrameName; + } + } + + f.frameBorder = "0"; + f.frameSpacing = "0"; + + f.marginWidth = "0"; + f.marginHeight = "0"; + + f.width = "100%"; + f.height = "100%"; + + f.hspace = "0"; + f.vspace = "0"; + + f.border = "0"; + f.scrolling = "auto"; + f.unselectable = "on"; + f.allowTransparency = "true"; + + f.style.position = "absolute"; + f.style.top = 0; + f.style.left = 0; + }; + +qx.ui.embed.Iframe.initBlocker = function() +{ + + if (qx.ui.embed.Iframe._blocker) { + return; + } + + var b = qx.ui.embed.Iframe._blocker = document.createElement("div"); + + if (qx.core.Client.getInstance().isMshtml()) { + b.style.backgroundImage = "url(" + qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif") + ")"; + } + + b.style.position = "absolute"; + b.style.top = 0; + b.style.left = 0; + b.style.width = "100%"; + b.style.height = "100%"; + b.style.zIndex = 1; + b.style.display = "none"; +}; + + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js new file mode 100644 index 0000000000..9ea3398eb9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js @@ -0,0 +1,90 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.LinkEmbed", qx.ui.embed.HtmlEmbed, +function(vHtml, vUri, vTarget) +{ + qx.ui.embed.HtmlEmbed.call(this, vHtml); + + if (typeof vUri != "undefined") { + this.setUri(vUri); + } + + if (typeof vTarget != "undefined") { + this.setTarget(vTarget); + } +}); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any valid html URI +*/ +qx.OO.addProperty({ name : "uri", type : "string", defaultValue : "#", impl : "html" }); + +/*! + Any valid html target +*/ +qx.OO.addProperty({ name : "target", type : "string", defaultValue : "_blank", impl : "html" }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.ui.embed.LinkEmbed.LINK_START = "<a target='"; +qx.ui.embed.LinkEmbed.HREF_START = "' href='"; +qx.ui.embed.LinkEmbed.HREF_STOP = "'>"; +qx.ui.embed.LinkEmbed.LINK_STOP = "</a>"; + +qx.Proto._syncHtml = function() +{ + var vHtml = []; + + vHtml.push(qx.ui.embed.LinkEmbed.LINK_START); + vHtml.push(this.getTarget()); + vHtml.push(qx.ui.embed.LinkEmbed.HREF_START); + vHtml.push(this.getUri()); + vHtml.push(qx.ui.embed.LinkEmbed.HREF_STOP); + vHtml.push(this.getHtml()); + vHtml.push(qx.ui.embed.LinkEmbed.LINK_STOP); + + this.getElement().innerHTML = vHtml.join(""); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js new file mode 100644 index 0000000000..3b8554a682 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js @@ -0,0 +1,50 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.NodeEmbed", qx.ui.basic.Terminator, +function(vId) +{ + qx.ui.basic.Terminator.call(this); + + if (vId != null) { + this.setSourceNodeId(vId); + } +}); + +qx.OO.addProperty({ name : "sourceNodeId", type : "string" }); + +qx.Proto._createElementImpl = function() +{ + var vNode = document.getElementById(this.getSourceNodeId()); + + if (!vNode) { + throw new Error("Could not find source node with ID: " + this.getSourceNodeId()); + } + + vNode.style.display = ""; + + return this.setElement(vNode); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js new file mode 100644 index 0000000000..a2554e3973 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js @@ -0,0 +1,123 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.TextEmbed", qx.ui.basic.Terminator, +function(vText) +{ + qx.ui.basic.Terminator.call(this); + + if (vText != null) { + this.setText(vText); + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any text string which can contain TEXT, too +*/ +qx.OO.addProperty({ name : "text", type : "string" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + +/*! + Wrap the text? +*/ +qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true }); + +/** The horizontal alignment of the text. */ +qx.OO.addProperty({ name : "textAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right", "justify" ], allowNull : false }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyText = function() +{ + if (this._isCreated) { + this._syncText(); + } + + return true; +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + +qx.Proto._modifyWrap = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + return true; +} + +// property modifier +qx.Proto._modifyTextAlign = function(propValue, propOldValue, propData) { + this.setStyleProperty("textAlign", propValue); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this.getElement().appendChild(document.createTextNode(this.getText())); +} + +qx.Proto._syncText = function() { + this.getElement().firstChild.nodeValue = this.getText(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Button.js new file mode 100644 index 0000000000..858a1b8906 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Button.js @@ -0,0 +1,208 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ +/** + * A button. + * + * @state {abandoned} + * @state {over} + * @state {pressed} + */ +qx.OO.defineClass("qx.ui.form.Button", qx.ui.basic.Atom, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) +{ + // ************************************************************************ + // INIT + // ************************************************************************ + qx.ui.basic.Atom.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + // Make focusable + this.setTabIndex(1); + + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keyup", this._onkeyup); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "button" }); + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + if (e.getTarget() != this) { + return; + } + + if (this.hasState("abandoned")) + { + this.removeState("abandoned"); + this.addState("pressed"); + } + + this.addState("over"); +} + +qx.Proto._onmouseout = function(e) +{ + if (e.getTarget() != this) { + return; + } + + this.removeState("over"); + + if (this.hasState("pressed")) + { + // Activate capturing if the button get a mouseout while + // the button is pressed. + this.setCapture(true); + + this.removeState("pressed"); + this.addState("abandoned"); + } +} + +qx.Proto._onmousedown = function(e) +{ + if (e.getTarget() != this || !e.isLeftButtonPressed()) { + return; + } + + this.removeState("abandoned"); + this.addState("pressed"); +} + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + // We must remove the states before executing the command + // because in cases were the window lost the focus while + // executing we get the capture phase back (mouseout). + var hasPressed = this.hasState("pressed"); + var hasAbandoned = this.hasState("abandoned"); + + if (hasPressed) { + this.removeState("pressed"); + } + + if (hasAbandoned) { + this.removeState("abandoned"); + } + + if (!hasAbandoned) + { + this.addState("over"); + + if (hasPressed) { + this.execute(); + } + } +} + +qx.Proto._onkeydown = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Enter": + case "Space": + this.removeState("abandoned"); + this.addState("pressed"); + } +} + +qx.Proto._onkeyup = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Enter": + case "Space": + if (this.hasState("pressed")) + { + this.removeState("abandoned"); + this.removeState("pressed"); + this.execute(); + } + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mouseover", this._onmouseover, this); + this.removeEventListener("mouseout", this._onmouseout, this); + this.removeEventListener("mousedown", this._onmousedown, this); + this.removeEventListener("mouseup", this._onmouseup, this); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown, this); + this.removeEventListener("keyup", this._onkeyup, this); + + + // ************************************************************************ + // SUPER CLASS + // ************************************************************************ + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js new file mode 100644 index 0000000000..8a8c581655 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js @@ -0,0 +1,212 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.CheckBox", qx.ui.basic.Atom, +function(vText, vValue, vName, vChecked) +{ + qx.ui.basic.Atom.call(this, vText); + + this.setTabIndex(1); + this.setPadding(2, 3); + + this._createIcon(); + + if (vValue != null) { + this.setValue(vValue); + } + + if (vName != null) { + this.setName(vName); + } + + if (vChecked != null) { + this.setChecked(vChecked); + } else { + this.setChecked(false); + } + + this.addEventListener("click", this._onclick); + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keyup", this._onkeyup); +}); + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.OO.removeProperty({ name : "icon" }); +qx.OO.removeProperty({ name : "disabledIcon" }); + +/*! + The HTML name of the form element used by the widget +*/ +qx.OO.addProperty({ name : "name", type : "string" }); + +/*! + The HTML value of the form element used by the widget +*/ +qx.OO.addProperty({ name : "value", type : "string" }); + +/*! + If the widget is checked +*/ +qx.OO.addProperty({ name : "checked", type : "boolean", getAlias : "isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + ICON HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.INPUT_TYPE = "checkbox"; + +qx.Proto._createIcon = function() +{ + var i = this._iconObject = new qx.ui.form.InputCheckSymbol; + + i.setType(this.INPUT_TYPE); + i.setChecked(this.isChecked()); + i.setEnabled(this.isEnabled()); + i.setAnonymous(true); + + this.addAtBegin(i); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setChecked(propValue); + } + + return true; +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setEnabled(propValue); + } + + return qx.ui.basic.Atom.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + + + + +/* +--------------------------------------------------------------------------- + HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleIcon = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_ICON: + case qx.ui.basic.Atom.SHOW_BOTH: + this._iconIsVisible = true; + break; + + default: + this._iconIsVisible = false; + } + + if (this._iconIsVisible) + { + this._iconObject ? this._iconObject.setDisplay(true) : this._createIcon(); + } + else if (this._iconObject) + { + this._iconObject.setDisplay(false); + } +} + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onclick = function(e) { + this.toggleChecked(); +}; + + +qx.Proto._onkeydown = function(e) +{ + if(e.getKeyIdentifier() == "Enter" && !e.isAltPressed()) { + this.toggleChecked(); + } +}; + + +qx.Proto._onkeyup = function(e) +{ + if(e.getKeyIdentifier() == "Space") { + this.toggleChecked(); + } +}; + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this.removeEventListener("click", this._onclick); + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keyup", this._onkeyup); + + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js new file mode 100644 index 0000000000..08a45826c0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js @@ -0,0 +1,837 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) +#embed(qx.widgettheme/arrows/down.gif) + +************************************************************************ */ + +/** + * A combo-box for qooxdoo. + * + * The major additional feature compared to typical select fields is that it allows + * it to be editable. Also images are supported inside the popup list. + * + * Features: + * <ul> + * <li>Editable text field</li> + * <li>Complete key-navigation</li> + * <li>Images inside the list</li> + * <li>Images and text inside the list</li> + * </ul> + * + * @event beforeInitialOpen {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.form.ComboBox", qx.ui.layout.HorizontalBoxLayout, +function() +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + + // ************************************************************************ + // LIST + // ************************************************************************ + var l = this._list = new qx.ui.form.List; + + l.setAppearance("combo-box-list"); + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + var m = this._manager = this._list.getManager(); + + m.setMultiSelection(false); + m.setDragSelection(false); + + + // ************************************************************************ + // POPUP + // ************************************************************************ + var p = this._popup = new qx.ui.popup.Popup; + + p.setAppearance("combo-box-popup"); + p.setAutoHide(false); + + p.add(l); + + + // ************************************************************************ + // TEXTFIELD + // ************************************************************************ + var f = this._field = new qx.ui.form.TextField; + + f.setAppearance("combo-box-text-field"); + f.setTabIndex(-1); + + this.add(f); + + + // ************************************************************************ + // BUTTON + // ************************************************************************ + + // Use qx.ui.basic.Atom instead of qx.ui.form.Button here to omit the registration + // of the unneeded and complex button events. + var b = this._button = new qx.ui.basic.Atom(null, "widget/arrows/down.gif"); + + b.setAppearance("combo-box-button"); + b.setTabIndex(-1); + + this.add(b); + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTabIndex(1); + this.setEditable(false); + + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyinput", this._onkeyinput); + + + // ************************************************************************ + // WIDGET STATE EVENTS + // ************************************************************************ + this.addEventListener("beforeDisappear", this._onbeforedisappear); + + + // ************************************************************************ + // CHILDREN EVENTS + // ************************************************************************ + this._popup.addEventListener("appear", this._onpopupappear, this); + this._field.addEventListener("input", this._oninput, this); + + + // ************************************************************************ + // DOCUMENT EVENTS + // ************************************************************************ + var vDoc = qx.ui.core.ClientDocument.getInstance(); + vDoc.addEventListener("windowblur", this._onwindowblur, this); + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + this.remapChildrenHandlingTo(l); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "combo-box" }); + +qx.OO.addProperty({ name: "editable", type: "boolean", getAlias: "isEditable" }); +qx.OO.addProperty({ name: "selected", type: "object", instance : "qx.ui.form.ListItem" }); +qx.OO.addProperty({ name: "value", type : "string" }); +qx.OO.addProperty({ name: "pagingInterval", type: "number", defaultValue: 10 }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getPopup = function() { + return this._popup; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.getField = function() { + return this._field; +} + +qx.Proto.getButton = function() { + return this._button; +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySelected = function(propValue, propOldValue, propData) +{ + this._fromSelected = true; + + // only do this if we called setSelected seperatly + // and not from the property "value". + if (!this._fromValue) { + this.setValue(propValue ? propValue.getLabel() : ""); + } + + // reset manager cache + this._manager.setLeadItem(propValue); + this._manager.setAnchorItem(propValue); + + // sync to manager + if (propValue) + { + this._manager.setSelectedItem(propValue); + } + else + { + this._manager.deselectAll(); + } + + // reset hint + delete this._fromSelected; + + return true; +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + this._fromValue = true; + + // only do this if we called setValue seperatly + // and not from the event "input". + if (!this._fromInput) + { + if (this._field.getValue() == propValue) { + this._field.forceValue(null); + } + + this._field.setValue(propValue); + } + + // only do this if we called setValue seperatly + // and not from the property "selected". + if (!this._fromSelected) + { + // inform selected property + var vSelItem = this._list.findStringExact(propValue); + + // ignore disabled items + if (vSelItem != null && !vSelItem.getEnabled()) { + vSelItem = null; + } + + this.setSelected(vSelItem); + } + + // reset hint + delete this._fromValue; + + return true; +} + +qx.Proto._modifyEditable = function(propValue, propOldValue, propData) +{ + var f = this._field; + + f.setReadOnly(!propValue); + f.setCursor(propValue ? null : "default"); + f.setSelectable(propValue); + + return true; +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._button) { + this._button.setEnabled(propValue); + } + + if (this._field) { + this._field.setEnabled(propValue); + } + + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + + + + + +/* +--------------------------------------------------------------------------- + POPUP HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._oldSelected = null; + +qx.Proto._openPopup = function() +{ + var p = this._popup; + var el = this.getElement(); + + if (!p.isCreated()) { + this.createDispatchEvent("beforeInitialOpen"); + } + + if (this._list.getChildrenLength() == 0) { + return; + } + + p.positionRelativeTo(el, 1, qx.html.Dimension.getBoxHeight(el)); + p.setWidth(this.getBoxWidth()-2); + + p.setParent(this.getTopLevelWidget()); + p.show(); + + this._oldSelected = this.getSelected(); + + this.setCapture(true); +} + +qx.Proto._closePopup = function() +{ + this._popup.hide(); + this.setCapture(false); +} + +qx.Proto._testClosePopup = function() +{ + if (this._popup.isSeeable()) { + this._closePopup(); + } +} + +qx.Proto._togglePopup = function() { + this._popup.isSeeable() ? this._closePopup() : this._openPopup(); +} + + + + + +/* +--------------------------------------------------------------------------- + OTHER EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onpopupappear = function(e) +{ + var vSelItem = this.getSelected(); + if (vSelItem) { + vSelItem.scrollIntoView(); + } +} + +qx.Proto._oninput = function(e) +{ + // Hint for modifier + this._fromInput = true; + + this.setValue(this._field.getComputedValue()); + + // be sure that the found item is in view + if (this.getPopup().isSeeable() && this.getSelected()) { + this.getSelected().scrollIntoView(); + } + + delete this._fromInput; +} + +qx.Proto._onbeforedisappear = function(e) +{ + this._testClosePopup(); +} + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vTarget = e.getTarget(); + + switch(vTarget) + { + case this._field: + if (this.getEditable()) { + break; + } + + // no break here + + case this._button: + this._button.addState("pressed"); + this._togglePopup(); + break; + + case this: + case this._list: + break; + + default: + if (vTarget instanceof qx.ui.form.ListItem && vTarget.getParent() == this._list) + { + this._list._onmousedown(e); + this.setSelected(this._list.getSelectedItem()); + + this._closePopup(); + this.setFocused(true); + } + else if (this._popup.isSeeable()) + { + this._popup.hide(); + this.setCapture(false); + } + } +} + +qx.Proto._onmouseup = function(e) +{ + switch(e.getTarget()) + { + case this._field: + if (this.getEditable()) { + break; + } + + // no break here + + default: + this._button.removeState("pressed"); + break; + } +} + +qx.Proto._onmouseover = function(e) +{ + var vTarget = e.getTarget(); + + if (vTarget instanceof qx.ui.form.ListItem) + { + var vManager = this._manager; + + vManager.deselectAll(); + + vManager.setLeadItem(vTarget); + vManager.setAnchorItem(vTarget); + + vManager.setSelectedItem(vTarget); + } +} + +qx.Proto._onmousewheel = function(e) +{ + if (!this._popup.isSeeable()) + { + var toSelect; + + var isSelected = this.getSelected(); + + if (e.getWheelDelta() < 0) + { + toSelect = isSelected ? this._manager.getNext(isSelected) : this._manager.getFirst(); + } + else + { + toSelect = isSelected ? this._manager.getPrevious(isSelected) : this._manager.getLast(); + } + + if (toSelect) + { + this.setSelected(toSelect); + } + } + /* close the popup if the event target is not the combobox or + * not one of the list items of the popup list + */ + else { + var vTarget = e.getTarget(); + + if (vTarget!=this && vTarget.getParent()!=this._list) { + this._popup.hide(); + this.setCapture(false); + } + } +} + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var vManager = this._manager; + var vVisible = this._popup.isSeeable(); + + switch(e.getKeyIdentifier()) + { + // Handle <ENTER> + case "Enter": + if (vVisible) + { + this.setSelected(this._manager.getSelectedItem()); + this._closePopup(); + this.setFocused(true); + } + else + { + this._openPopup(); + } + + return; + + // Handle <ESC> + case "Escape": + if (vVisible) + { + vManager.setLeadItem(this._oldSelected); + vManager.setAnchorItem(this._oldSelected); + + vManager.setSelectedItem(this._oldSelected); + + this._field.setValue(this._oldSelected ? this._oldSelected.getLabel() : ""); + + this._closePopup(); + this.setFocused(true); + } + + return; + + // Handle Alt+Down + case "Down": + if (e.isAltPressed()) + { + this._togglePopup(); + return; + } + + break; + } +}; + + +qx.Proto._onkeypress = function(e) +{ + var vVisible = this._popup.isSeeable(); + var vManager = this._manager; + + switch(e.getKeyIdentifier()) + { + // Handle <PAGEUP> + case "PageUp": + if (!vVisible) + { + var vPrevious; + var vTemp = this.getSelected(); + + if (vTemp) + { + var vInterval = this.getPagingInterval(); + + do { + vPrevious = vTemp; + } while(--vInterval && (vTemp = vManager.getPrevious(vPrevious))); + } + else + { + vPrevious = vManager.getLast(); + } + + this.setSelected(vPrevious); + + return; + } + + break; + + // Handle <PAGEDOWN> + case "PageDown": + if (!vVisible) + { + var vNext; + var vTemp = this.getSelected(); + + if (vTemp) + { + var vInterval = this.getPagingInterval(); + + do { + vNext = vTemp; + } while(--vInterval && (vTemp = vManager.getNext(vNext))); + } + else + { + vNext = vManager.getFirst(); + } + + this.setSelected(vNext); + + return; + } + + break; + } + + // Default Handling + if (!this.isEditable() || vVisible) + { + this._list._onkeypress(e); + + var vSelected = this._manager.getSelectedItem(); + + if (!vVisible) + { + this.setSelected(vSelected); + } + else if (vSelected) + { + this._field.setValue(vSelected.getLabel()); + } + } +}; + + +qx.Proto._onkeyinput = function(e) +{ + var vVisible = this._popup.isSeeable(); + if (!this.isEditable() || vVisible) + { + this._list._onkeyinput(e); + + var vSelected = this._manager.getSelectedItem(); + + if (!vVisible) + { + this.setSelected(vSelected); + } + else if (vSelected) + { + this._field.setValue(vSelected.getLabel()); + } + } +}; + + + +/* +--------------------------------------------------------------------------- + GLOBAL BLUR/FOCUS HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onwindowblur = qx.Proto._testClosePopup; + + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._visualizeBlur = function() +{ + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (qx.core.Client.getInstance().isMshtml()) + { + if (this.getEnableElementFocus() && !this.getFocusRoot().getFocusedChild()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().blur(); + } + else + { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + else + { + if (this.getEnableElementFocus()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().blur(); + } + else if (!this.getFocusRoot().getFocusedChild()) + { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() +{ + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().focus(); + this.getField()._ontabfocus(); + } + else + { + this.getElement().focus(); + } + } + catch(ex) {}; + } + + this.addState("focused"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + this.removeEventListener("keyinput", this._onkeyinput); + + // ************************************************************************ + // DOCUMENT EVENTS + // ************************************************************************ + var vDoc = qx.ui.core.ClientDocument.getInstance(); + vDoc.removeEventListener("windowblur", this._onwindowblur, this); + + if (this._popup) + { + this._popup.removeEventListener("appear", this._onpopupappear, this); + if (!qx.core.Object._disposeAll) { + this._popup.setParent(null); + // If this is not a page unload, we have to reset the parent. Otherwise, + // disposing a ComboBox that was clicked at least once would mean that + // the popup is still referenced by the parent. When an application + // repeatedly creates and disposes ComboBoxes, this would mean a memleak + // (and it would also mess with other things like focus management). + } + this._popup.dispose(); + this._popup = null; + } + + if (this._list) + { + this._list.dispose(); + this._list = null; + } + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + if (this._field) + { + this._field.removeEventListener("input", this._oninput, this); + this._field.dispose(); + this._field = null; + } + + if (this._button) + { + this._button.dispose(); + this._button = null; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js new file mode 100644 index 0000000000..03004689af --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js @@ -0,0 +1,1037 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * David Perez Carmona (david-perez), based on qx.ui.form.ComboBox + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_comboboxex) +#require(qx.ui.table.Table) +#embed(qx.widgettheme/arrows/down.gif) +#embed(qx.icontheme/16/actions/edit-find.png) +#embed(qx.icontheme/16/actions/dialog-ok.png) +#embed(qx.icontheme/16/actions/dialog-cancel.png) + +************************************************************************ */ + +/** + * An enhanced combo-box for qooxdoo. + * + * <p>Features:</p> + * <ul> + * <li>Editable text field</li> + * <li>Complete key-navigation</li> + * <li>Mouse wheel navigation</li> + * <li>Multicolumn display in list</li> + * <li>If more than one column, headers are automatically shown</li> + * <li>Can show the ID and/or description of each list item</li> + * <li>Automatically calculating needed width</li> + * <li>Popup list always shows full contents, and can be wider than text field</li> + * <li>Search values through popup dialog</li> + * <li>Internationalization support of messages</li> + * </ul> + * <p>Pending features:</p> + * <ul> + * <li>Images inside the list</li> + * <li>Autocomplete on key input</li> + * </ul> + * + * @event beforeInitialOpen {qx.event.type.Event} + */ +qx.OO.defineClass('qx.ui.form.ComboBoxEx', qx.ui.layout.HorizontalBoxLayout, function() { + qx.ui.layout.HorizontalBoxLayout.call(this); + + // ************************************************************************ + // POPUP + // ************************************************************************ + var p = this._popup = new qx.ui.popup.Popup; + p.setAppearance('combo-box-ex-popup'); + + // ************************************************************************ + // LIST + // ************************************************************************ + this._createList([ this.tr("ID"), this.tr("Description") ]); + + // ************************************************************************ + // FIELD + // ************************************************************************ + var f = this._field = new qx.ui.form.TextField; + f.setAppearance('combo-box-ex-text-field'); + f.addEventListener("input", this._oninput, this); + this.add(f); + this.setEditable(false); + + // ************************************************************************ + // BUTTON + // ************************************************************************ + + // Use qx.ui.basic.Atom instead of qx.ui.form.Button here to omit the registration + // of the unneeded and complex button events. + var b = this._button = new qx.ui.basic.Atom(null, "widget/arrows/down.gif"); + b.set({ + appearance: "combo-box-button", + tabIndex: -1 + }); + this.add(b); + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTabIndex(1); + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mousewheel", this._onmousewheel); + this.addEventListener("dblclick", function() { + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + }); + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + + // ************************************************************************ + // WIDGET STATE EVENTS + // ************************************************************************ + this.addEventListener("beforeDisappear", this._testClosePopup); + + // ************************************************************************ + // CHILDREN EVENTS + // ************************************************************************ + this._popup.addEventListener("appear", this._onpopupappear, this); +}); + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "combo-box-ex" }); + +/*!Is the text field component editable or the user can only select from the list?*/ +qx.OO.addProperty({ name: "editable", type: "boolean", getAlias: "isEditable" }); + +/*!0 based. -1 means no selected index. It retrieves always the value column of the selection, not the description.*/ +qx.OO.addProperty({ name: "value", type : "string" }); + +/*!How many items to transverse with PageUp and PageDn.*/ +qx.OO.addProperty({ name: "pagingInterval", type: "number", defaultValue: 10 }); + +/*!Show the ID column (column 0) of the selection data?*/ +qx.OO.addProperty({ name: "idColumnVisible", type: "boolean", getAlias: "isIdColumnVisible", defaultValue: false }); + +/*!Only used when editable is false. It determines what to show in the text field of the combo box.*/ +qx.OO.addProperty({ name: "showOnTextField", type: "string", defaultValue: 'description', possibleValues : [ 'description', 'idAndDescription' ] }); + +/*!Only used when editable is false and showOnTextField=='idAndDescription'.*/ +qx.OO.addProperty({ name: "idDescriptionSeparator", type: "string", defaultValue: '- ' }); + +/*!Ensures that always an item is selected (in case the selection isn't empty). Only used when editable is false.*/ +qx.OO.addProperty({ name: 'ensureSomethingSelected', type: "boolean", defaultValue: true }); + +/*!Allow the search dialog when double clicking the combo, or pressing special keys?.*/ +qx.OO.addProperty({ name: 'allowSearch', type: "boolean", defaultValue: true }); + +/*!Maximum number of visible rows in the popup list.*/ +qx.OO.addProperty({ name: 'maxVisibleRows', type: "number", defaultValue: 10 }); + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPopup = function() { + return this._popup; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.getField = function() { + return this._field; +} + +qx.Proto.getButton = function() { + return this._button; +} + +qx.Proto._getComboSetting = function(key) { + return qx.Settings.getValueOfClass('qx.ui.form.ComboBoxEx', key); +} + +/**Gets the current selected row of the selection. + * @return null if nothing selected or an array*/ +qx.Proto.getSelectedRow = function() { + var ind = this.getSelectedIndex(); + return ind < 0 ? null : this._model.getData()[ind]; +} + +/**Creates the list component.*/ +qx.Proto._createList = function(columns) { + this._model = new qx.ui.table.SimpleTableModel; + // Default column titles + this._model.setColumns(columns); + var l = this._list = new qx.ui.table.Table(this._model); + l.setFocusedCell = function() {} + l.setAppearance('combo-box-ex-list'); + // We receive this: Modification of property "keepFirstVisibleRowComplete" failed with exception: TypeError - vCurrentChild has no properties or + // this: Modification of property "keepFirstVisibleRowComplete" failed with exception: TypeError - this.getParent() has no properties + l.forceKeepFirstVisibleRowComplete(false); + var selMan = l._getSelectionManager(); + var oldHandle = selMan.handleMouseUp, me = this; + selMan.handleMouseUp = function(vItem, e) { + oldHandle.apply(selMan, arguments); + if (e.isLeftButtonPressed()) { + me._testClosePopup(); + } + } + this._modifyIdColumnVisible(this.getIdColumnVisible()); + this._manager = l.getSelectionModel(); + this._manager.addEventListener('changeSelection', this._onChangeSelection, this); + // Avoid deselection from user + this._manager.removeSelectionInterval = function() {}; + this._manager.setSelectionMode(qx.ui.table.SelectionModel.SINGLE_SELECTION); + this._popup.add(l); + // Invalidate calculation of column widths + delete this._calcDimensions; +} + + +/* +--------------------------------------------------------------------------- + PSEUDO-PROPERTIES +--------------------------------------------------------------------------- +*/ + +/**Sets the header for each column. + * @param columns {String[]}*/ +qx.Proto.setColumnHeaders = function(columns) { + if (!this._list || columns.length != this._model.getColumnCount()) { + if (this._list) { + var data = this._model.getData(); + this._list.setParent(null); + this._list.dispose(); + this._list = null; + } + this._createList(columns); + if (data && data.length) { + this._model.setData(data); + } + } else { + this._model.setColumns(columns); + this._list.getTableColumnModel().init(columns.length); + delete this._calcDimensions; + } + this._modifyIdColumnVisible(this.getIdColumnVisible()); +} + +/**Getter for {@link #setColumnHeaders}. + * @return {String[]}*/ +qx.Proto.getColumnHeaders = function(propVal) { + var cols = []; + cols.length = this._model.getColumnCount(); + for (var col = 0; col < cols.length; col++) { + cols[col] = this._model.getColumnName(col); + } + return cols; +} + +/**Sets the list of selectable items. + * @param data {var[][]} Array of values. Its value is an array, with the following info:<ul>. + * <li>Column 0 represents the ID, i.e. the value that is stored internally and used by the app.</li> + * <li>Column 1 represents the description, the text that the end user normally sees.</li> + * <li>Columns > 1 will also be shown in the popup list, it you have set the appropiate column headers with {@link #setColumnHeaders}.</li> + * </ul>*/ +qx.Proto.setSelection = function(data) { + // Invalidate calculation of column widths + delete this._calcDimensions; + this._model.setData(data); + // Try to preserve currently selected value + if (!this.getEditable()) { + this._modifyValue(this.getValue()); + } +} + +/**Getter for {@link #setSelection}. + * @return {Array}*/ +qx.Proto.getSelection = function() { + return this._model.getData(); +} + +/**Sets the index of the currently selected item in the list. + * @param index {number} -1 means no selected index*/ +qx.Proto.setSelectedIndex = function(index) { + var items = this.getSelection().length; + if (items >= 0) { + if (index < 0 && !this.getEditable() && this.getEnsureSomethingSelected()) { + index = 0; + } + if (index >= 0) { + index = qx.lang.Number.limit(index, 0, items-1); + this._manager.setSelectionInterval(index, index); + if (this._popup.isSeeable()) { + this._list.scrollCellVisible(0, index); + } + } else { + this._manager.clearSelection(); + } + } + return true; +} + +/**Getter for {@link #setSelectedIndex}.*/ +qx.Proto.getSelectedIndex = function() { + var index = this._manager.getAnchorSelectionIndex(); + return this._manager.isSelectedIndex(index) ? index:-1; +} + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyShowOnTextField = function(propVal) { + if (!this.getEditable()) { + this.setSelectedIndex(this.getSelectedIndex()); + delete this._calcDimensions; // Invalidate this._neededTextFieldWidth + } + return true; +} + +qx.Proto._modifyMaxVisibleRows = function() { + delete this._calcDimensions; // Invalidate this._list.height + return true; +} + +qx.Proto._checkIdDescriptionSeparator = function(propVal) { + // For measuring widths, it is better to replace spaces with non-breakable spaces + return String(propVal).replace(/ /g, '\u00A0') +} + +qx.Proto._modifyIdDescriptionSeparator = function(propVal) { + if (!this.getEditable() && this.getShowOnTextField() == 'idAndDescription') { + this.setSelectedIndex(this.getSelectedIndex()); + delete this._calcDimensions; // Invalidate this._neededTextFieldWidth + } + return true; +} + +qx.Proto._modifyIdColumnVisible = function(propVal) { + this._list.getTableColumnModel().setColumnVisible(0, propVal); + delete this._calcDimensions; + return true; +} + +qx.Proto._modifyEditable = function(propValue/*, propOldValue, propData*/) { + var f = this._field; + f.setReadOnly(!propValue); + f.setCursor(propValue ? null : "default"); + f.setSelectable(propValue); + return true; +} + +qx.Proto._modifyValue = function(propValue/*, propOldValue, propData*/) { + this._fromValue = true; + + var values = this._model.getData(); + var i = -1; + if (propValue != null) { + for (var i = 0; i < values.length; i++) { + if (propValue == values[i][0]) { + break; + } + } + if (i == values.length) { + i = -1; + } + } + if (this.getEditable()) { + this._field.setValue(propValue); + } + // only do this if we called setValue separately + // and not from the property "selected". + if (!this._fromSelected) { + this.setSelectedIndex(i); + } + // reset hint + delete this._fromValue; + return true; +} + +qx.Proto._modifyEnabled = function(propValue/*, propOldValue, propData*/) { + if (this._button) { + this._button.setEnabled(propValue); + } + if (this._field) { + this._field.setEnabled(propValue); + } + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.apply(this, arguments); +} + + +/* +--------------------------------------------------------------------------- + POPUP HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._oldSelected = null; + +qx.Proto._openPopup = function() { + if (this.isSearchInProgress()) { + return; + } + var p = this._popup; + p.setAutoHide(false); + var el = this.getElement(); + if (!p.isCreated()) { + this.createDispatchEvent("beforeInitialOpen"); + } + if (!this.getSelection().length) { + return; + } + p.positionRelativeTo(el, 1, qx.html.Dimension.getBoxHeight(el)); + this._calculateDimensions(); + p.setParent(this.getTopLevelWidget()); + p.auto(); + p.show(); + this._oldSelected = this.getSelectedIndex(); + window.setInterval(function() { + p.setAutoHide(true); + }, 0); +} + +/**Hide the popup list.*/ +qx.Proto._closePopup = function() { + this._popup.hide(); +} + +/**Hide the popup list only when needed.*/ +qx.Proto._testClosePopup = function() { + if (this._popup.isSeeable()) { + this._closePopup(); + } +} + +/**Toggle the visibility of the popup list.*/ +qx.Proto._togglePopup = function() { + this._popup.isSeeable() ? this._closePopup() : this._openPopup(); +} + +/* +--------------------------------------------------------------------------- + DIMENSIONING +--------------------------------------------------------------------------- +*/ + +/**Sizes the width of the text field component to the needed value to show any selection item.*/ +qx.Proto.sizeTextFieldToContent = function() { + this._calculateDimensions(); + this._field.setWidth(this._neededTextFieldWidth); +} + +/**Calculates the needed dimensions for the text field and list components*/ +qx.Proto._calculateDimensions = function() { + if (this._calcDimensions) { + // Already calculated + return; + } + var data = this.getSelection(); + var cols = this.getColumnHeaders(), nCols = cols.length; + var columnWidths = []; + this._neededTextFieldWidth = 0; + columnWidths.length = cols.length; + for (var col = 0; col < cols.length; col++) { + columnWidths[col] = 0; + } + var withDescript = this.getShowOnTextField() == 'idAndDescription'; + for (var row = 0, rows = Math.min(data.length, 50); row < rows; row++) { + var r = data[row], wi0, wi1; + for (col = 0; col < nCols; col++) { + var wi = this._getTextWidth(r[col]); + if (col == 0) { + wi0 = wi; + } else if (col == 1) { + wi1 = wi; + } + columnWidths[col] = Math.max(wi, columnWidths[col]); + } + this._neededTextFieldWidth = Math.max(this._neededTextFieldWidth, + wi1+(withDescript ? wi0:0)); + } + if (this.getShowOnTextField() == 'idAndDescription') { + this._neededTextFieldWidth += this._getTextWidth(this.getIdDescriptionSeparator()); + } + this._neededTextFieldWidth += 8; /*Extra margins*/ + var maxRows = this.getMaxVisibleRows(), + // Only assign room for the vertical scrollbar when needed + width = data.length > maxRows ? (new qx.ui.core.ScrollBar)._getScrollBarWidth():0, + colModel = this._list.getTableColumnModel(), + countVisible = 0; + + // ##Only show headers if we have more than 1 column visible + for (col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + countVisible++; + } + } + var hasHeaders = countVisible > 1; + this._list.getPaneScroller(0).getHeader().setHeight(hasHeaders ? 'auto' : 1); + + // ##Size each column + for (col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + var w = columnWidths[col]; + if (hasHeaders) { + w = Math.max(w, this._getTextWidth(cols[col])); + } + w += 8; + this._list.setColumnWidth(col, w); + width += w; + } + } + + // ##Final width and height + this._list.set({ + width: width, + height: this._list.getRowHeight()* + Math.min(maxRows, (hasHeaders ? 1:0)+data.length)+2+(hasHeaders ? 2:0) + }); + // This denotes dimensions are already calculated + this._calcDimensions = true; +} + +/**Calculates the width of the given text. + * The default font is used. + * @return {Integer}*/ +qx.Proto._getTextWidth = function(text) { + var lab = new qx.ui.basic.Label(text); + var res = lab.getPreferredBoxWidth(); + lab.dispose(); + return res; +} + + +/* +--------------------------------------------------------------------------- + SEARCHING +--------------------------------------------------------------------------- +*/ + +/**Does this combo have the searched dialog open?*/ +qx.Proto.isSearchInProgress = function() { + return !this._popup.contains(this._list); +} + +/**Searches the given text. Called from the search dialog. + * @param startIndex {number} Start index, 0 based + * @param txt {String} Text to find + * @param caseSens {Boolean} Case sensivity flag.*/ +qx.Proto._search = function(startIndex, txt, caseSens) { + if (txt == null || !txt.length) { + return; + } + var row = startIndex, + nCols = this._model.getColumnCount(), + nRows = this.getSelection().length, + data = this._model.getData(); + if (!caseSens) { + txt = txt.toLowerCase(); + } + var colModel = this._list.getTableColumnModel(); + while (true) { + var dataRow = data[row]; + if (dataRow) { + for (var col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + var txtCol = dataRow[col]; + if (!caseSens) { + txtCol = txtCol.toLowerCase(); + } + if (txtCol.indexOf(txt) >= 0) { + this._manager.setSelectionInterval(row, row); + this._list.scrollCellVisible(1, row); + return; + } + } + } + } + row = (row+1)% nRows; + if (row == startIndex) { + break; + } + } +} + +/**Opens a popup search dialog, useful when the combo has a lot of items. + * This dialog is triggered by double clicking the combo, pressing F3 or Ctrl+F.*/ +qx.Proto.openSearchDialog = function() { + var sel = this.getSelection(); + if (!sel || !sel.length || this.isSearchInProgress()) { + return; + } + this._testClosePopup(); + + var me = this, + oldSelectedIndex = this.getSelectedIndex(), + startIndex = oldSelectedIndex; + + //###searchField + function search() { + me._search(startIndex, searchField.getComputedValue(), checkCase.isChecked()); + } + var searchField = new qx.ui.form.TextField; + searchField.set({ + minWidth: this._field.getWidth(), + width: '100%' + }); + searchField.addEventListener("input", function() { + search(); + }); + + //###checkCase + var checkCase = new qx.ui.form.CheckBox(this.tr("Case sensitive")); + checkCase.set({ + horizontalAlign: 'center', + marginBottom: 4 + }); + + //###vbox + var vbox = new qx.ui.layout.VerticalBoxLayout; + vbox.set({ + spacing: 6, + horizontalChildrenAlign: 'center', + height: '100%' + }); + vbox.auto(); + vbox.add(searchField, checkCase); + + //###list, we reuse the same list in the popup + this._calculateDimensions(); + var border = qx.renderer.border.BorderPresets.getInstance().inset; + var newListSettings = { + /*minHeight: border.getTopWidth()+this._list.getHeight()+border.getBottomWidth(), + height: '1*',*/ + height: border.getTopWidth()+this._list.getHeight()+border.getBottomWidth(), + width: border.getLeftWidth()+this._list.getWidth()+border.getRightWidth(), + border: border, + parent: vbox + }; + // Save old list settings + var oldListSettings = {}; + for (var prop in newListSettings) { + oldListSettings[prop] = this._list[qx.OO.getter[prop]](); + } + this._list.set(newListSettings); + + //###buttons + var butNext = new qx.ui.form.Button('', 'icon/16/actions/edit-find.png'); + butNext.set({ + toolTip: new qx.ui.popup.ToolTip(this.tr("Search next occurrence")) + }); + butNext.addEventListener("execute", function() { + startIndex = (this.getSelectedIndex()+1) % sel.length; + search(); + }, this); + + var butOk = new qx.ui.form.Button('', 'icon/16/actions/dialog-ok.png'); + butOk.addEventListener('execute', function() { + oldSelectedIndex = null; + win.close(); + }, this); + + var butCancel = new qx.ui.form.Button('', 'icon/16/actions/dialog-cancel.png'); + butCancel.addEventListener('execute', function() { + win.close(); + }, this); + + var butBox = new qx.ui.layout.VerticalBoxLayout; + butBox.auto(); + butBox.set({ + spacing: 10 + }); + butBox.add(butNext, butOk, butCancel); + + //###hbox + var hbox = new qx.ui.layout.BoxLayout; + hbox.auto(); + hbox.setPadding(10); + hbox.set({ + spacing: 8, + minHeight: 'auto', + height: '100%' + }); + hbox.add(vbox, butBox); + + //###Window + var win = new qx.ui.window.Window(this.tr("Search items in list"), 'icon/16/actions/edit-find.png'); + win.add(hbox); + win.positionRelativeTo(this); + win.set({ + autoHide: true, + allowMaximize: false, + showMaximize: false, + allowMinimize: false, + showMinimize: false + }); + win.addEventListener("appear", function() { + searchField.focus(); + }); + win.addEventListener("disappear", function() { + if (oldSelectedIndex != null) { + // Hit Cancel button + this.setSelectedIndex(oldSelectedIndex); + } + this._list.set(oldListSettings); + this.focus(); + }, this); + win.addEventListener("keydown", function(e) { + switch (e.getKeyIdentifier()) { + case "Enter": + butOk.createDispatchEvent('execute'); + break; + case "Escape": + butCancel.createDispatchEvent('execute'); + break; + case "F3": + butNext.createDispatchEvent('execute'); + break; + default: + return; + } + e.preventDefault(); + }, this); + win.auto(); + win.addToDocument(); + win.open(); +} + +/* +--------------------------------------------------------------------------- + OTHER EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onChangeSelection = function(e) { + this._fromSelected = true; + + // only do this if we called setValue separately + // and not from the event "input". + if (!this._fromInput) { + var index = this.getSelectedIndex(); + if (index >= 0) { + var row = this._model.getData()[index]; + } + if (row || !this.getEditable()) { + this.setValue(row && row[0]); + } + // In case of editable, this.setValue() already calls this._field.setValue() + if (!this.getEditable()) { + var val = ""; + if (row) { + val = this.getShowOnTextField() == 'description' ? + row[1] : + (row[0] != null && row[0] != '' ? row[0] + this.getIdDescriptionSeparator() + row[1]:row[1]); + } + this._field.setValue(val); + } + } + // reset hint + delete this._fromSelected; +} + +qx.Proto._onpopupappear = function(e) { + var index = this.getSelectedIndex(); + if (index >= 0) { + this._list.scrollCellVisible(0, index); + } +} + +qx.Proto._oninput = function(e) { + // Hint for modifier + this._fromInput = true; + this.setValue(this._field.getComputedValue()); + delete this._fromInput; +} + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) { + switch(e.getTarget()) { + case this._field: + if (this.getEditable()) { + break; + } + // no break here + case this._button: + this._button.addState("pressed"); + this._togglePopup(); + // Assure we receive the mouse up event + this.setCapture(true); + break; + } +} + +qx.Proto._onmouseup = function(e) { + switch(e.getTarget()) { + case this._field: + if (this.getEditable()) { + break; + } + // no break here + default: + this._button.removeState("pressed"); + break; + } + this.setCapture(false); +} + +qx.Proto._onmousewheel = function(e) { + if (!this._popup.isSeeable()) { + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()+(e.getWheelDelta() < 0 ? -1:1))); + } +} + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) { + var vVisible = this._popup.isSeeable(); + + switch (e.getKeyIdentifier()) { + case "Enter": + if (vVisible) { + this._closePopup(); + this.setFocused(true); + } else { + this._openPopup(); + } + break; + + case "Escape": + if (vVisible) { + this.setSelectedIndex(this._oldSelected); + this._closePopup(); + this.setFocused(true); + } + break; + + case "Home": + this.setSelectedIndex(0); + break; + + case "End": + var items = this.getSelection().length; + if (items) { + this.setSelectedIndex(items-1); + } + break; + + case "Down": + if (e.isAltPressed()) { + this._togglePopup(); + } + break; + + case "F3": + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + break; + + case "F": + if (e.isCtrlPressed()) { + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + break; + } + return; + + default: + if (vVisible) { + this._list.dispatchEvent(e); + } + return; + } + e.preventDefault(); +} + + +qx.Proto._onkeypress = function(e) { + var vVisible = this._popup.isSeeable(); + + switch (e.getKeyIdentifier()) { + case "Up": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()-1)); + break; + + case "Down": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()+1)); + break; + + case "PageUp": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()-this.getPagingInterval())); + break; + + case "PageDown": + this.setSelectedIndex(this.getSelectedIndex()+this.getPagingInterval()); + break; + + default: + if (vVisible) { + this._list.dispatchEvent(e); + } + return; + } + e.preventDefault(); + + if (!this.isEditable() && this._list.isSeeable()) { + this._list.dispatchEvent(e); + } + +} + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._visualizeBlur = function() { + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (qx.core.Client.getInstance().isMshtml()) { + if (this.getEnableElementFocus() && !this.getFocusRoot().getFocusedChild()) { + try { + if (this.getEditable()) { + this.getField().getElement().blur(); + } else { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } else { + if (this.getEnableElementFocus()) { + try { + if (this.getEditable()) { + this.getField().getElement().blur(); + } else if (!this.getFocusRoot().getFocusedChild()) { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() { + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) { + try { + if (this.getEditable()) { + this.getField().getElement().focus(); + this.getField()._ontabfocus(); + } else { + this.getElement().focus(); + } + } catch(ex) { + } + } + this.addState("focused"); + return true; +} + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + this._model = null; + if (this._manager) { + this._manager.removeEventListener('changeSelection', this._onChangeSelection); + this._manager = null; + } + if (this._list) { + this._list.dispose(); + this._list = null; + } + if (this._popup) { + this._popup.removeEventListener("appear", this._onpopupappear, this); + this._popup.dispose(); + this._popup = null; + } + if (this._field) { + if (this.getEditable()) { + this._field.removeEventListener("input", this._oninput, this); + } + this._field.dispose(); + this._field = null; + } + if (this._button) { + this._button.dispose(); + this._button = null; + } + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js new file mode 100644 index 0000000000..32e269e55a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js @@ -0,0 +1,95 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.InputCheckSymbol", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setTagName("input"); + this.setSelectable(false); + + if (qx.core.Client.getInstance().isMshtml()) + { + // Take control over size of element (mshtml) + this.setWidth(13); + this.setHeight(13); + } + else if (qx.core.Client.getInstance().isGecko()) + { + // Remove gecko default margin + this.setMargin(0); + } + + // we need to be sure that the dom protection of this is added + this.forceTabIndex(1); + this.setTabIndex(-1); + this.setChecked(false); +}); + +qx.OO.addProperty({ name : "name", type : "string", impl : "apply" }); +qx.OO.addProperty({ name : "value", impl : "apply" }); +qx.OO.addProperty({ name : "type", impl : "apply" }); +qx.OO.addProperty({ name : "checked", type : "boolean", impl : "apply", getAlias : "isChecked" }); + +qx.Proto._modifyApply = function(propValue, propOldValue, propData) { + return this.setHtmlProperty(propData.name, propValue); +} + +qx.Proto.getPreferredBoxWidth = function() { + return 13; +} + +qx.Proto.getPreferredBoxHeight = function() { + return 13; +} + +qx.Proto.getBoxWidth = qx.Proto.getPreferredBoxWidth; +qx.Proto.getBoxHeight = qx.Proto.getPreferredBoxHeight; + +qx.Proto.getInnerWidth = qx.Proto.getPreferredBoxWidth; +qx.Proto.getInnerHeight = qx.Proto.getPreferredBoxHeight; + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._afterAppear = function() + { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + var vElement = this.getElement(); + vElement.checked = this.getChecked(); + + if (!this.getEnabled()) { + vElement.disabled = true; + } + } +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + propValue ? this.removeHtmlAttribute("disabled") : this.setHtmlAttribute("disabled", "disabled"); + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/List.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/List.js new file mode 100644 index 0000000000..23f4051023 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/List.js @@ -0,0 +1,385 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.List", qx.ui.layout.VerticalBoxLayout, +function() +{ + qx.ui.layout.VerticalBoxLayout.call(this); + + + // ************************************************************************ + // INITILISIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.SelectionManager(this); + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setSelectable(false); + this.setTabIndex(1); + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyinput", this._onkeyinput); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list" }); + +qx.OO.addProperty({ name : "enableInlineFind", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "markLeadingItem", type : "boolean", defaultValue : false }); + +qx.Proto._pressedString = ""; + + + + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getListItemTarget = function(vItem) +{ + while (vItem != null && vItem.getParent() != this) { + vItem = vItem.getParent(); + } + + return vItem; +} + +qx.Proto.getSelectedItem = function() { + return this.getSelectedItems()[0]; +} + +qx.Proto.getSelectedItems = function() { + return this._manager.getSelectedItems(); +} + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseOver(vItem, e); + } +} + +qx.Proto._onmousedown = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseDown(vItem, e); + } +} + +qx.Proto._onmouseup = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseUp(vItem, e); + } +} + +qx.Proto._onclick = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleClick(vItem, e); + } +} + +qx.Proto._ondblclick = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleDblClick(vItem, e); + } +} + + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + // Execute action on press <ENTER> + if (e.getKeyIdentifier() == "Enter" && !e.isAltPressed()) + { + var items = this.getSelectedItems(); + var currentItem; + + for (var i=0; i<items.length; i++) { + items[i].createDispatchEvent("action"); + } + } +}; + + +qx.Proto._onkeypress = function(e) +{ + // Give control to selectionManager + this._manager.handleKeyPress(e); +}; + + +qx.Proto._lastKeyPress = 0; + +qx.Proto._onkeyinput = function(e) +{ + if (!this.getEnableInlineFind()) { + return; + } + + // Reset string after a second of non pressed key + if (((new Date).valueOf() - this._lastKeyPress) > 1000) { + this._pressedString = ""; + } + + // Combine keys the user pressed to a string + this._pressedString += String.fromCharCode(e.getCharCode()); + + // Find matching item + var matchedItem = this.findString(this._pressedString, null); + + if (matchedItem) + { + var oldVal = this._manager._getChangeValue(); + + // Temporary disable change event + var oldFireChange = this._manager.getFireChange(); + this._manager.setFireChange(false); + + // Reset current selection + this._manager._deselectAll(); + + // Update manager + this._manager.setItemSelected(matchedItem, true); + this._manager.setAnchorItem(matchedItem); + this._manager.setLeadItem(matchedItem); + + // Scroll to matched item + matchedItem.scrollIntoView(); + + // Recover event status + this._manager.setFireChange(oldFireChange); + + // Dispatch event if there were any changes + if (oldFireChange && this._manager._hasChanged(oldVal)) { + this._manager._dispatchChange(); + } + } + + // Store timestamp + this._lastKeyPress = (new Date).valueOf(); + e.preventDefault(); +} + + + + +/* +--------------------------------------------------------------------------- + FIND SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._findItem = function(vUserValue, vStartIndex, vType) +{ + var vAllItems = this.getChildren(); + + // If no startIndex given try to get it by current selection + if (vStartIndex == null) + { + vStartIndex = vAllItems.indexOf(this.getSelectedItem()); + + if (vStartIndex == -1) { + vStartIndex = 0; + } + } + + var methodName = "matches" + vType; + + // Mode #1: Find all items after the startIndex + for (var i=vStartIndex; i<vAllItems.length; i++) { + if (vAllItems[i][methodName](vUserValue)) { + return vAllItems[i]; + } + } + + // Mode #2: Find all items before the startIndex + for (var i=0; i<vStartIndex; i++) { + if (vAllItems[i][methodName](vUserValue)) { + return vAllItems[i]; + } + } + + return null; +} + +qx.Proto.findString = function(vText, vStartIndex) { + return this._findItem(vText, vStartIndex || 0, "String"); +} + +qx.Proto.findStringExact = function(vText, vStartIndex) { + return this._findItem(vText, vStartIndex || 0, "StringExact"); +} + +qx.Proto.findValue = function(vText, vStartIndex) { + return this._findItem(vText, vStartIndex || 0, "Value"); +} + +qx.Proto.findValueExact = function(vText, vStartIndex) { + return this._findItem(vText, vStartIndex || 0, "ValueExact"); +} + + + + + + +/* +--------------------------------------------------------------------------- + SORT SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._sortItemsCompare = function(a, b) { + return a.key < b.key ? -1 : a.key == b.key ? 0 : 1; +} + +qx.Proto.sortItemsByString = function(vReverse) +{ + var sortitems = []; + var items = this.getChildren(); + + for(var i=0, l=items.length; i<l; i++) { + sortitems[i] = { key : items[i].getLabel(), item : items[i] } + } + + sortitems.sort(this._sortItemsCompare); + if (vReverse) { + sortitems.reverse(); + } + + for(var i=0; i<l; i++) { + this.addAt(sortitems[i].item, i); + } +} + +qx.Proto.sortItemsByValue = function(vReverse) +{ + var sortitems = []; + var items = this.getChildren(); + + for(var i=0, l=items.length; i<l; i++) { + sortitems[i] = { key : items[i].getValue(), item : items[i] } + } + + sortitems.sort(this._sortItemsCompare); + if (vReverse) { + sortitems.reverse(); + } + + for(var i=0; i<l; i++) { + this.addAt(sortitems[i].item, i); + } +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("click", this._onclick); + this.removeEventListener("dblclick", this._ondblclick); + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + this.removeEventListener("keyinput", this._onkeyinput); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ListItem.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ListItem.js new file mode 100644 index 0000000000..4d8bc34977 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/ListItem.js @@ -0,0 +1,117 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/** + * @event action {qx.event.type.Event} (Fired by {@link qx.ui.form.List}) + */ +qx.OO.defineClass("qx.ui.form.ListItem", qx.ui.basic.Atom, +function(vText, vIcon, vValue) +{ + qx.ui.basic.Atom.call(this, vText, vIcon); + + if (vValue != null) { + this.setValue(vValue); + } + + + // ************************************************************************ + // EVENT LISTENER + // ************************************************************************ + this.addEventListener("dblclick", this._ondblclick); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-item" }); +qx.OO.addProperty({ name : "value" }); + + + + + +/* +--------------------------------------------------------------------------- + STATE +--------------------------------------------------------------------------- +*/ + +qx.Proto.handleStateChange = function() +{ + if (this.hasState("lead")) + { + this.setStyleProperty("MozOutline", "1px dotted invert"); + this.setStyleProperty("outline", "1px dotted invert"); + } + else + { + this.removeStyleProperty("MozOutline"); + this.setStyleProperty("outline", "0px none"); + } +} + +// Remove default outline focus border +qx.Proto._applyStateStyleFocus = function(vStates) {}; + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.matchesString = function(vText) { + return vText != "" && this.getLabel().toLowerCase().indexOf(vText.toLowerCase()) == 0; +} + +qx.Proto.matchesStringExact = function(vText) { + return vText != "" && this.getLabel().toLowerCase() == String(vText).toLowerCase(); +} + +qx.Proto.matchesValue = function(vText) { + return vText != "" && this.getValue().toLowerCase().indexOf(vText.toLowerCase()) == 0; +} + +qx.Proto.matchesValueExact = function(vText) { + return vText != "" && this.getValue().toLowerCase() == String(vText).toLowerCase(); +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._ondblclick = function(e) +{ + var vCommand = this.getCommand(); + if (vCommand) { + vCommand.execute(); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/PasswordField.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/PasswordField.js new file mode 100644 index 0000000000..9c0bc3b006 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/PasswordField.js @@ -0,0 +1,33 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.PasswordField", qx.ui.form.TextField, +function(vText) +{ + qx.ui.form.TextField.call(this, vText); + + this.setHtmlProperty("type", "password"); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RadioButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RadioButton.js new file mode 100644 index 0000000000..d17bd7046b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RadioButton.js @@ -0,0 +1,187 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.RadioButton", qx.ui.form.CheckBox, +function(vText, vValue, vName, vChecked) { + qx.ui.form.CheckBox.call(this, vText, vValue, vName, vChecked); + + this.addEventListener("keypress", this._onkeypress); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons +*/ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + + + + + +/* +--------------------------------------------------------------------------- + ICON HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.INPUT_TYPE = "radio"; + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setChecked(propValue); + } + + var vManager = this.getManager(); + if (vManager) { + vManager.handleItemChecked(this, propValue); + } + + return true; +} + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setName(propValue); + } + + if (this.getManager()) { + this.getManager().setName(propValue); + } + + return true; +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + if (this.isCreated() && this._iconObject) { + this._iconObject.setValue(propValue); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + if (e.getKeyIdentifier() == "Enter" && !e.isAltPressed()) { + this.setChecked(true); + } +}; + + +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Left": + case "Up": + qx.event.handler.FocusHandler.mouseFocus = false; + // we want to have a focus border when using arrows to select + qx.event.handler.FocusHandler.mouseFocus = false; + + return this.getManager() ? this.getManager().selectPrevious(this) : true; + + case "Right": + case "Down": + // we want to have a focus border when using arrows to select + qx.event.handler.FocusHandler.mouseFocus = false; + + return this.getManager() ? this.getManager().selectNext(this) : true; + } +}; + + +qx.Proto._onclick = function(e) { + this.setChecked(true); +} + +qx.Proto._onkeyup = function(e) +{ + if(e.getKeyIdentifier() == "Space") { + this.setChecked(true); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this.removeEventListener("keypress", this._onkeypress); + return qx.ui.form.CheckBox.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RepeatButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RepeatButton.js new file mode 100755 index 0000000000..bee201cf1f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/RepeatButton.js @@ -0,0 +1,129 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/** + * @event execute {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.form.RepeatButton", qx.ui.form.Button, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.form.Button.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + this._timer = new qx.client.Timer; + this._timer.setInterval(this.getInterval()); + this._timer.addEventListener("interval", this._oninterval, this); +}); + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "interval", type : "number", defaultValue : 100 }); +qx.OO.addProperty({ name : "firstInterval", type : "number", defaultValue : 500 }); + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + if (e.getTarget() != this || !e.isLeftButtonPressed()) { + return; + } + + this._executed = false; + + this._timer.setInterval(this.getFirstInterval()); + this._timer.start(); + + this.removeState("abandoned"); + this.addState("pressed"); +} + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + if (!this.hasState("abandoned")) + { + this.addState("over"); + + if (this.hasState("pressed") && !this._executed) { + this.execute(); + } + } + + this._timer.stop(); + + this.removeState("abandoned"); + this.removeState("pressed"); +} + +qx.Proto._oninterval = function(e) +{ + this._timer.stop(); + this._timer.setInterval(this.getInterval()); + this._timer.start(); + + this._executed = true; + this.createDispatchEvent("execute"); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._timer) + { + this._timer.stop(); + this._timer.dispose(); + this._timer = null; + } + + return qx.ui.form.Button.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Spinner.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Spinner.js new file mode 100644 index 0000000000..651c173c93 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/Spinner.js @@ -0,0 +1,694 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) +#embed(qx.widgettheme/arrows/up_small.gif) +#embed(qx.widgettheme/arrows/down_small.gif) + +************************************************************************ */ + +/** + * @event change {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.form.Spinner", qx.ui.layout.HorizontalBoxLayout, +function(vMin, vValue, vMax) +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTabIndex(-1); + + if (qx.core.Client.getInstance().isMshtml()) { + this.setStyleProperty("fontSize", "0px"); + } + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + this._manager = new qx.type.Range(); + + + // ************************************************************************ + // TEXTFIELD + // ************************************************************************ + this._textfield = new qx.ui.form.TextField; + this._textfield.setAppearance("spinner-field"); + this._textfield.setValue(String(this._manager.getValue())); + + this.add(this._textfield); + + + // ************************************************************************ + // BUTTON LAYOUT + // ************************************************************************ + this._buttonlayout = new qx.ui.layout.VerticalBoxLayout; + this._buttonlayout.setWidth("auto"); + this.add(this._buttonlayout); + + + // ************************************************************************ + // UP-BUTTON + // ************************************************************************ + this._upbutton = new qx.ui.basic.Image("widget/arrows/up_small.gif"); + this._upbutton.setAppearance("spinner-button-up"); + this._buttonlayout.add(this._upbutton); + + + // ************************************************************************ + // DOWN-BUTTON + // ************************************************************************ + this._downbutton = new qx.ui.basic.Image("widget/arrows/down_small.gif"); + this._downbutton.setAppearance("spinner-button-down"); + this._buttonlayout.add(this._downbutton); + + + // ************************************************************************ + // TIMER + // ************************************************************************ + this._timer = new qx.client.Timer(this.getInterval()); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + this.addEventListener("keypress", this._onkeypress, this); + this.addEventListener("keydown", this._onkeydown, this); + this.addEventListener("keyup", this._onkeyup, this); + this.addEventListener("mousewheel", this._onmousewheel, this); + + this._textfield.addEventListener("input", this._oninput, this); + this._textfield.addEventListener("blur", this._onblur, this); + this._upbutton.addEventListener("mousedown", this._onmousedown, this); + this._downbutton.addEventListener("mousedown", this._onmousedown, this); + this._manager.addEventListener("change", this._onchange, this); + this._timer.addEventListener("interval", this._oninterval, this); + + + // ************************************************************************ + // INITIALIZATION + // ************************************************************************ + + if(vMin != null) { + this.setMin(vMin); + } + + if(vMax != null) { + this.setMax(vMax); + } + + if(vValue != null) { + this.setValue(vValue); + } +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "spinner" }); + +/*! + The amount to increment on each event (keypress or mousedown). +*/ +qx.OO.addProperty({ name : "incrementAmount", type : "number", defaultValue : 1 }); + +/*! + The amount to increment on each event (keypress or mousedown). +*/ +qx.OO.addProperty({ name : "wheelIncrementAmount", type : "number", defaultValue : 1 }); + +/*! + The amount to increment on each pageup / pagedown keypress +*/ +qx.OO.addProperty({ name : "pageIncrementAmount", type : "number", defaultValue : 10 }); + +/*! + The current value of the interval (this should be used internally only). +*/ +qx.OO.addProperty({ name : "interval", type : "number", defaultValue : 100 }); + +/*! + The first interval on event based shrink/growth of the value. +*/ +qx.OO.addProperty({ name : "firstInterval", type : "number", defaultValue : 500 }); + +/*! + This configures the minimum value for the timer interval. +*/ +qx.OO.addProperty({ name : "minTimer", type : "number", defaultValue : 20 }); + +/*! + Decrease of the timer on each interval (for the next interval) until minTimer reached. +*/ +qx.OO.addProperty({ name : "timerDecrease", type : "number", defaultValue : 2 }); + +/*! + If minTimer was reached, how much the amount of each interval should growth (in relation to the previous interval). +*/ +qx.OO.addProperty({ name : "amountGrowth", type : "number", defaultValue : 1.01 }); + + +qx.Proto._modifyIncrementAmount = function(propValue, propOldValue, propData) +{ + this._computedIncrementAmount = propValue; + return true; +}; + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() { + return 50; +} + +qx.Proto._computePreferredInnerHeight = function() { + return 14; +} + + + + + +/* +--------------------------------------------------------------------------- + KEY EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeypress = function(e) +{ + var vIdentifier = e.getKeyIdentifier(); + + if (vIdentifier == "Enter" && !e.isAltPressed()) + { + this._checkValue(true, false, false); + this._textfield.selectAll(); + } + else + { + switch (vIdentifier) + { + case "Up": + case "Down": + + case "Left": + case "Right": + + case "Shift": + case "Control": + case "Alt": + + case "Escape": + case "Delete": + case "Backspace": + + case "Insert": + + case "Home": + case "End": + + case "PageUp": + case "PageDown": + + case "NumLock": + case "Tab": + break; + + default: + if (vIdentifier >= "0" && vIdentifier <= "9") { + return; + } + + e.preventDefault(); + } + } +} + +qx.Proto._onkeydown = function(e) +{ + var vIdentifier = e.getKeyIdentifier(); + + if (this._intervalIncrease == null) + { + switch(vIdentifier) + { + case "Up": + case "Down": + this._intervalIncrease = vIdentifier == "Up"; + this._intervalMode = "single"; + + this._resetIncrements(); + this._checkValue(true, false, false); + + this._increment(); + this._timer.startWith(this.getFirstInterval()); + + break; + + case "PageUp": + case "PageDown": + this._intervalIncrease = vIdentifier == "PageUp"; + this._intervalMode = "page"; + + this._resetIncrements(); + this._checkValue(true, false, false); + + this._pageIncrement(); + this._timer.startWith(this.getFirstInterval()); + + break; + } + } +} + +qx.Proto._onkeyup = function(e) +{ + if (this._intervalIncrease != null) + { + switch(e.getKeyIdentifier()) + { + case "Up": + case "Down": + case "PageUp": + case "PageDown": + this._timer.stop(); + + this._intervalIncrease = null; + this._intervalMode = null; + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._checkValue(true); + + var vButton = e.getCurrentTarget(); + + vButton.addState("pressed"); + + vButton.addEventListener("mouseup", this._onmouseup, this); + vButton.addEventListener("mouseout", this._onmouseup, this); + + this._intervalIncrease = vButton == this._upbutton; + this._resetIncrements(); + this._increment(); + + this._textfield.selectAll(); + + this._timer.setInterval(this.getFirstInterval()); + this._timer.start(); +} + +qx.Proto._onmouseup = function(e) +{ + var vButton = e.getCurrentTarget(); + + vButton.removeState("pressed"); + + vButton.removeEventListener("mouseup", this._onmouseup, this); + vButton.removeEventListener("mouseout", this._onmouseup, this); + + this._textfield.selectAll(); + this._textfield.setFocused(true); + + this._timer.stop(); + this._intervalIncrease = null; +} + +qx.Proto._onmousewheel = function(e) +{ + this._manager.setValue(this._manager.getValue() + this.getWheelIncrementAmount() * e.getWheelDelta()); + this._textfield.selectAll(); +} + + + + +/* +--------------------------------------------------------------------------- + OTHER EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._oninput = function(e) { + this._checkValue(true, true); +} + +qx.Proto._onchange = function(e) +{ + var vValue = this._manager.getValue(); + + this._textfield.setValue(String(vValue)); + + if (vValue == this.getMin()) + { + this._downbutton.removeState("pressed"); + this._downbutton.setEnabled(false); + this._timer.stop(); + } + else + { + this._downbutton.setEnabled(true); + } + + if (vValue == this.getMax()) + { + this._upbutton.removeState("pressed"); + this._upbutton.setEnabled(false); + this._timer.stop(); + } + else + { + this._upbutton.setEnabled(true); + } + + if (this.hasEventListeners("change")) { + this.dispatchEvent(new qx.event.type.Event("change"), true); + } +} + +qx.Proto._onblur = function(e) { + this._checkValue(false); +} + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO RANGE MANAGER +--------------------------------------------------------------------------- +*/ + +qx.Proto.setValue = function(nValue) { + this._manager.setValue(nValue); +} + +qx.Proto.getValue = function() { + this._checkValue(true); + return this._manager.getValue(); +} + +qx.Proto.resetValue = function() { + return this._manager.resetValue(); +} + +qx.Proto.setMax = function(vMax) { + return this._manager.setMax(vMax); +} + +qx.Proto.getMax = function() { + return this._manager.getMax(); +} + +qx.Proto.setMin = function(vMin) { + return this._manager.setMin(vMin); +} + +qx.Proto.getMin = function() { + return this._manager.getMin(); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + INTERVAL HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._intervalIncrease = null; + +qx.Proto._oninterval = function(e) +{ + this._timer.stop(); + this.setInterval(Math.max(this.getMinTimer(), this.getInterval()-this.getTimerDecrease())); + + if (this._intervalMode == "page") + { + this._pageIncrement(); + } + else + { + if (this.getInterval() == this.getMinTimer()) { + this._computedIncrementAmount = this.getAmountGrowth() * this._computedIncrementAmount; + } + + this._increment(); + } + + switch(this._intervalIncrease) + { + case true: + if (this.getValue() == this.getMax()) { + return; + } + + case false: + if (this.getValue() == this.getMin()) { + return; + } + } + + this._timer.restartWith(this.getInterval()); +} + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto._checkValue = function(acceptEmpty, acceptEdit) +{ + var el = this._textfield.getElement(); + + if (!el) { + return; + } + + if (el.value == "") + { + if (!acceptEmpty) + { + el.value = this.resetValue(); + this._textfield.selectAll(); + + return; + } + } + else + { + // cache working variable + var val = el.value; + + // fix leading '0' + if (val.length > 1) + { + while(val.charAt(0) == "0") { + val = val.substr(1, val.length); + } + + var f1 = parseInt(val) || 0; + + if (f1 != el.value) { + el.value = f1; + return; + } + } + + // fix for negative integer handling + if (val == "-" && acceptEmpty && this.getMin() < 0) + { + if (el.value != val) { + el.value = val; + } + + return; + } + + // parse the string + val = parseInt(val); + + // main check routine + var doFix = true; + var fixedVal = this._manager._checkValue(val); + + if (isNaN(fixedVal)) { + fixedVal = this._manager.getValue(); + } + + // handle empty string + if (acceptEmpty && val == "") + { + doFix = false; + } + else if (!isNaN(val)) + { + // check for editmode in keypress events + if (acceptEdit) + { + // fix min/max values + if (val > fixedVal && !(val > 0 && fixedVal <= 0) && String(val).length < String(fixedVal).length) + { + doFix = false; + } + else if (val < fixedVal && !(val < 0 && fixedVal >= 0) && String(val).length < String(fixedVal).length) + { + doFix = false; + } + } + } + + // apply value fix + if (doFix && el.value != fixedVal) { + el.value = fixedVal; + } + + // inform manager + if (!acceptEdit) { + this._manager.setValue(fixedVal); + } + } +} + +qx.Proto._increment = function() { + this._manager.setValue(this._manager.getValue() + ((this._intervalIncrease ? 1 : - 1) * this._computedIncrementAmount)); +} + +qx.Proto._pageIncrement = function() { + this._manager.setValue(this._manager.getValue() + ((this._intervalIncrease ? 1 : - 1) * this.getPageIncrementAmount())); +} + +qx.Proto._resetIncrements = function() +{ + this._computedIncrementAmount = this.getIncrementAmount(); + this.resetInterval(); +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("keypress", this._onkeypress, this); + this.removeEventListener("keydown", this._onkeydown, this); + this.removeEventListener("keyup", this._onkeyup, this); + this.removeEventListener("mousewheel", this._onmousewheel, this); + + if (this._textfield) + { + this._textfield.removeEventListener("blur", this._onblur, this); + this._textfield.removeEventListener("input", this._oninput, this); + this._textfield.dispose(); + this._textfield = null; + } + + if (this._buttonlayout) + { + this._buttonlayout.dispose(); + this._buttonlayout = null; + } + + if (this._upbutton) + { + this._upbutton.removeEventListener("mousedown", this._onmousedown, this); + this._upbutton.dispose(); + this._upbutton = null; + } + + if (this._downbutton) + { + this._downbutton.removeEventListener("mousedown", this._onmousedown, this); + this._downbutton.dispose(); + this._downbutton = null; + } + + if (this._timer) + { + this._timer.removeEventListener("interval", this._oninterval, this); + this._timer.stop(); + this._timer.dispose(); + this._timer = null; + } + + if (this._manager) + { + this._manager.removeEventListener("change", this._onchange, this); + this._manager.dispose(); + this._manager = null; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +}
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js new file mode 100644 index 0000000000..e3ceae4aa6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/** + * @param vValue {String} this string is ddisplayed as the value of the TextArea. + */ +qx.OO.defineClass("qx.ui.form.TextArea", qx.ui.form.TextField, +function(vValue) +{ + qx.ui.form.TextField.call(this, vValue); + + this.setTagName("textarea"); + this.removeHtmlProperty("type"); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "text-area" }); + +qx.OO.addProperty({ name : "wrap", type : "boolean" }); + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyWrap = function(propValue, propOldValue, propData) { + return this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + } +} +else +{ + qx.Proto._modifyWrap = function(propValue, propOldValue, propData) { + return this.setHtmlProperty("wrap", propValue ? "soft" : "off"); + } +} + +qx.Proto._computePreferredInnerHeight = function() { + return 60; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextField.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextField.js new file mode 100644 index 0000000000..b11eeb1870 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/form/TextField.js @@ -0,0 +1,540 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.TextField", qx.ui.basic.Terminator, +function(vValue) +{ + // ************************************************************************ + // INIT + // ************************************************************************ + qx.ui.basic.Terminator.call(this); + + if (typeof vValue === "string") { + this.setValue(vValue); + } + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTagName("input"); + this.setHtmlProperty("type", "text"); + this.setHtmlAttribute("autocomplete", "OFF"); + this.setTabIndex(1); + this.setSelectable(true); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + this.enableInlineEvent("input"); + + this.addEventListener("blur", this._onblur); + this.addEventListener("focus", this._onfocus); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "text-field" }); + +qx.OO.addProperty({ name : "value", type : "string", defaultValue : "" }); +qx.OO.addProperty({ name : "maxLength", type : "number" }); +qx.OO.addProperty({ name : "readOnly", type : "boolean" }); + +qx.OO.addProperty({ name : "selectionStart", type : "number" }); +qx.OO.addProperty({ name : "selectionLength", type : "number" }); +qx.OO.addProperty({ name : "selectionText", type : "string" }); + +qx.OO.addProperty({ name : "validator", type : "function" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + + + + +/* +--------------------------------------------------------------------------- + CLONING +--------------------------------------------------------------------------- +*/ + +// Extend ignore list with selection properties +qx.Proto._clonePropertyIgnoreList += ",selectionStart,selectionLength,selectionText"; + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + propValue ? this.removeHtmlAttribute("disabled") : this.setHtmlAttribute("disabled", "disabled"); + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + this._inValueProperty = true; + this.setHtmlProperty(propData.name, propValue == null ? "" : propValue); + delete this._inValueProperty; + + return true; +} + +qx.Proto._modifyMaxLength = function(propValue, propOldValue, propData) { + return propValue ? this.setHtmlProperty(propData.name, propValue) : this.removeHtmlProperty(propData.name); +} + +qx.Proto._modifyReadOnly = function(propValue, propOldValue, propData) { + return propValue ? this.setHtmlProperty(propData.name, propData.name) : this.removeHtmlProperty(propData.name); +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + this._invalidatePreferredInnerDimensions(); + + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getComputedValue = function(e) +{ + this._visualPropertyCheck(); + return this.getElement().value; +} + + + + + +/* +--------------------------------------------------------------------------- + VALIDATION +--------------------------------------------------------------------------- +*/ + +qx.ui.form.TextField.createRegExpValidator = function(vRegExp) +{ + return function(s) { + return vRegExp.test(s); + } +} + +qx.Proto.isValid = function() +{ + var vValidator = this.getValidator(); + return !vValidator || vValidator(this.getValue()); +} + +qx.Proto.isComputedValid = function() +{ + var vValidator = this.getValidator(); + return !vValidator || vValidator(this.getComputedValue()); +} + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() { + return 120; +} + +qx.Proto._computePreferredInnerHeight = function() { + return 15; +} + + + + + +/* +--------------------------------------------------------------------------- + BROWSER QUIRKS +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto._firstInputFixApplied = false; + + qx.Proto._afterAppear = function() + { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + if (!this._firstInputFixApplied) { + qx.client.Timer.once(this._ieFirstInputFix, this, 1); + } + } + + /*! + Fix IE's input event for filled text fields + */ + qx.Proto._ieFirstInputFix = function() + { + this._inValueProperty = true; + this.getElement().value = this.getValue() === null ? "" : this.getValue(); + this._firstInputFixApplied = true; + delete this._inValueProperty; + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._textOnFocus = null; + +qx.Proto._ontabfocus = function(e) { + this.selectAll(); +} + +qx.Proto._onfocus = function(e) { + this._textOnFocus = this.getComputedValue(); +} + +qx.Proto._onblur = function(e) +{ + var vValue = this.getComputedValue().toString(); + + if (this._textOnFocus != vValue) { + this.setValue(vValue); + } + + this.setSelectionLength(0); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CROSS-BROWSER SELECTION HANDLING +--------------------------------------------------------------------------- +*/ + +if (qx.core.Client.getInstance().isMshtml()) +{ + /*! + Microsoft Documentation: + http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/createrange.asp + http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_textrange.asp + */ + + qx.Proto._getRange = function() + { + this._visualPropertyCheck(); + return this.getElement().createTextRange(); + } + + qx.Proto._getSelectionRange = function() + { + this._visualPropertyCheck(); + return this.getTopLevelWidget().getDocumentElement().selection.createRange(); + } + + qx.Proto.setSelectionStart = function(vStart) + { + this._visualPropertyCheck(); + + var vText = this.getElement().value; + + // a bit hacky, special handling for line-breaks + var i = 0; + while (i<vStart) + { + // find next line break + i = vText.indexOf("\r\n", i); + + if (i == -1) { + break; + } + + vStart--; + i++; + } + + var vRange = this._getRange(); + + vRange.collapse(); + vRange.move("character", vStart); + vRange.select(); + } + + qx.Proto.getSelectionStart = function() + { + this._visualPropertyCheck(); + + var vSelectionRange = this._getSelectionRange(); + + if (!this.getElement().contains(vSelectionRange.parentElement())) { + return -1; + } + + var vRange = this._getRange(); + + vRange.setEndPoint("EndToStart", vSelectionRange); + return vRange.text.length; + } + + qx.Proto.setSelectionLength = function(vLength) + { + this._visualPropertyCheck(); + + var vSelectionRange = this._getSelectionRange(); + + if (!this.getElement().contains(vSelectionRange.parentElement())) { + return; + } + + vSelectionRange.collapse(); + vSelectionRange.moveEnd("character", vLength); + vSelectionRange.select(); + } + + qx.Proto.getSelectionLength = function() + { + this._visualPropertyCheck(); + + var vSelectionRange = this._getSelectionRange(); + + if (!this.getElement().contains(vSelectionRange.parentElement())) { + return 0; + } + + return vSelectionRange.text.length; + } + + qx.Proto.setSelectionText = function(vText) + { + this._visualPropertyCheck(); + + var vStart = this.getSelectionStart(); + var vSelectionRange = this._getSelectionRange(); + + if (!this.getElement().contains(vSelectionRange.parentElement())) { + return; + } + + vSelectionRange.text = vText; + + // apply text to internal storage + this.setValue(this.getElement().value); + + // recover selection (to behave the same gecko does) + this.setSelectionStart(vStart); + this.setSelectionLength(vText.length); + + return true; + } + + qx.Proto.getSelectionText = function() + { + this._visualPropertyCheck(); + + var vSelectionRange = this._getSelectionRange(); + + if (!this.getElement().contains(vSelectionRange.parentElement())) { + return ""; + } + + return vSelectionRange.text; + } + + qx.Proto.selectAll = function() + { + this._visualPropertyCheck(); + + if (this.getValue() != null) + { + this.setSelectionStart(0); + this.setSelectionLength(this.getValue().length); + } + + // to be sure we get the element selected + this.getElement().select(); + } + + qx.Proto.selectFromTo = function(vStart, vEnd) + { + this._visualPropertyCheck(); + + this.setSelectionStart(vStart); + this.setSelectionLength(vEnd-vStart); + } +} +else +{ + qx.Proto.setSelectionStart = function(vStart) + { + this._visualPropertyCheck(); + this.getElement().selectionStart = vStart; + } + + qx.Proto.getSelectionStart = function() + { + this._visualPropertyCheck(); + return this.getElement().selectionStart; + } + + qx.Proto.setSelectionLength = function(vLength) + { + this._visualPropertyCheck(); + + var el = this.getElement(); + if (qx.util.Validation.isValidString(el.value)) { + el.selectionEnd = el.selectionStart + vLength; + } + } + + qx.Proto.getSelectionLength = function() + { + this._visualPropertyCheck(); + + var el = this.getElement(); + return el.selectionEnd - el.selectionStart; + } + + qx.Proto.setSelectionText = function(vText) + { + this._visualPropertyCheck(); + + var el = this.getElement(); + + var vOldText = el.value; + var vStart = el.selectionStart; + + var vOldTextBefore = vOldText.substr(0, vStart); + var vOldTextAfter = vOldText.substr(el.selectionEnd); + + var vValue = el.value = vOldTextBefore + vText + vOldTextAfter; + + // recover selection + el.selectionStart = vStart; + el.selectionEnd = vStart + vText.length; + + // apply new value to internal cache + this.setValue(vValue); + + return true; + } + + qx.Proto.getSelectionText = function() + { + this._visualPropertyCheck(); + + return this.getElement().value.substr(this.getSelectionStart(), this.getSelectionLength()); + } + + qx.Proto.selectAll = function() + { + this._visualPropertyCheck(); + + this.getElement().select(); + } + + qx.Proto.selectFromTo = function(vStart, vEnd) + { + this._visualPropertyCheck(); + + var el = this.getElement(); + el.selectionStart = vStart; + el.selectionEnd = vEnd; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("blur", this._onblur); + this.removeEventListener("focus", this._onfocus); + + qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/CheckGroupBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/CheckGroupBox.js new file mode 100644 index 0000000000..eef301457c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/CheckGroupBox.js @@ -0,0 +1,41 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.groupbox.CheckGroupBox", qx.ui.groupbox.GroupBox, +function(vLegend) { + qx.ui.groupbox.GroupBox.call(this, vLegend); +}); + +qx.Proto._createLegendObject = function() +{ + this._legendObject = new qx.ui.form.CheckBox; + this._legendObject.setAppearance("check-box-field-set-legend"); + this._legendObject.setChecked(true); + + this.add(this._legendObject); +} + +qx.Proto.setIcon = qx.Proto.getIcon = null; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/GroupBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/GroupBox.js new file mode 100644 index 0000000000..93651d63a8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/GroupBox.js @@ -0,0 +1,158 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.groupbox.GroupBox", qx.ui.layout.CanvasLayout, +function(vLegend, vIcon) +{ + qx.ui.layout.CanvasLayout.call(this); + + + // ************************************************************************ + // SUB WIDGETS + // ************************************************************************ + this._createFrameObject(); + this._createLegendObject(); + + + // ************************************************************************ + // INIT + // ************************************************************************ + this.setLegend(vLegend); + + if (vIcon != null) { + this.setIcon(vIcon); + } + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + this.remapChildrenHandlingTo(this._frameObject); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "field-set" }); + + + + +/* +--------------------------------------------------------------------------- + SUB WIDGET CREATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._createLegendObject = function() +{ + this._legendObject = new qx.ui.basic.Atom; + this._legendObject.setAppearance("field-set-legend"); + + this.add(this._legendObject); +} + +qx.Proto._createFrameObject = function() +{ + this._frameObject = new qx.ui.layout.CanvasLayout; + this._frameObject.setAppearance("field-set-frame"); + + this.add(this._frameObject); +} + + + + + +/* +--------------------------------------------------------------------------- + GETTER FOR SUB WIDGETS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getFrameObject = function() { + return this._frameObject; +} + +qx.Proto.getLegendObject = function() { + return this._legendObject; +} + + + + + + +/* +--------------------------------------------------------------------------- + SETTER/GETTER +--------------------------------------------------------------------------- +*/ + +qx.Proto.setLegend = function(vLegend) { + this._legendObject.setLabel(vLegend); +} + +qx.Proto.getLegend = function() { + return this._legendObject.getLabel(); +} + +qx.Proto.setIcon = function(vIcon) { + this._legendObject.setIcon(vIcon); +} + +qx.Proto.getIcon = function() { + this._legendObject.getIcon(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._legendObject) + { + this._legendObject.dispose(); + this._legendObject = null; + } + + if (this._frameObject) + { + this._frameObject.dispose(); + this._frameObject = null; + } + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/RadioGroupBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/RadioGroupBox.js new file mode 100644 index 0000000000..0761d78fc3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/groupbox/RadioGroupBox.js @@ -0,0 +1,41 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.groupbox.RadioGroupBox", qx.ui.groupbox.GroupBox, +function(vLegend) { + qx.ui.groupbox.GroupBox.call(this, vLegend); +}); + +qx.Proto._createLegendObject = function() +{ + this._legendObject = new qx.ui.form.RadioButton; + this._legendObject.setAppearance("radio-button-field-set-legend"); + this._legendObject.setChecked(true); + + this.add(this._legendObject); +} + +qx.Proto.setIcon = qx.Proto.getIcon = null; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/BoxLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/BoxLayout.js new file mode 100644 index 0000000000..728b6c5e24 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/BoxLayout.js @@ -0,0 +1,275 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.BoxLayout", qx.ui.core.Parent, +function(vOrientation) +{ + qx.ui.core.Parent.call(this); + + // apply orientation + if (vOrientation != null) { + this.setOrientation(vOrientation); + } +}); + +qx.ui.layout.BoxLayout.STR_REVERSED = "-reversed"; + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The orientation of the layout control. Allowed values are "horizontal" (default) and "vertical". +*/ +qx.OO.addProperty({ name : "orientation", type : "string", possibleValues : [ "horizontal", "vertical" ], addToQueueRuntime : true }); + +/*! + The spacing between childrens. Could be any positive integer value. +*/ +qx.OO.addProperty({ name : "spacing", type : "number", defaultValue : 0, addToQueueRuntime : true, impl : "layout" }); + +/*! + The horizontal align of the children. Allowed values are: "left", "center" and "right" +*/ +qx.OO.addProperty({ name : "horizontalChildrenAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right" ], impl : "layoutOrder", addToQueueRuntime : true }); + +/*! + The vertical align of the children. Allowed values are: "top", "middle" and "bottom" +*/ +qx.OO.addProperty({ name : "verticalChildrenAlign", type : "string", defaultValue : "top", possibleValues : [ "top", "middle", "bottom" ], impl : "layoutOrder", addToQueueRuntime : true }); + +/*! + Should the children be layouted in reverse order? +*/ +qx.OO.addProperty({ name : "reverseChildrenOrder", type : "boolean", defaultValue : false, impl : "layoutOrder", addToQueueRuntime : true }); + +/*! + Should the widgets be stretched to the available width (orientation==vertical) or height (orientation==horizontal)? + This only applies if the child has not configured a own value for this axis. +*/ +qx.OO.addProperty({ name : "stretchChildrenOrthogonalAxis", type : "boolean", defaultValue : true, addToQueueRuntime : true }); + +/*! + If there are min/max values in combination with flex try to optimize placement. + This is more complex and produces more time for the layouter but sometimes this feature is needed. +*/ +qx.OO.addProperty({ name : "useAdvancedFlexAllocation", type : "boolean", defaultValue : false, addToQueueRuntime : true }); + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return this.getOrientation() == "vertical" ? new qx.renderer.layout.VerticalBoxLayoutImpl(this) : new qx.renderer.layout.HorizontalBoxLayoutImpl(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + HELPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._layoutHorizontal = false; +qx.Proto._layoutVertical = false; +qx.Proto._layoutMode = "left"; + +qx.Proto.isHorizontal = function() { + return this._layoutHorizontal; +} + +qx.Proto.isVertical = function() { + return this._layoutVertical; +} + +qx.Proto.getLayoutMode = function() +{ + if (this._layoutMode == null) { + this._updateLayoutMode(); + } + + return this._layoutMode; +} + +qx.Proto._updateLayoutMode = function() +{ + this._layoutMode = this._layoutVertical ? this.getVerticalChildrenAlign() : this.getHorizontalChildrenAlign(); + + if (this.getReverseChildrenOrder()) { + this._layoutMode += qx.ui.layout.BoxLayout.STR_REVERSED; + } +} + +qx.Proto._invalidateLayoutMode = function() { + this._layoutMode = null; +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyOrientation = function(propValue, propOldValue, propData) +{ + // update fast access variables + this._layoutHorizontal = propValue == "horizontal"; + this._layoutVertical = propValue == "vertical"; + + // Layout Implementation + if (this._layoutImpl) + { + this._layoutImpl.dispose(); + this._layoutImpl = null; + } + + if (qx.util.Validation.isValidString(propValue)) { + this._layoutImpl = this._createLayoutImpl(); + } + + // call other core modifier + return this._modifyLayoutOrder(propValue, propOldValue, propData); +} + +qx.Proto._modifyLayoutOrder = function(propValue, propOldValue, propData) +{ + // update layout mode + this._invalidateLayoutMode(); + + // call other core modifier + return this._modifyLayout(propValue, propOldValue, propData); +} + +qx.Proto._modifyLayout = function(propValue, propOldValue, propData) +{ + // invalidate inner preferred dimensions + this._invalidatePreferredInnerDimensions(); + + // accumulated width needs to be invalidated + this._invalidateAccumulatedChildrenOuterWidth(); + this._invalidateAccumulatedChildrenOuterHeight(); + + // make property handling happy :) + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ACCUMULATED CHILDREN WIDTH/HEIGHT +-------------------------------------------------------------------------------- + + Needed for center/middle and right/bottom alignment + +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "accumulatedChildrenOuterWidth", defaultValue : null }); +qx.OO.addCachedProperty({ name : "accumulatedChildrenOuterHeight", defaultValue : null }); + +qx.Proto._computeAccumulatedChildrenOuterWidth = function() +{ + var ch=this.getVisibleChildren(), chc, i=-1, sp=this.getSpacing(), s=-sp; + + while(chc=ch[++i]) { + s += chc.getOuterWidth() + sp; + } + + return s; +} + +qx.Proto._computeAccumulatedChildrenOuterHeight = function() +{ + var ch=this.getVisibleChildren(), chc, i=-1, sp=this.getSpacing(), s=-sp; + + while(chc=ch[++i]) { + s += chc.getOuterHeight() + sp; + } + + return s; +} + + + + + + + +/* +--------------------------------------------------------------------------- + STRETCHING SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._recomputeChildrenStretchingX = function() +{ + var ch=this.getVisibleChildren(), chc, i=-1; + + while(chc=ch[++i]) + { + if (chc._recomputeStretchingX() && chc._recomputeBoxWidth()) { + chc._recomputeOuterWidth(); + } + } +} + +qx.Proto._recomputeChildrenStretchingY = function() +{ + var ch=this.getVisibleChildren(), chc, i=-1; + + while(chc=ch[++i]) + { + if (chc._recomputeStretchingY() && chc._recomputeBoxHeight()) { + chc._recomputeOuterHeight(); + } + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/CanvasLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/CanvasLayout.js new file mode 100644 index 0000000000..9b27f57247 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/CanvasLayout.js @@ -0,0 +1,47 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.CanvasLayout", qx.ui.core.Parent, +function() { + qx.ui.core.Parent.call(this); +}); + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.CanvasLayoutImpl(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/DockLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/DockLayout.js new file mode 100644 index 0000000000..dc208a69f5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/DockLayout.js @@ -0,0 +1,118 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.DockLayout", qx.ui.core.Parent, +function() { + qx.ui.core.Parent.call(this); +}); + +/*! + The layout mode (in which order the children should be layouted) +*/ +qx.OO.addProperty({ name : "mode", type : "string", defaultValue : "vertical", possibleValues : [ "vertical", "horizontal", "ordered" ], addToQueueRuntime : true }); + +/* + Overwrite from qx.ui.core.Widget, we do not support 'auto' and 'flex' +*/ +qx.OO.changeProperty({ name : "width", addToQueue : true, unitDetection : "pixelPercent" }); +qx.OO.changeProperty({ name : "minWidth", defaultValue : -Infinity, addToQueue : true, unitDetection : "pixelPercent" }); +qx.OO.changeProperty({ name : "minWidth", defaultValue : -Infinity, addToQueue : true, unitDetection : "pixelPercent" }); +qx.OO.changeProperty({ name : "height", addToQueue : true, unitDetection : "pixelPercent" }); +qx.OO.changeProperty({ name : "minHeight", defaultValue : -Infinity, addToQueue : true, unitDetection : "pixelPercent" }); +qx.OO.changeProperty({ name : "minHeight", defaultValue : -Infinity, addToQueue : true, unitDetection : "pixelPercent" }); + + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.DockLayoutImpl(this); +} + + + + +/* +--------------------------------------------------------------------------- + ENHANCED CHILDREN FEATURES +--------------------------------------------------------------------------- +*/ + +/*! + Add multiple childrens and make them left aligned +*/ +qx.Proto.addLeft = function() { + this._addAlignedHorizontal("left", arguments); +} + +/*! + Add multiple childrens and make them right aligned +*/ +qx.Proto.addRight = function() { + this._addAlignedHorizontal("right", arguments); +} + +/*! + Add multiple childrens and make them top aligned +*/ +qx.Proto.addTop = function() { + this._addAlignedVertical("top", arguments); +} + +/*! + Add multiple childrens and make them bottom aligned +*/ +qx.Proto.addBottom = function() { + this._addAlignedVertical("bottom", arguments); +} + +qx.Proto._addAlignedVertical = function(vAlign, vArgs) +{ + for (var i=0, l=vArgs.length; i<l; i++) { + vArgs[i].setVerticalAlign(vAlign); + } + + this.add.apply(this, vArgs); +} + +qx.Proto._addAlignedHorizontal = function(vAlign, vArgs) +{ + for (var i=0, l=vArgs.length; i<l; i++) { + vArgs[i].setHorizontalAlign(vAlign); + } + + this.add.apply(this, vArgs); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/FlowLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/FlowLayout.js new file mode 100644 index 0000000000..8bf343a6fe --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/FlowLayout.js @@ -0,0 +1,108 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.FlowLayout", qx.ui.core.Parent, +function() { + qx.ui.core.Parent.call(this); +}); + +/*! + The spacing between childrens. Could be any positive integer value. +*/ +qx.OO.addProperty({ name : "horizontalSpacing", type : "number", defaultValue : 0, addToQueueRuntime : true, impl : "layout" }); + +/*! + The spacing between childrens. Could be any positive integer value. +*/ +qx.OO.addProperty({ name : "verticalSpacing", type : "number", defaultValue : 0, addToQueueRuntime : true, impl : "layout" }); + +/*! + The horizontal align of the children. Allowed values are: "left" and "right" +*/ +qx.OO.addProperty({ name : "horizontalChildrenAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "right" ], addToQueueRuntime : true }); + +/*! + The vertical align of the children. Allowed values are: "top" and "bottom" +*/ +qx.OO.addProperty({ name : "verticalChildrenAlign", type : "string", defaultValue : "top", possibleValues : [ "top", "bottom" ], addToQueueRuntime : true }); + +/*! + Should the children be layouted in reverse order? +*/ +qx.OO.addProperty({ name : "reverseChildrenOrder", type : "boolean", defaultValue : false, addToQueueRuntime : true, impl : "layout" }); + + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.FlowLayoutImpl(this); +} + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._changeInnerWidth = function(vNew, vOld) +{ + qx.ui.core.Parent.prototype._changeInnerWidth.call(this, vNew, vOld); + + // allow 'auto' values for height to update when the inner width changes + this._invalidatePreferredInnerHeight(); +} + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyLayout = function(propValue, propOldValue, propData) +{ + // invalidate inner preferred dimensions + this._invalidatePreferredInnerDimensions(); + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/GridLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/GridLayout.js new file mode 100644 index 0000000000..e8e980a298 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/GridLayout.js @@ -0,0 +1,866 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.GridLayout", qx.ui.core.Parent, +function() +{ + qx.ui.core.Parent.call(this); + + this._columnData = []; + this._rowData = []; + + this._spans = []; +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The spacing between childrens. Could be any positive integer value. +*/ +qx.OO.addProperty({ name : "horizontalSpacing", type : "number", defaultValue : 0, addToQueueRuntime : true, impl : "layout" }); + +/*! + The spacing between childrens. Could be any positive integer value. +*/ +qx.OO.addProperty({ name : "verticalSpacing", type : "number", defaultValue : 0, addToQueueRuntime : true, impl : "layout" }); + +/*! + The horizontal align of the children. Allowed values are: "left", "center" and "right" +*/ +qx.OO.addProperty({ name : "horizontalChildrenAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right" ], addToQueueRuntime : true }); + +/*! + The vertical align of the children. Allowed values are: "top", "middle" and "bottom" +*/ +qx.OO.addProperty({ name : "verticalChildrenAlign", type : "string", defaultValue : "top", possibleValues : [ "top", "middle", "bottom" ], addToQueueRuntime : true }); + +/*! + Cell padding top of all cells, if not locally defined +*/ +qx.OO.addProperty({ name : "cellPaddingTop", type : "number" }); + +/*! + Cell padding right of all cells, if not locally defined +*/ +qx.OO.addProperty({ name : "cellPaddingRight", type : "number" }); + +/*! + Cell padding bottom of all cells, if not locally defined +*/ +qx.OO.addProperty({ name : "cellPaddingBottom", type : "number" }); + +/*! + Cell padding left of all cells, if not locally defined +*/ +qx.OO.addProperty({ name : "cellPaddingLeft", type : "number" }); + + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.GridLayoutImpl(this); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CORE FUNCTIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto.add = function(vChild, vCol, vRow) +{ + vChild._col = vCol; + vChild._row = vRow; + + if (this.isFillCell(vCol, vRow)) { + throw new Error("Could not insert child " + vChild + " into a fill cell: " + vCol + "x" + vRow); + } + + qx.ui.core.Parent.prototype.add.call(this, vChild); +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyLayout = function(propValue, propOldValue, propData) +{ + // invalidate inner preferred dimensions + this._invalidatePreferredInnerDimensions(); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + GRID SETUP +--------------------------------------------------------------------------- +*/ + +qx.Proto._syncDataFields = function(vData, vOldLength, vNewLength) +{ + if (vNewLength > vOldLength) + { + for (var i=vOldLength; i<vNewLength; i++) { + vData[i] = {}; + } + } + else if (vOldLength > vNewLength) + { + vData.splice(vNewLength, vOldLength - vNewLength); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + GRID SETUP: COLUMNS +--------------------------------------------------------------------------- +*/ + +qx.Proto._columnCount = 0; + +qx.Proto.setColumnCount = function(vCount) +{ + this._columnCount = vCount; + this._syncColumnDataFields(); +} + +qx.Proto.getColumnCount = function() { + return this._columnCount; +} + +qx.Proto.addColumn = function() +{ + this._columnCount++; + this._syncColumnDataFields(); +} + +qx.Proto.removeColumn = function() +{ + if (this._columnCount > 0) + { + this._columnCount--; + this._syncColumnDataFields(); + } +} + +qx.Proto._syncColumnDataFields = function() +{ + var vData = this._columnData; + var vOldLength = vData.length; + var vNewLength = this._columnCount; + + this._syncDataFields(vData, vOldLength, vNewLength); +} + + + + + +/* +--------------------------------------------------------------------------- + GRID SETUP: ROWS +--------------------------------------------------------------------------- +*/ + +qx.Proto._rowCount = 0; + +qx.Proto.setRowCount = function(vCount) +{ + this._rowCount = vCount; + this._syncRowDataFields(); +} + +qx.Proto.getRowCount = function() { + return this._rowCount; +} + +qx.Proto.addRow = function() +{ + this._rowCount++; + this._syncRowDataFields(); +} + +qx.Proto.removeRow = function() +{ + if (this._rowCount > 0) + { + this._rowCount--; + this._syncRowDataFields(); + } +} + +qx.Proto._syncRowDataFields = function() +{ + var vData = this._rowData; + var vOldLength = vData.length; + var vNewLength = this._rowCount; + + this._syncDataFields(vData, vOldLength, vNewLength); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DATA HANDLING: COLUMNS +--------------------------------------------------------------------------- +*/ + +qx.Proto._getColumnProperty = function(vColumnIndex, vProperty) +{ + try + { + return this._columnData[vColumnIndex][vProperty] || null; + } + catch(ex) + { + this.error("Error while getting column property (" + vColumnIndex + "|" + vProperty + ")", ex); + return null; + } +} + +qx.Proto._setupColumnProperty = function(vColumnIndex, vProperty, vValue) +{ + this._columnData[vColumnIndex][vProperty] = vValue; + this._invalidateColumnLayout(); +} + +qx.Proto._removeColumnProperty = function(vColumnIndex, vProperty, vValue) +{ + delete this._columnData[vColumnIndex][vProperty]; + this._invalidateColumnLayout(); +} + +qx.Proto._invalidateColumnLayout = function() +{ + if (!this._initialLayoutDone || !this._isDisplayable) { + return; + } + + this.forEachVisibleChild(function() { + this.addToQueue("width"); + }); +} + + + + + + +/* +--------------------------------------------------------------------------- + DATA HANDLING: ROWS +--------------------------------------------------------------------------- +*/ + +qx.Proto._getRowProperty = function(vRowIndex, vProperty) +{ + try + { + return this._rowData[vRowIndex][vProperty] || null; + } + catch(ex) + { + this.error("Error while getting row property (" + vRowIndex + "|" + vProperty + ")", ex); + return null; + } +} + +qx.Proto._setupRowProperty = function(vRowIndex, vProperty, vValue) +{ + this._rowData[vRowIndex][vProperty] = vValue; + this._invalidateRowLayout(); +} + +qx.Proto._removeRowProperty = function(vRowIndex, vProperty, vValue) +{ + delete this._rowData[vRowIndex][vProperty]; + this._invalidateRowLayout(); +} + +qx.Proto._invalidateRowLayout = function() +{ + if (!this._initialLayoutDone || !this._isDisplayable) { + return; + } + + this.forEachVisibleChild(function() { + this.addToQueue("height"); + }); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL DIMENSIONS +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnWidth = function(vIndex, vValue) +{ + this._setupColumnProperty(vIndex, "widthValue", vValue); + + var vType = qx.ui.core.Parent.prototype._evalUnitsPixelPercentAutoFlex(vValue); + + this._setupColumnProperty(vIndex, "widthType", vType); + + var vParsed, vComputed; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vParsed = vComputed = Math.round(vValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + case qx.ui.core.Widget.TYPE_FLEX: + vParsed = parseFloat(vValue); + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + vParsed = vComputed = null; + break; + + default: + vParsed = vComputed = null; + } + + this._setupColumnProperty(vIndex, "widthParsed", vParsed); + this._setupColumnProperty(vIndex, "widthComputed", vComputed); +} + +qx.Proto.setRowHeight = function(vIndex, vValue) +{ + this._setupRowProperty(vIndex, "heightValue", vValue); + + var vType = qx.ui.core.Widget.prototype._evalUnitsPixelPercentAutoFlex(vValue); + this._setupRowProperty(vIndex, "heightType", vType); + + var vParsed, vComputed; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vParsed = vComputed = Math.round(vValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + case qx.ui.core.Widget.TYPE_FLEX: + vParsed = parseFloat(vValue); + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + vParsed = vComputed = null; + break; + + default: + vParsed = vComputed = null; + } + + this._setupRowProperty(vIndex, "heightParsed", vParsed); + this._setupRowProperty(vIndex, "heightComputed", vComputed); +} + + + +// GETTER: BOX + +qx.Proto.getColumnBoxWidth = function(vIndex) +{ + var vComputed = this._getColumnProperty(vIndex, "widthComputed"); + + if (vComputed != null) { + return vComputed; + } + + var vType = this._getColumnProperty(vIndex, "widthType"); + var vParsed = this._getColumnProperty(vIndex, "widthParsed"); + var vComputed = null; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vComputed = Math.max(0, vParsed); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + vComputed = this.getInnerWidth() * Math.max(0, vParsed) * 0.01; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + // TODO + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_FLEX: + // TODO + vComputed = null; + break; + } + + this._setupColumnProperty(vIndex, "widthComputed", vComputed); + return vComputed; +} + +qx.Proto.getRowBoxHeight = function(vIndex) +{ + var vComputed = this._getRowProperty(vIndex, "heightComputed"); + + if (vComputed != null) { + return vComputed; + } + + var vType = this._getRowProperty(vIndex, "heightType"); + var vParsed = this._getRowProperty(vIndex, "heightParsed"); + var vComputed = null; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vComputed = Math.max(0, vParsed); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + vComputed = this.getInnerHeight() * Math.max(0, vParsed) * 0.01; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + // TODO + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_FLEX: + // TODO + vComputed = null; + break; + } + + this._setupRowProperty(vIndex, "heightComputed", vComputed); + return vComputed; +} + + +// GETTER: PADDING + +qx.Proto.getComputedCellPaddingLeft = function(vCol, vRow) { + return this.getColumnPaddingLeft(vCol) || this.getRowPaddingLeft(vRow) || this.getCellPaddingLeft() || 0; +} + +qx.Proto.getComputedCellPaddingRight = function(vCol, vRow) { + return this.getColumnPaddingRight(vCol) || this.getRowPaddingRight(vRow) || this.getCellPaddingRight() || 0; +} + +qx.Proto.getComputedCellPaddingTop = function(vCol, vRow) { + return this.getRowPaddingTop(vRow) || this.getColumnPaddingTop(vCol) || this.getCellPaddingTop() || 0; +} + +qx.Proto.getComputedCellPaddingBottom = function(vCol, vRow) { + return this.getRowPaddingBottom(vRow) || this.getColumnPaddingBottom(vCol) || this.getCellPaddingBottom() || 0; +} + + +// GETTER: INNER + +qx.Proto.getColumnInnerWidth = function(vCol, vRow) { + return this.getColumnBoxWidth(vCol) - this.getComputedCellPaddingLeft(vCol, vRow) - this.getComputedCellPaddingRight(vCol, vRow); +} + +qx.Proto.getRowInnerHeight = function(vCol, vRow) { + return this.getRowBoxHeight(vRow) - this.getComputedCellPaddingTop(vCol, vRow) - this.getComputedCellPaddingBottom(vCol, vRow); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL ALIGNMENT +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnHorizontalAlignment = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "horizontalAlignment", vValue); +} + +qx.Proto.setColumnVerticalAlignment = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "verticalAlignment", vValue); +} + +qx.Proto.setRowHorizontalAlignment = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "horizontalAlignment", vValue); +} + +qx.Proto.setRowVerticalAlignment = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "verticalAlignment", vValue); +} + + + +// GETTER + +qx.Proto.getColumnHorizontalAlignment = function(vIndex) { + return this._getColumnProperty(vIndex, "horizontalAlignment"); +} + +qx.Proto.getColumnVerticalAlignment = function(vIndex) { + return this._getColumnProperty(vIndex, "verticalAlignment"); +} + +qx.Proto.getRowHorizontalAlignment = function(vIndex) { + return this._getRowProperty(vIndex, "horizontalAlignment"); +} + +qx.Proto.getRowVerticalAlignment = function(vIndex) { + return this._getRowProperty(vIndex, "verticalAlignment"); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL PADDING +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnPaddingTop = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingTop", vValue); +} + +qx.Proto.setColumnPaddingRight = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingRight", vValue); +} + +qx.Proto.setColumnPaddingBottom = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingBottom", vValue); +} + +qx.Proto.setColumnPaddingLeft = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingLeft", vValue); +} + +qx.Proto.setRowPaddingTop = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingTop", vValue); +} + +qx.Proto.setRowPaddingRight = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingRight", vValue); +} + +qx.Proto.setRowPaddingBottom = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingBottom", vValue); +} + +qx.Proto.setRowPaddingLeft = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingLeft", vValue); +} + + + +// GETTER + +qx.Proto.getColumnPaddingTop = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingTop"); +} + +qx.Proto.getColumnPaddingRight = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingRight"); +} + +qx.Proto.getColumnPaddingBottom = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingBottom"); +} + +qx.Proto.getColumnPaddingLeft = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingLeft"); +} + +qx.Proto.getRowPaddingTop = function(vIndex) { + return this._getRowProperty(vIndex, "paddingTop"); +} + +qx.Proto.getRowPaddingRight = function(vIndex) { + return this._getRowProperty(vIndex, "paddingRight"); +} + +qx.Proto.getRowPaddingBottom = function(vIndex) { + return this._getRowProperty(vIndex, "paddingBottom"); +} + +qx.Proto.getRowPaddingLeft = function(vIndex) { + return this._getRowProperty(vIndex, "paddingLeft"); +} + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._changeInnerWidth = function(vNew, vOld) +{ + for (var i=0, l=this.getColumnCount(); i<l; i++) { + if (this._getColumnProperty(i, "widthType") == qx.ui.core.Widget.TYPE_PERCENT) { + this._setupColumnProperty(i, "widthComputed", null); + } + } + + qx.ui.core.Parent.prototype._changeInnerWidth.call(this, vNew, vOld); +} + +qx.Proto._changeInnerHeight = function(vNew, vOld) +{ + for (var i=0, l=this.getRowCount(); i<l; i++) { + if (this._getRowProperty(i, "heightType") == qx.ui.core.Widget.TYPE_PERCENT) { + this._setupRowProperty(i, "heightComputed", null); + } + } + + qx.ui.core.Parent.prototype._changeInnerHeight.call(this, vNew, vOld); +} + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto.getInnerWidthForChild = function(vChild) { + return this._getColumnProperty(vChild._col, "widthComputed"); +} + +qx.Proto.getInnerHeightForChild = function(vChild) { + return this._getRowProperty(vChild._row, "heightComputed"); +} + + + + + +/* +--------------------------------------------------------------------------- + SPAN CELLS +--------------------------------------------------------------------------- +*/ + +qx.Proto.mergeCells = function(vStartCol, vStartRow, vColLength, vRowLength) +{ + var vSpans = this._spans; + var vLength = vSpans.length; + + // Find end cols/rows + var vEndCol = vStartCol + vColLength - 1; + var vEndRow = vStartRow + vRowLength - 1; + + if (this._collidesWithSpans(vStartCol, vStartRow, vEndCol, vEndRow)) + { + this.debug("Span collision detected!"); + + // Send out warning + return false; + } + + // Finally store new span entry + vSpans.push({ startCol : vStartCol, startRow : vStartRow, endCol : vEndCol, endRow : vEndRow, colLength : vColLength, rowLength : vRowLength }); + + // Send out ok + return true; +} + +qx.Proto.hasSpans = function() { + return this._spans.length > 0; +} + +qx.Proto.getSpanEntry = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i<l; i++) + { + c = s[i]; + + if (vCol >= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow) { + return c; + } + } + + return null; +} + +qx.Proto.isSpanStart = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i<l; i++) + { + c = s[i]; + + if (c.startCol == vCol && c.startRow == vRow) { + return true; + } + } + + return false; +} + +qx.Proto.isSpanCell = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i<l; i++) + { + c = s[i]; + + if (vCol >= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow) { + return true; + } + } + + return false; +} + +qx.Proto.isFillCell = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i<l; i++) + { + c = s[i]; + + if (vCol >= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow && (vCol > c.startCol || vRow > c.startRow)) { + return true; + } + } + + return false; +} + +qx.Proto._collidesWithSpans = function(vStartCol, vStartRow, vEndCol, vEndRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i<l; i++) + { + c = s[i]; + + if (vEndCol >= c.startCol && vStartCol <= c.endCol && vEndRow >= c.startRow && vStartRow <= c.endRow ) { + return true; + } + } + + return false; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + + delete this._columnData; + delete this._rowData; + + delete this._spans; + + return qx.ui.core.Parent.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js new file mode 100644 index 0000000000..637d9eab29 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js @@ -0,0 +1,31 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.HorizontalBoxLayout", qx.ui.layout.BoxLayout, +function() { + qx.ui.layout.BoxLayout.call(this, "horizontal"); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js new file mode 100644 index 0000000000..8135e9c65e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js @@ -0,0 +1,31 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.VerticalBoxLayout", qx.ui.layout.BoxLayout, +function() { + qx.ui.layout.BoxLayout.call(this, "vertical"); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js new file mode 100644 index 0000000000..53286a66ef --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js @@ -0,0 +1,39 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellHtml", qx.ui.embed.HtmlEmbed, +function(vHtml) +{ + qx.ui.embed.HtmlEmbed.call(this, vHtml); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-html" }); + +qx.ui.listview.ContentCellHtml.empty = { + html : "" +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js new file mode 100644 index 0000000000..7cf839cb0c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js @@ -0,0 +1,41 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellIconHtml", qx.ui.embed.IconHtmlEmbed, +function(vHtml, vIcon, vIconWidth, vIconHeight) +{ + qx.ui.embed.IconHtmlEmbed.call(this, vHtml, vIcon, vIconWidth, vIconHeight); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-icon-html" }); + +qx.ui.listview.ContentCellIconHtml.empty = +{ + icon : "", + html : "" +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js new file mode 100644 index 0000000000..de9672ca22 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js @@ -0,0 +1,60 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellImage", qx.ui.basic.Image, +function(vSource, vWidth, vHeight) { + qx.ui.basic.Image.call(this, vSource, vWidth, vHeight); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-image" }); + +qx.ui.listview.ContentCellImage.empty = { + source : "static/image/blank.gif" +} + + + +/* +--------------------------------------------------------------------------- + CUSTOM SETTER +--------------------------------------------------------------------------- +*/ + +qx.Proto.setSource = function(vSource) +{ + if (this._initialLayoutDone) + { + return this._updateContent(qx.manager.object.AliasManager.getInstance().resolvePath(vSource == "" ? "static/image/blank.gif" : vSource)); + } + else + { + return qx.ui.basic.Image.prototype.setSource.call(this, vSource); + } +} + +// Omit dimension setup in list-view +qx.Proto._postApplyDimensions = qx.lang.Function.returnTrue; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js new file mode 100644 index 0000000000..3931cb3a7f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js @@ -0,0 +1,42 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellLink", qx.ui.embed.LinkEmbed, +function(vHtml) +{ + qx.ui.embed.LinkEmbed.call(this, vHtml); + + // selectable = false will break links in gecko based browsers + this.setSelectable(true); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-link" }); + +qx.ui.listview.ContentCellLink.empty = +{ + html : "", + uri : "#" +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js new file mode 100644 index 0000000000..d77abf72a3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js @@ -0,0 +1,42 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellText", qx.ui.embed.TextEmbed, +function(vText) +{ + qx.ui.embed.TextEmbed.call(this, vText); + + this.setStyleProperty("whiteSpace", "nowrap"); + this.setStyleProperty("textOverflow", "ellipsis"); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-text" }); + +qx.ui.listview.ContentCellText.empty = { + text : "" +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/Header.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/Header.js new file mode 100644 index 0000000000..73824e5448 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/Header.js @@ -0,0 +1,296 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.Header", qx.ui.layout.HorizontalBoxLayout, +function(vColumns) +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + // This fixes the innerWidth calculation difference between the grid(pane) and the head. + this.setPaddingRight(qx.ui.core.Widget.SCROLLBAR_SIZE); + + + // ************************************************************************ + // STORE REFERENCE TO CONFIG ENTRY + // ************************************************************************ + this._columns = vColumns; + + + // ************************************************************************ + // CREATE HEADER CELLS + // ************************************************************************ + var vHeadCell, vHeadSeparator; + + for (var vCol in vColumns) + { + vHeadCell = new qx.ui.listview.HeaderCell(vColumns[vCol], vCol); + vHeadSeparator = new qx.ui.listview.HeaderSeparator; + + this.add(vHeadCell, vHeadSeparator); + + if (vColumns[vCol].align) { + vHeadCell.setHorizontalChildrenAlign(vColumns[vCol].align); + + if (vColumns[vCol].align == "right") { + vHeadCell.setReverseChildrenOrder(true); + } + } + + // store some additional data + vColumns[vCol].contentClass = qx.OO.classes["qx.ui.listview.ContentCell" + qx.lang.String.toFirstUp(vColumns[vCol].type || "text")]; + vColumns[vCol].headerCell = vHeadCell; + } + + + // ************************************************************************ + // ADD EVENT LISTENERS + // ************************************************************************ + this.addEventListener("mousemove", this._onmousemove); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseout", this._onmouseout); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header" }); + + + +/* +--------------------------------------------------------------------------- + RESIZE SYNC +--------------------------------------------------------------------------- +*/ + +qx.Proto._syncColumnWidth = function(vWidth) +{ + var vChildren = this.getChildren(); + var vColumn = Math.ceil(vChildren.indexOf(this._resizeCell) / 2); + + this.getParent().getPane().setColumnWidth(vColumn, vWidth); +} + +qx.Proto._syncResizeLine = function() +{ + qx.ui.core.Widget.flushGlobalQueues(); + + var vParent = this.getParent(); + var vLine = vParent.getResizeLine(); + var vLeft = qx.html.Location.getPageBoxLeft(this._resizeSeparator.getElement()) - qx.html.Location.getPageInnerLeft(this.getElement()); + var vTop = qx.html.Dimension.getBoxHeight(vParent.getHeader().getElement()); + var vHeight = qx.html.Dimension.getBoxHeight(vParent.getElement()) - vTop; + + vLine._applyRuntimeTop(vTop); + vLine._applyRuntimeHeight(vHeight); + vLine._applyRuntimeLeft(vLeft); + + vLine.removeStyleProperty("visibility"); +} + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._mshtml = qx.core.Client.getInstance().isMshtml(); + +qx.Proto._onmousemove = function(e) +{ + if (!this.getParent().getResizable()) { + return; + } + + if (this._resizingActive) + { + // Slow down mshtml a bit + if (this._mshtml) + { + if ((new Date).valueOf() - this._last < 50) { + return; + } + + this._last = (new Date).valueOf(); + } + + var vNewLeft = e.getPageX(); + var vSizeDiff = vNewLeft - this._resizeStart; + var vCell = this._resizeCell; + + vCell.setWidth(Math.max(4, vCell.getWidth() + vSizeDiff)); + this._resizeStart = vNewLeft; + + if (this.getParent().getLiveResize()) + { + this._syncColumnWidth(vCell._computeBoxWidth()); + } + else + { + this._syncResizeLine(); + } + } + else + { + var vTarget = e.getTarget(); + var vEventPos = e.getPageX(); + var vTargetPosLeft = qx.html.Location.getPageBoxLeft(vTarget.getElement()); + var vTargetPosRight = vTargetPosLeft + qx.html.Dimension.getBoxWidth(vTarget.getElement()); + + var vResizeCursor = false; + var vResizeSeparator = null; + + if (vTarget instanceof qx.ui.listview.HeaderSeparator) + { + vResizeCursor = true; + vResizeSeparator = vTarget; + } + else if ((vEventPos - vTargetPosLeft) <= 10) + { + // Ignore first column + if (!vTarget.isFirstChild()) + { + vResizeCursor = true; + vResizeSeparator = vTarget.getPreviousSibling(); + } + } + else if ((vTargetPosRight - vEventPos) <= 10) + { + vResizeCursor = true; + vResizeSeparator = vTarget.getNextSibling(); + } + + if (!(vResizeSeparator instanceof qx.ui.listview.HeaderSeparator)) + { + vResizeSeparator = vTarget = vResizeCursor = null; + } + + // Check if child is marked as resizable + else if (vResizeSeparator) + { + var vResizeCell = vResizeSeparator.getPreviousSibling(); + + if (vResizeCell && (vResizeCell._computedWidthTypePercent || vResizeCell._config.resizable == false)) { + vResizeSeparator = vTarget = vResizeCursor = null; + } + } + + // Apply global cursor + this.getTopLevelWidget().setGlobalCursor(vResizeCursor ? "e-resize" : null); + + // Store data for mousedown + this._resizeSeparator = vResizeSeparator; + this._resizeTarget = vTarget; + } +} + +qx.Proto._onmousedown = function(e) +{ + if (!this._resizeSeparator) { + return; + } + + this._resizingActive = true; + this._resizeStart = e.getPageX(); + this._resizeCell = this._resizeSeparator.getPreviousSibling(); + + if (!this.getParent().getLiveResize()) { + this._syncResizeLine(); + } + + this.setCapture(true); +} + +qx.Proto._onmouseup = function(e) +{ + if (!this._resizingActive) { + return; + } + + this._syncColumnWidth(this._resizeCell.getBoxWidth()); + + this.setCapture(false); + this.getTopLevelWidget().setGlobalCursor(null); + + // Remove hover effect + this._resizeTarget.removeState("over"); + + // Hide resize line + this.getParent().getResizeLine().setStyleProperty("visibility", "hidden"); + + this._cleanupResizing(); +} + +qx.Proto._onmouseout = function(e) +{ + if (!this.getCapture()) { + this.getTopLevelWidget().setGlobalCursor(null); + } +} + +qx.Proto._cleanupResizing = function() +{ + delete this._resizingActive; + + delete this._resizeSeparator; + delete this._resizeTarget; + delete this._resizeStart; + delete this._resizeCell; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._cleanupResizing(); + + this.removeEventListener("mousemove", this._onmousemove); + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseout", this._onmouseout); + + this._columns = null; + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js new file mode 100644 index 0000000000..3d0e21cb42 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js @@ -0,0 +1,259 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) +#embed(qx.widgettheme/arrows/up.gif) +#embed(qx.widgettheme/arrows/down.gif) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.HeaderCell", qx.ui.basic.Atom, +function(vConfig, vId) +{ + qx.ui.basic.Atom.call(this, vConfig.label, vConfig.icon, vConfig.iconWidth, vConfig.iconHeight, vConfig.flash); + + // Text Overflow + this.setStyleProperty("textOverflow", "ellipsis"); + + + // ************************************************************************ + // STORE REFERENCE TO CONFIG ENTRY + // ************************************************************************ + this._config = vConfig; + this._id = vId; + + + // ************************************************************************ + // ARGUMENTS + // ************************************************************************ + this.setWidth(typeof vConfig.width === "undefined" ? "auto" : vConfig.width); + + if (vConfig.minWidth != null) { + this.setMinWidth(vConfig.minWidth); + } + + if (vConfig.maxWidth != null) { + this.setMaxWidth(vConfig.maxWidth); + } + + + // ************************************************************************ + // ADDITIONAL CHILDREN + // ************************************************************************ + + // Re-Enable flex support + this.getLayoutImpl().setEnableFlexSupport(true); + + this._spacer = new qx.ui.basic.HorizontalSpacer; + + this._arrowup = new qx.ui.basic.Image("widget/arrows/up.gif"); + this._arrowup.setVerticalAlign("middle"); + this._arrowup.setDisplay(false); + + this._arrowdown = new qx.ui.basic.Image("widget/arrows/down.gif"); + this._arrowdown.setVerticalAlign("middle"); + this._arrowdown.setDisplay(false); + + this.add(this._spacer, this._arrowup, this._arrowdown); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header-cell" }); +qx.OO.addProperty({ name : "sortOrder", type : "string", allowNull : true, possibleValues : [ "ascending", "descending" ] }); + +qx.Class.C_SORT_ASCENDING = "ascending"; +qx.Class.C_SORT_DESCENDING = "descending"; + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +} + +qx.Proto.getNextSortOrder = function() +{ + var vCurrentSortOrder = this.getSortOrder(); + + switch(vCurrentSortOrder) + { + case qx.ui.listview.HeaderCell.C_SORT_ASCENDING: + return qx.ui.listview.HeaderCell.C_SORT_DESCENDING; + + default: + return qx.ui.listview.HeaderCell.C_SORT_ASCENDING; + } +} + +qx.Proto.updateSort = function() +{ + + var vListView = this.getView(); + var vData = vListView.getData(); + var vFieldId = this._id; + var vSortProp = this._config.sortProp || "text"; + var vSortMethod = this._config.sortMethod || qx.util.Compare.byString; + + vData.sort(function(a, b) { + return vSortMethod(a[vFieldId][vSortProp], b[vFieldId][vSortProp]); + }); + + if (this.getSortOrder() == qx.ui.listview.HeaderCell.C_SORT_DESCENDING) { + vData.reverse(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySortOrder = function(propValue, propOldValue, propData) +{ + var vListView = this.getView(); + + switch(propValue) + { + case qx.ui.listview.HeaderCell.C_SORT_ASCENDING: + this._arrowup.setDisplay(true); + this._arrowdown.setDisplay(false); + + vListView.setSortBy(this._id); + break; + + case qx.ui.listview.HeaderCell.C_SORT_DESCENDING: + this._arrowup.setDisplay(false); + this._arrowdown.setDisplay(true); + + vListView.setSortBy(this._id); + break; + + default: + this._arrowup.setDisplay(false); + this._arrowdown.setDisplay(false); + + if (vListView.getSortBy() == this._id) { + vListView.setSortBy(null); + } + } + + if (propValue) + { + this.updateSort(); + vListView.update(); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) { + this.addState("over"); +} + +qx.Proto._onmouseout = function(e) { + this.removeState("over"); +} + +qx.Proto._onmouseup = function(e) +{ + if (!this._config.sortable || this.getParent()._resizeSeparator) { + return; + } + + this.setSortOrder(this.getNextSortOrder()); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._config; + + if (this._spacer) + { + this._spacer.dispose(); + this._spacer = null; + } + + if (this._arrowup) + { + this._arrowup.dispose(); + this._arrowup = null; + } + + if (this._arrowdown) + { + this._arrowdown.dispose(); + this._arrowdown = null; + } + + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js new file mode 100644 index 0000000000..b2124fda0f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js @@ -0,0 +1,32 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.HeaderSeparator", qx.ui.basic.Terminator, +function() { + qx.ui.basic.Terminator.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header-separator" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js new file mode 100644 index 0000000000..a4226b88e7 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js @@ -0,0 +1,375 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ListView", qx.ui.layout.VerticalBoxLayout, +function(vData, vColumns) +{ + // ************************************************************************ + // REFERENCES + // ************************************************************************ + + this._data = vData; + this._columns = vColumns; + + + + // ************************************************************************ + // OBJECTS + // ************************************************************************ + + this._header = new qx.ui.listview.Header(vColumns); + this._frame = new qx.ui.layout.HorizontalBoxLayout; + this._pane = new qx.ui.listview.ListViewPane(vData, vColumns); + this._scroll = new qx.ui.layout.CanvasLayout; + this._scrollContent = new qx.ui.basic.Terminator; + this._resizeLine = new qx.ui.basic.Terminator; + + + + // ************************************************************************ + // SUPERCLASS CONSTRUCTOR + // ************************************************************************ + + qx.ui.layout.VerticalBoxLayout.call(this); + + + + // ************************************************************************ + // HEADER + // ************************************************************************ + + this._header.setParent(this); + + + + // ************************************************************************ + // FRAME + // ************************************************************************ + + this._frame.setParent(this); + this._frame.setHeight("1*"); + this._frame.setWidth(null); + + + + // ************************************************************************ + // PANE + // ************************************************************************ + + this._pane.setParent(this._frame); + + + + // ************************************************************************ + // SCROLL AREA + // ************************************************************************ + + this._scroll.setWidth("auto"); + this._scroll.setOverflow("scrollY"); + this._scroll.setParent(this._frame); + this._scroll.enableInlineEvent("scroll"); + this._scroll.addEventListener("scroll", this._onscroll, this); + + + + // ************************************************************************ + // SCROLL CONTENT + // ************************************************************************ + + this._scrollContent.setWidth(1); + this._scrollContent.setParent(this._scroll); + + + + + // ************************************************************************ + // RESIZE LINE + // ************************************************************************ + + this._resizeLine.setBackgroundColor("#D6D5D9"); + this._resizeLine.setWidth(1); + this._resizeLine.setParent(this); + + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mousedown", this._onmousedown); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view" }); + +qx.OO.addProperty({ name : "resizable", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "liveResize", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "sortBy", type : "string" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getData = function() { + return this._data; +} + +qx.Proto.getColumns = function() { + return this._columns; +} + +qx.Proto.getHeader = function() { + return this._header; +} + +qx.Proto.getFrame = function() { + return this._frame; +} + +qx.Proto.getPane = function() { + return this._pane; +} + +qx.Proto.getScroll = function() { + return this._scroll; +} + +qx.Proto.getScrollContent = function() { + return this._scrollContent; +} + +qx.Proto.getResizeLine = function() { + return this._resizeLine; +} + +qx.Proto.update = function() +{ + this.updateScrollBar(); + this.updateContent(); + + // ignore updateLayout here, as it is mostly initially used +} + +qx.Proto.updateScrollBar = function() { + this._scrollContent.setHeight((this._data.length * this._pane._rowHeight) + this._pane._rowHeight); +} + +/*! + Bugfix for gecko 1.8 (the one released with firefox 1.5) + Overflow updates if content gets smaller are problematic + https://bugzilla.mozilla.org/show_bug.cgi?id=320106 +*/ +if (qx.core.Client.getInstance().isGecko() && qx.core.Client.getInstance().getVersion() >= 1.8) +{ + qx.Proto._updateScrollBar = qx.Proto.updateScrollBar; + + qx.Proto.updateScrollBar = function() + { + this._updateScrollBar(); + + this._scroll.setStyleProperty("height", "0px"); + this._scroll.forceHeight(0); + this._scroll.setHeight(null); + } +} + +qx.Proto.updateContent = function() { + this.getPane()._updateRendering(true); +} + +qx.Proto.updateLayout = function() { + this.getPane()._updateLayout(); +} + +qx.Proto.updateSort = function() +{ + var vSortBy = this.getSortBy(); + + if (!vSortBy) { + return; + } + + var vCell = this._getHeaderCell(vSortBy); + + if (vCell) { + vCell.updateSort(); + } +} + +qx.Proto._getHeaderCell = function(vCellId) +{ + var vNewEntry = this._columns[vCellId]; + return vNewEntry ? vNewEntry.headerCell : null; +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySortBy = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + var vOldCell = this._getHeaderCell(propOldValue); + + if (vOldCell) { + vOldCell.setSortOrder(null); + } + } + + if (propValue) + { + var vNewCell = this._getHeaderCell(propValue); + + if (vNewCell && vNewCell.getSortOrder() == null) { + vNewCell.setSortOrder(qx.ui.listview.HeaderCell.C_SORT_ASCENDING); + } + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onscroll = function(e) { + this._pane._onscroll(e); +} + +qx.Proto._onmousedown = function(e) { + this.getFocusRoot().setActiveChild(this.getPane()); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + qx.ui.layout.VerticalBoxLayout.prototype._handleDisplayableCustom.call(this, vDisplayable, vParent, vHint); + + if (vDisplayable) + { + this.updateLayout(); + this.updateScrollBar(); + this.updateContent(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._header) + { + this._header.dispose(); + this._header = null; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + if (this._scroll) + { + this._scroll.dispose(); + this._scroll = null; + } + + if (this._scrollContent) + { + this._scrollContent.dispose(); + this._scrollContent = null; + } + + if (this._resizeLine) + { + this._resizeLine.dispose(); + this._resizeLine = null; + } + + delete this._columns; + delete this._data; + + this.removeEventListener("mousedown", this._onmousedown); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js new file mode 100644 index 0000000000..afd5077c3e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js @@ -0,0 +1,563 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) +#load(qx.ui.listview.ContentCellHtml) +#load(qx.ui.listview.ContentCellIconHtml) +#load(qx.ui.listview.ContentCellImage) +#load(qx.ui.listview.ContentCellLink) +#load(qx.ui.listview.ContentCellText) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ListViewPane", qx.ui.layout.GridLayout, +function(vData, vColumns) +{ + qx.ui.layout.GridLayout.call(this); + + // ************************************************************************ + // DATA + // ************************************************************************ + // Add aliases for data tables + this._data = vData; + this._columns = vColumns; + + + // ************************************************************************ + // INITIALIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.VirtualSelectionManager(this); + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + // Add handling for mouse wheel events + // Needed because the virtual scroll area does not fire browser + // understandable events above this pane. + this.addEventListener("mousewheel", this._onmousewheel); + + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keypress", this._onkeypress); +}); + +qx.OO.changeProperty({ name : "appearance", + type : "string", + defaultValue : "list-view-pane" + }); + +qx.Proto._rowHeight = 16; + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +} + + + + + + +/* +--------------------------------------------------------------------------- + UPDATER +--------------------------------------------------------------------------- +*/ + +qx.Proto._lastRowCount = 0; + +qx.Proto._updateLayout = function(vUpdate) +{ + // this.debug("InnerHeight: " + this._computeInnerHeight()); + // this.debug("BoxHeight: " + this._computeBoxHeight()); + // return + + var vColumns = this._columns; + var vRowCount = Math.ceil(this.getInnerHeight() / this._rowHeight); + var vData = this._data; + var vCell; + + // this.debug("Row-Count: " + this._lastRowCount + " => " + vRowCount); + + // Sync cells: Add new ones and configure them + if (vRowCount > this._lastRowCount) + { + for (var i=this._lastRowCount, j=0; i<vRowCount; i++, j=0) + { + for (var vCol in vColumns) + { + vCell = new vColumns[vCol].contentClass; + + this.add(vCell, j++, i); + + if (vColumns[vCol].align) { + vCell.setStyleProperty("textAlign", + vColumns[vCol].align); + } + } + } + } + + // Sync cells: Remove existing ones and dispose them + else if (this._lastRowCount > vRowCount) + { + var vChildren = this.getChildren(); + var vChildrenLength = vChildren.length - 1; + + for (var i=this._lastRowCount; i>vRowCount; i--) + { + for (var vCol in vColumns) + { + vCell = vChildren[vChildrenLength--]; + this.remove(vCell); + vCell.dispose(); + } + } + } + + // Update row and column count + this.setRowCount(vRowCount); + if (!vUpdate) { + this.setColumnCount(qx.lang.Object.getLength(vColumns)); + } + + // Apply height to all rows + for (var i=0; i<vRowCount; i++) { + this.setRowHeight(i, this._rowHeight); + } + + if (!vUpdate) + { + // Apply width and alignment to all columns + var vCount = 0; + for (var vCol in vColumns) + { + this.setColumnHorizontalAlignment(vCount, vColumns[vCol].align); + this.setColumnWidth(vCount, vColumns[vCol].width); + + vCount++; + } + } + + // Store last row count + this._lastRowCount = vRowCount; +} + +qx.Proto._currentScrollTop = -1; + +qx.Proto._updateRendering = function(vForce) +{ + if (this._updatingRendering) { + return; + } + + var vScrollTop = (this._initialLayoutDone + ? this.getView().getScroll().getScrollTop() + : 0); + + this._updatingRendering = true; + this._currentScrollTop = vScrollTop; + + for (var i=0; i<this._rowCount; i++) { + this._updateRow(i); + } + + delete this._updatingRendering; +} + +qx.Proto._updateRow = function(vRelativeRow) +{ + var vData = this._data; + var vRowOffset = Math.floor(this._currentScrollTop / this._rowHeight); + + var vColumnCount = this.getColumnCount(); + var vColumns = this._columns; + + var vChildren = this.getVisibleChildren(); + var vChild, vEntry, vCol; + + var j=0; + + for (vCol in vColumns) + { + vEntry = vData[vRowOffset+vRelativeRow]; + vChild = vChildren[vColumnCount*vRelativeRow+(j++)]; + + if (vChild) + { + if (vEntry && vEntry._selected) { + vChild.addState("selected"); + } else { + vChild.removeState("selected"); + } + vChild.set(vEntry + ? vEntry[vCol] + : vColumns[vCol].empty || vColumns[vCol].contentClass.empty); + } + } +} + +qx.Proto._onscroll = function(e) { + this._updateRendering(); +} + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._changeInnerHeight = function(vNew, vOld) +{ + this._updateLayout(true); + this._updateRendering(true); + + return qx.ui.layout.GridLayout.prototype._changeInnerHeight.call(this, + vNew, + vOld); +} + + + + + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getListViewTarget = function(e) +{ + var vEventTop = e.getPageY(); + var vPaneTop = qx.html.Location.getPageInnerTop(this.getElement()); + var vItemNo = Math.floor(this._currentScrollTop / this._rowHeight) + + Math.floor((vEventTop - vPaneTop) / this._rowHeight); + + return this._data[vItemNo]; +} + +qx.Proto.getSelectedItem = function() { + return this.getSelectedItems()[0]; +} + +qx.Proto.getSelectedItems = function() { + return this._manager.getSelectedItems(); +} + +qx.Proto.getData = function() { + return this._data; +} + +// use static row height +qx.Proto.getItemHeight = function(vItem) { + return this._rowHeight; +} + +// use the full inner width of the pane +qx.Proto.getItemWidth = function(vItem) { + return qx.html.Dimension.getInnerWidth(this.getElement()); +} + +qx.Proto.getItemLeft = function(vItem) { + return 0; +} + +qx.Proto.getItemTop = function(vItem) { + return this._data.indexOf(vItem) * this._rowHeight; +} + + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousewheel = function(e) +{ + var vScroll = this.getView().getScroll(); + vScroll.setScrollTop(vScroll.getScrollTop() - (e.getWheelDelta() * 20)); +} + +qx.Proto._onmouseover = function(e) +{ + var vTarget = this.getListViewTarget(e); + if (vTarget) { + this._manager.handleMouseOver(vTarget, e); + } +} + +qx.Proto._onmousedown = function(e) +{ + var vTarget = this.getListViewTarget(e); + if (vTarget) { + this._manager.handleMouseDown(vTarget, e); + } +} + +qx.Proto._onmouseup = function(e) +{ + var vTarget = this.getListViewTarget(e); + if (vTarget) { + this._manager.handleMouseUp(vTarget, e); + } +} + +qx.Proto._onclick = function(e) +{ + var vTarget = this.getListViewTarget(e); + if (vTarget) { + this._manager.handleClick(vTarget, e); + } +} + +qx.Proto._ondblclick = function(e) +{ + var vTarget = this.getListViewTarget(e); + if (vTarget) { + this._manager.handleDblClick(vTarget, e); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeypress = function(e) +{ + this._manager.handleKeyPress(e); + e.preventDefault(); +} + + + + + + +/* +--------------------------------------------------------------------------- + MANAGER SELECTION +--------------------------------------------------------------------------- +*/ + +qx.Proto._updateSelectionState = function(vItem, vIsSelected) +{ + vItem._selected = vIsSelected; + this._updateItem(vItem); +} + +qx.Proto._updateAnchorState = function(vItem, vIsAnchor) +{ + vItem._anchor = vIsAnchor; + this._updateItem(vItem); +} + +qx.Proto._updateLeadState = function(vItem, vIsLead) +{ + vItem._lead = vIsLead; + this._updateItem(vItem); +} + +qx.Proto.scrollItemIntoView = function(vItem, vAlignLeftTop) +{ + this.scrollItemIntoViewX(vItem, vAlignLeftTop); + this.scrollItemIntoViewY(vItem, vAlignLeftTop); +} + +qx.Proto.scrollItemIntoViewX = function(vItem, vAlignLeft) { + // this.error("Not implemented in qx.ui.listview.ListViewPane!"); +} + +qx.Proto.scrollItemIntoViewY = function(vItem, vAlignTop) +{ + var vItems = this._data; + var vOffset = vItems.indexOf(vItem) * this._rowHeight; + var vHeight = this._rowHeight; + + // normalize client height (we want that the item is fully visible) + var vParentHeight = (Math.floor(this.getClientHeight() / this._rowHeight) * + this._rowHeight); + var vParentScrollTop = this._currentScrollTop; + + var vNewScrollTop = null; + + if (vAlignTop) + { + vNewScrollTop = vOffset; + } + else if (vAlignTop == false) + { + vNewScrollTop = vOffset + vHeight - vParentHeight; + } + else if (vHeight > vParentHeight || vOffset < vParentScrollTop) + { + vNewScrollTop = vOffset; + } + else if ((vOffset + vHeight) > (vParentScrollTop + vParentHeight)) + { + vNewScrollTop = vOffset + vHeight - vParentHeight; + } + + if (vNewScrollTop != null) { + this.getView().getScroll().setScrollTop(vNewScrollTop); + } +} + +qx.Proto.setScrollTop = function(vScrollTop) +{ + this.getView().getScroll().setScrollTop(vScrollTop); + this._updateRendering(); +} + +qx.Proto.getScrollTop = function() { + return this._currentScrollTop; +} + +qx.Proto.setScrollLeft = function() { + this.error("Not implemented in qx.ui.listview.ListViewPane!"); +} + +qx.Proto.getScrollLeft = function() { + return 0; +} + +qx.Proto.isItemVisible = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + var vRowLength = Math.ceil(this.getClientHeight() / this._rowHeight); + + return vIndex >= vRowStart && vIndex <= (vRowStart + vRowLength); +} + +qx.Proto.getRelativeItemPosition = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + + return vIndex - vRowStart; +} + +qx.Proto._updateItem = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + var vRowLength = Math.ceil(this.getClientHeight() / this._rowHeight); + + if (vIndex < vRowStart || vIndex > (vRowStart + vRowLength)) { + return; + } + + this._updateRow(vIndex - vRowStart); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + this.removeEventListener("mousewheel", this._onmousewheel); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("click", this._onclick); + this.removeEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.removeEventListener("keypress", this._onkeypress); + + + // ************************************************************************ + // DATA + // ************************************************************************ + delete this._data; + delete this._columns; + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + return qx.ui.layout.GridLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Button.js new file mode 100644 index 0000000000..55a8b5795f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Button.js @@ -0,0 +1,360 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) +#embed(qx.widgettheme/arrows/next.gif) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Button", qx.ui.layout.HorizontalBoxLayout, +function(vLabel, vIcon, vCommand, vMenu) +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + + // ************************************************************************ + // LAYOUT + // ************************************************************************ + + var io = this._iconObject = new qx.ui.basic.Image; + io.setWidth(16); + io.setAnonymous(true); + + var lo = this._labelObject = new qx.ui.basic.Label; + lo.setAnonymous(true); + lo.setSelectable(false); + + var so = this._shortcutObject = new qx.ui.basic.Label; + so.setAnonymous(true); + so.setSelectable(false); + + var ao = this._arrowObject = new qx.ui.basic.Image("widget/arrows/next.gif"); + ao.setAnonymous(true); + + + // ************************************************************************ + // INIT + // ************************************************************************ + + if (vLabel != null) { + this.setLabel(vLabel); + } + + if (vIcon != null) { + this.setIcon(vIcon); + } + + if (vCommand != null) { + this.setCommand(vCommand); + qx.locale.Manager.getInstance().addEventListener("changeLocale", function(e) { + this._modifyCommand(vCommand, vCommand); + }, this) + } + + if (vMenu != null) { + this.setMenu(vMenu); + } + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseup", this._onmouseup); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-button" }); + +qx.OO.addProperty({ name : "icon", type : "string" }); +qx.OO.addProperty({ name : "label" }); +qx.OO.addProperty({ name : "menu", type : "object" }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto._hasIcon = false; +qx.Proto._hasLabel = false; +qx.Proto._hasShortcut = false; +qx.Proto._hasMenu = false; + +qx.Proto.hasIcon = function() { + return this._hasIcon; +} + +qx.Proto.hasLabel = function() { + return this._hasLabel; +} + +qx.Proto.hasShortcut = function() { + return this._hasShortcut; +} + +qx.Proto.hasMenu = function() { + return this._hasMenu; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +qx.Proto.getShortcutObject = function() { + return this._shortcutObject; +} + +qx.Proto.getArrowObject = function() { + return this._arrowObject; +} + +qx.Proto.getParentMenu = function() +{ + var vParent = this.getParent(); + if (vParent) + { + vParent = vParent.getParent(); + + if (vParent && vParent instanceof qx.ui.menu.Menu) { + return vParent; + } + } + + return null; +} + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.MenuButtonLayoutImpl(this); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setEnabled(propValue); + } + + if (this._labelObject) { + this._labelObject.setEnabled(propValue); + } + + if (this._shortcutObject) { + this._shortcutObject.setEnabled(propValue); + } + + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyIcon = function(propValue, propOldValue, propData) +{ + this._iconObject.setSource(propValue); + + if (qx.util.Validation.isValidString(propValue)) + { + this._hasIcon = true; + + if (qx.util.Validation.isInvalidString(propOldValue)) { + this.addAtBegin(this._iconObject); + } + } + else + { + this._hasIcon = false; + this.remove(this._iconObject); + } + + return true; +} + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + this._labelObject.setHtml(propValue); + + if ((typeof propValue == "string" && propValue != "") || propValue instanceof qx.locale.LocalizedString) + { + this._hasLabel = true; + + if (!((typeof propOldValue == "string" && propOldValue != "") || propOldValue instanceof qx.locale.LocalizedString)) { + this.addAt(this._labelObject, this.getFirstChild() == this._iconObject ? 1 : 0); + } + } + else + { + this._hasLabel = false; + this.remove(this._labelObject); + } + + return true; +} + +qx.Proto._modifyCommand = function(propValue, propOldValue, propData) +{ + var vHtml = propValue ? propValue.toString() : ""; + + this._shortcutObject.setHtml(vHtml); + + if (qx.util.Validation.isValidString(vHtml)) + { + this._hasShortcut = true; + + var vOldHtml = propOldValue ? propOldValue.getShortcut() : ""; + + if (qx.util.Validation.isInvalidString(vOldHtml)) + { + if (this.getLastChild() == this._arrowObject) + { + this.addBefore(this._shortcutObject, this._arrowObject); + } + else + { + this.addAtEnd(this._shortcutObject); + } + } + } + else + { + this._hasShortcut = false; + this.remove(this._shortcutObject); + } + + return true; +} + +qx.Proto._modifyMenu = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._hasMenu = true; + + if (qx.util.Validation.isInvalidObject(propOldValue)) { + this.addAtEnd(this._arrowObject); + } + } + else + { + this._hasMenu = false; + this.remove(this._arrowObject); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseup = function(e) { + this.execute(); +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Dispose children + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + if (this._shortcutObject) + { + this._shortcutObject.dispose(); + this._shortcutObject = null; + } + + if (this._arrowObject) + { + this._arrowObject.dispose(); + this._arrowObject = null; + } + + // Remove event listeners + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js new file mode 100644 index 0000000000..efb02c035f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js @@ -0,0 +1,89 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) +#embed(qx.widgettheme/menu/checkbox.gif) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/*! + A checkbox for the menu system. +*/ +qx.OO.defineClass("qx.ui.menu.CheckBox", qx.ui.menu.Button, +function(vLabel, vCommand, vChecked) +{ + qx.ui.menu.Button.call(this, vLabel, "static/image/blank.gif", vCommand); + + if (vChecked != null) { + this.setChecked(vChecked); + } + + qx.manager.object.ImageManager.getInstance().preload("widget/menu/checkbox.gif"); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-check-box" }); +qx.OO.addProperty({ name : "name", type : "string" }); +qx.OO.addProperty({ name : "value", type : "string" }); +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false, getAlias : "isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + propValue ? this.addState("checked") : this.removeState("checked"); + this.getIconObject().setSource(propValue ? "widget/menu/checkbox.gif" : "static/image/blank.gif"); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EXECUTE +--------------------------------------------------------------------------- +*/ + +qx.Proto.execute = function() +{ + this.setChecked(!this.getChecked()); + qx.ui.menu.Button.prototype.execute.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js new file mode 100644 index 0000000000..23b060d821 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +/*! + A small helper class to create a special layout handler for qx.ui.menu.Menus +*/ +qx.OO.defineClass("qx.ui.menu.Layout", qx.ui.layout.VerticalBoxLayout, +function() +{ + qx.ui.layout.VerticalBoxLayout.call(this); + + this.setAnonymous(true); +}); + + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-layout" }); + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.MenuLayoutImpl(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js new file mode 100644 index 0000000000..bf4d584ae9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js @@ -0,0 +1,922 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Menu", qx.ui.popup.Popup, +function() +{ + qx.ui.popup.Popup.call(this); + + + // ************************************************************************ + // LAYOUT + // ************************************************************************ + + var l = this._layout = new qx.ui.menu.Layout; + this.add(l); + + + // ************************************************************************ + // TIMER + // ************************************************************************ + this._openTimer = new qx.client.Timer(this.getOpenInterval()); + this._openTimer.addEventListener("interval", this._onopentimer, this); + + this._closeTimer = new qx.client.Timer(this.getCloseInterval()); + this._closeTimer.addEventListener("interval", this._onclosetimer, this); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousemove", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + + this.remapChildrenHandlingTo(this._layout); +}); + +qx.Proto._remappingChildTable = [ "add", "remove", "addAt", "addAtBegin", "addAtEnd", "removeAt", "addBefore", "addAfter", "removeAll", "getFirstChild", "getFirstActiveChild", "getLastChild", "getLastActiveChild" ]; +qx.Proto._isFocusRoot = false; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu" }); + +qx.OO.addProperty({ name : "iconContentGap", type : "number", defaultValue : 4 }); +qx.OO.addProperty({ name : "labelShortcutGap", type : "number", defaultValue : 10 }); +qx.OO.addProperty({ name : "contentArrowGap", type : "number", defaultValue : 8 }); +qx.OO.addProperty({ name : "contentNonIconPadding", type : "number", defaultValue : 20 }); +qx.OO.addProperty({ name : "contentNonArrowPadding", type : "number", defaultValue : 8 }); + +qx.OO.addProperty({ name : "hoverItem", type : "object" }); +qx.OO.addProperty({ name : "openItem", type : "object" }); + +/** Widget that opened the menu */ +qx.OO.addProperty({ name : "opener", type : "object" }); + +/** reference to the parent menu if the menu is a submenu */ +qx.OO.addProperty({ name : "parentMenu", type : "object" }); + +qx.OO.addProperty({ name : "fastReopen", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "openInterval", type : "number", defaultValue : 250 }); +qx.OO.addProperty({ name : "closeInterval", type : "number", defaultValue : 250 }); + +qx.OO.addProperty({ name : "subMenuHorizontalOffset", type : "number", defaultValue : -3 }); +qx.OO.addProperty({ name : "subMenuVerticalOffset", type : "number", defaultValue : -2 }); + +qx.OO.addProperty({ name : "indentShortcuts", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getLayout = function() { + return this._layout; +} + +/** + * Returns if the given element is a child of this menu + * + * @param vElement {Object} element to test + * @param vButtonsOnly {boolean ? false} if true, child elements other than buttons + * will be ignored + */ +qx.Proto.isSubElement = function(vElement, vButtonsOnly) +{ + if ((vElement.getParent() === this._layout) + + //accept this as child, this can happen if a scrollbar is clicked upon in + //a context menu + ||((!vButtonsOnly) && (vElement === this))) { + return true; + } + + for (var a=this._layout.getChildren(), l=a.length, i=0; i<l; i++) + { + if (a[i].getMenu && a[i].getMenu() && a[i].getMenu().isSubElement(vElement, vButtonsOnly)) { + return true; + } + } + + return false; +} + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + // Intentionally bypass superclass and call super.super._beforeAppear + qx.ui.layout.CanvasLayout.prototype._beforeAppear.call(this); + + // register to menu manager as active widget + qx.manager.object.MenuManager.getInstance().add(this); + + // zIndex handling + this.bringToFront(); + + //setup as global active widget + this._makeActive(); +} + +qx.Proto._beforeDisappear = function() +{ + // Intentionally bypass superclass and call super.super._beforeDisappear + qx.ui.layout.CanvasLayout.prototype._beforeDisappear.call(this); + + // deregister as opened from qx.manager.object.MenuManager + qx.manager.object.MenuManager.getInstance().remove(this); + + // reset global active widget + this._makeInactive(); + + // reset properties on close + this.setHoverItem(null); + this.setOpenItem(null); + + // be sure that the opener button gets the correct state + var vOpener = this.getOpener(); + if (vOpener) { + vOpener.removeState("pressed"); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyHoverItem = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.removeState("over"); + } + + if (propValue) { + propValue.addState("over"); + } + + return true; +} + +qx.Proto._modifyOpenItem = function(propValue, propOldValue, propData) +{ + var vMakeActive = false; + + if (propOldValue) + { + var vOldSub = propOldValue.getMenu(); + + if (vOldSub) + { + vOldSub.setParentMenu(null); + vOldSub.setOpener(null); + vOldSub.hide(); + } + } + + if (propValue) + { + var vSub = propValue.getMenu(); + + if (vSub) + { + vSub.setOpener(propValue); + vSub.setParentMenu(this); + + var pl = propValue.getElement(); + var el = this.getElement(); + + vSub.setTop(qx.html.Location.getPageBoxTop(pl) + this.getSubMenuVerticalOffset()); + vSub.setLeft(qx.html.Location.getPageBoxLeft(el) + qx.html.Dimension.getBoxWidth(el) + this.getSubMenuHorizontalOffset()); + + vSub.show(); + + qx.ui.core.Widget.flushGlobalQueues(); + } + } + + return true; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + CREATE VARIABLES +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "maxIconWidth" }); +qx.OO.addCachedProperty({ name : "maxLabelWidth" }); +qx.OO.addCachedProperty({ name : "maxLabelWidthIncShortcut" }); +qx.OO.addCachedProperty({ name : "maxShortcutWidth" }); +qx.OO.addCachedProperty({ name : "maxArrowWidth" }); +qx.OO.addCachedProperty({ name : "maxContentWidth" }); + +qx.OO.addCachedProperty({ name : "iconPosition", defaultValue : 0 }); +qx.OO.addCachedProperty({ name : "labelPosition" }); +qx.OO.addCachedProperty({ name : "shortcutPosition" }); +qx.OO.addCachedProperty({ name : "arrowPosition" }); + +qx.OO.addCachedProperty({ name : "menuButtonNeededWidth" }); + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + MAX WIDTH COMPUTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeMaxIconWidth = function() +{ + var ch=this.getLayout().getChildren(), chl=ch.length, chc, m=0; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + + if (chc.hasIcon()) { + // Make static as long as not supported well + // m = Math.max(m, chc.getIconObject().getPreferredBoxWidth()); + m = Math.max(m, 16); + } + } + + return m; +} + +qx.Proto._computeMaxLabelWidth = function() +{ + var ch=this.getLayout().getChildren(), chl=ch.length, chc, m=0; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + + if (chc.hasLabel()) { + m = Math.max(m, chc.getLabelObject().getPreferredBoxWidth()); + } + } + + return m; +} + +qx.Proto._computeMaxLabelWidthIncShortcut = function() +{ + var ch=this.getLayout().getChildren(), chl=ch.length, chc, m=0; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + + if (chc.hasLabel() && chc.hasShortcut()) { + m = Math.max(m, chc.getLabelObject().getPreferredBoxWidth()); + } + } + + return m; +} + +qx.Proto._computeMaxShortcutWidth = function() +{ + var ch=this.getLayout().getChildren(), chl=ch.length, chc, m=0; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + + if (chc.hasShortcut()) { + m = Math.max(m, chc.getShortcutObject().getPreferredBoxWidth()); + } + } + + return m; +} + +qx.Proto._computeMaxArrowWidth = function() +{ + var ch=this.getLayout().getChildren(), chl=ch.length, chc, m=0; + + for (var i=0; i<chl; i++) + { + chc = ch[i]; + + if (chc.hasMenu()) { + // Make static as long as not supported well + // m = Math.max(m, chc.getArrowObject().getPreferredBoxWidth()); + m = Math.max(m, 4); + } + } + + return m; +} + +qx.Proto._computeMaxContentWidth = function() +{ + var vSum; + + var lw = this.getMaxLabelWidth(); + var sw = this.getMaxShortcutWidth(); + + if (this.getIndentShortcuts()) + { + var vTemp = sw+this.getMaxLabelWidthIncShortcut(); + + if (sw > 0) { + vTemp += this.getLabelShortcutGap(); + } + + vSum = Math.max(lw, vTemp); + } + else + { + vSum = lw + sw; + + if (lw > 0 && sw > 0) { + vSum += this.getLabelShortcutGap(); + } + } + + return vSum; +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + POSITION COMPUTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeIconPosition = function() { + return 0; +} + +qx.Proto._computeLabelPosition = function() +{ + var v = this.getMaxIconWidth(); + return v > 0 ? v + this.getIconContentGap() : this.getContentNonIconPadding(); +} + +qx.Proto._computeShortcutPosition = function() { + return this.getLabelPosition() + this.getMaxContentWidth() - this.getMaxShortcutWidth(); +} + +qx.Proto._computeArrowPosition = function() +{ + var v = this.getMaxContentWidth(); + return this.getLabelPosition() + (v > 0 ? v + this.getContentArrowGap() : v); +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + INVALIDATION OF CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._invalidateMaxIconWidth = function() +{ + this._cachedMaxIconWidth = null; + + this._invalidateLabelPosition(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxLabelWidth = function() +{ + this._cachedMaxLabelWidth = null; + + this._invalidateShortcutPosition(); + this._invalidateMaxLabelWidthIncShortcut(); + this._invalidateMaxContentWidth(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxShortcutWidth = function() +{ + this._cachedMaxShortcutWidth = null; + + this._invalidateArrowPosition(); + this._invalidateMaxContentWidth(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxLabelWidth = function() +{ + this._cachedMaxArrowWidth = null; + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateLabelPosition = function() +{ + this._cachedLabelPosition = null; + this._invalidateShortcutPosition(); +} + +qx.Proto._invalidateShortcutPosition = function() +{ + this._cachedShortcutPosition = null; + this._invalidateArrowPosition(); +} + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + NEEDED WIDTH COMPUTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeMenuButtonNeededWidth = function() +{ + var vSum = 0; + + var vMaxIcon = this.getMaxIconWidth(); + var vMaxContent = this.getMaxContentWidth(); + var vMaxArrow = this.getMaxArrowWidth(); + + if (vMaxIcon > 0) + { + vSum += vMaxIcon; + } + else + { + vSum += this.getContentNonIconPadding(); + } + + if (vMaxContent > 0) + { + if (vMaxIcon > 0) { + vSum += this.getIconContentGap(); + } + + vSum += vMaxContent; + } + + if (vMaxArrow > 0) + { + if (vMaxIcon > 0 || vMaxContent > 0) { + vSum += this.getContentArrowGap(); + } + + vSum += vMaxArrow; + } + else + { + vSum += this.getContentNonArrowPadding(); + } + + return vSum; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + /* ------------------------------ + HANDLE PARENT MENU + ------------------------------ */ + + // look if we have a parent menu + // if so we need to stop the close event started there + var vParent = this.getParentMenu(); + + if (vParent) + { + // stop the close event + vParent._closeTimer.stop(); + + // look if we have a opener, too (normally this should be) + var vOpener = this.getOpener(); + + // then setup it to look hovered + if (vOpener) { + vParent.setHoverItem(vOpener); + } + } + + + + + /* ------------------------------ + HANDLING FOR HOVERING MYSELF + ------------------------------ */ + + var t = e.getTarget(); + + if (t == this) + { + this._openTimer.stop(); + this._closeTimer.start(); + + this.setHoverItem(null); + + return; + } + + + + + /* ------------------------------ + HANDLING FOR HOVERING ITEMS + ------------------------------ */ + + var vOpen = this.getOpenItem(); + + // if we have a open item + if (vOpen) + { + this.setHoverItem(t); + this._openTimer.stop(); + + // if the new one has also a sub menu + if (t.hasMenu()) + { + // check if we should use fast reopen (this will open the menu instantly) + if (this.getFastReopen()) + { + this.setOpenItem(t); + this._closeTimer.stop(); + } + + // otherwise we use the default timer interval + else + { + this._openTimer.start(); + } + } + + // otherwise start the close timer for the old menu + else + { + this._closeTimer.start(); + } + } + + // otherwise handle the mouseover and restart the timer + else + { + this.setHoverItem(t); + + // stop timer for the last open request + this._openTimer.stop(); + + // and restart it if the new one has a menu, too + if (t.hasMenu()) { + this._openTimer.start(); + } + } +} + +qx.Proto._onmouseout = function(e) +{ + // stop the open timer (for any previous open requests) + this._openTimer.stop(); + + // start the close timer to hide a menu if needed + var t = e.getTarget(); + if (t != this && t.hasMenu()) { + this._closeTimer.start(); + } + + // reset the current hover item + this.setHoverItem(null); +} + +qx.Proto._onopentimer = function(e) +{ + // stop the open timer (we need only the first interval) + this._openTimer.stop(); + + // if we have a item which is currently hovered, open it + var vHover = this.getHoverItem(); + if (vHover && vHover.hasMenu()) { + this.setOpenItem(vHover); + } +} + +qx.Proto._onclosetimer = function(e) +{ + // stop the close timer (we need only the first interval) + this._closeTimer.stop(); + + // reset the current opened item + this.setOpenItem(null); +} + +/*! + Wraps key events to target functions +*/ +qx.Proto._onkeydown = function(e) +{ + if (e.getKeyIdentifier() == "Enter") { + this._onkeydown_enter(e); + } + e.preventDefault(); +}; + + +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Up": + this._onkeypress_up(e); + break; + + case "Down": + this._onkeypress_down(e); + break; + + case "Left": + this._onkeypress_left(e); + break; + + case "Right": + this._onkeypress_right(e); + break; + + default: + return; + } + + // Stop all matching events + e.preventDefault(); +}; + + +qx.Proto._onkeypress_up = function(e) +{ + var vHover = this.getHoverItem(); + var vPrev = vHover ? vHover.isFirstChild() ? this.getLastActiveChild() : vHover.getPreviousActiveSibling([qx.ui.menu.Separator]) : this.getLastActiveChild(); + + this.setHoverItem(vPrev); +}; + +qx.Proto._onkeypress_down = function(e) +{ + var vHover = this.getHoverItem(); + var vNext = vHover ? vHover.isLastChild() ? this.getFirstActiveChild() : vHover.getNextActiveSibling([qx.ui.menu.Separator]) : this.getFirstActiveChild(); + + this.setHoverItem(vNext); +}; + + +qx.Proto._onkeypress_left = function(e) +{ + var vOpener = this.getOpener(); + + // Jump to the "parent" qx.ui.menu.Menu + if (vOpener instanceof qx.ui.menu.Button) + { + var vOpenerParent = this.getOpener().getParentMenu(); + + vOpenerParent.setOpenItem(null); + vOpenerParent.setHoverItem(vOpener); + + vOpenerParent._makeActive(); + } + + // Jump to the previous ToolBarMenuButton + else if (vOpener instanceof qx.ui.toolbar.MenuButton) + { + var vToolBar = vOpener.getParentToolBar(); + + // change active widget to new button + this.getFocusRoot().setActiveChild(vToolBar); + + // execute toolbars keydown implementation + vToolBar._onkeypress(e); + } +}; + + +qx.Proto._onkeypress_right = function(e) +{ + var vHover = this.getHoverItem(); + + if (vHover) + { + var vMenu = vHover.getMenu(); + + if (vMenu) + { + this.setOpenItem(vHover); + + // mark first item in new submenu + vMenu.setHoverItem(vMenu.getFirstActiveChild()); + + return; + } + } + else if (!this.getOpenItem()) + { + var vFirst = this.getLayout().getFirstActiveChild(); + + if (vFirst) { + vFirst.hasMenu() ? this.setOpenItem(vFirst) : this.setHoverItem(vFirst); + } + } + + // Jump to the next ToolBarMenuButton + var vOpener = this.getOpener(); + + if (vOpener instanceof qx.ui.toolbar.MenuButton) + { + var vToolBar = vOpener.getParentToolBar(); + + // change active widget to new button + this.getFocusRoot().setActiveChild(vToolBar); + + // execute toolbars keydown implementation + vToolBar._onkeypress(e); + } + else if (vOpener instanceof qx.ui.menu.Button && vHover) + { + // search for menubar if existing + // menu -> button -> menu -> button -> menu -> menubarbutton -> menubar + + var vOpenerParent = vOpener.getParentMenu(); + + while (vOpenerParent && vOpenerParent instanceof qx.ui.menu.Menu) + { + vOpener = vOpenerParent.getOpener(); + + if (vOpener instanceof qx.ui.menu.Button) + { + vOpenerParent = vOpener.getParentMenu(); + } + else + { + if (vOpener) { + vOpenerParent = vOpener.getParent(); + } + + break; + } + } + + if (vOpenerParent instanceof qx.ui.toolbar.Part) { + vOpenerParent = vOpenerParent.getParent(); + } + + if (vOpenerParent instanceof qx.ui.toolbar.ToolBar) + { + // jump to next menubarbutton + this.getFocusRoot().setActiveChild(vOpenerParent); + vOpenerParent._onkeypress(e); + } + } +} + +qx.Proto._onkeydown_enter = function(e) +{ + var vHover = this.getHoverItem(); + if (vHover) { + vHover.execute(); + } + + qx.manager.object.MenuManager.getInstance().update(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._layout) + { + this._layout.dispose(); + this._layout = null; + } + + if (this._openTimer) + { + this._openTimer.dispose(); + this._openTimer = null; + } + + if (this._closeTimer) + { + this._closeTimer.dispose(); + this._closeTimer = null; + } + + // Remove event listeners + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousemove", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js new file mode 100644 index 0000000000..216b6238c6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js @@ -0,0 +1,122 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) +#embed(qx.widgettheme/menu/radiobutton.gif) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.RadioButton", qx.ui.menu.CheckBox, +function(vLabel, vCommand, vChecked) +{ + qx.ui.menu.CheckBox.call(this, vLabel, vCommand, vChecked); + + qx.manager.object.ImageManager.getInstance().preload("widget/menu/radiobutton.gif"); +}); + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-radio-button" }); + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons +*/ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + var vManager = this.getManager(); + + if (vManager) + { + if (propValue) + { + vManager.setSelected(this); + } + else if (vManager.getSelected() == this) + { + vManager.setSelected(null); + } + } + + propValue ? this.addState("checked") : this.removeState("checked"); + this.getIconObject().setSource(propValue ? "widget/menu/radiobutton.gif" : "static/image/blank.gif"); + + return true; +} + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propData) +{ + if (this.getManager()) { + this.getManager().setName(propValue); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EXECUTE +--------------------------------------------------------------------------- +*/ + +qx.Proto.execute = function() +{ + this.setChecked(true); + + // Intentionally bypass superclass and call super.super.execute + qx.ui.menu.Button.prototype.execute.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js new file mode 100644 index 0000000000..16d4251c8a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js @@ -0,0 +1,78 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Separator", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + // Fix IE Styling Issues + this.setStyleProperty("fontSize", "0"); + this.setStyleProperty("lineHeight", "0"); + + // ************************************************************************ + // LINE + // ************************************************************************ + + this._line = new qx.ui.basic.Terminator; + this._line.setAnonymous(true); + this._line.setAppearance("menu-separator-line"); + this.add(this._line); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + // needed to stop the event, and keep the menu showing + this.addEventListener("mousedown", this._onmousedown); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-separator" }); + +qx.Proto.hasIcon = qx.lang.Function.returnFalse; +qx.Proto.hasLabel = qx.lang.Function.returnFalse; +qx.Proto.hasShortcut = qx.lang.Function.returnFalse; +qx.Proto.hasMenu = qx.lang.Function.returnFalse; + +qx.Proto._onmousedown = function(e) { + e.stopPropagation(); +} + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._line) + { + this._line.dispose(); + this._line = null; + } + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js new file mode 100644 index 0000000000..42bdac4499 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menubar.Button", qx.ui.toolbar.MenuButton, +function(vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.toolbar.MenuButton.call(this, vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js new file mode 100644 index 0000000000..967136683e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menubar.MenuBar", qx.ui.toolbar.ToolBar, +function() { + qx.ui.toolbar.ToolBar.call(this); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js new file mode 100755 index 0000000000..21f643a3b8 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js @@ -0,0 +1,131 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractBar", qx.ui.layout.BoxLayout, +function() +{ + qx.ui.layout.BoxLayout.call(this); + + this._manager = new qx.manager.selection.RadioManager; + + this.addEventListener("mousewheel", this._onmousewheel); +}); + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._lastDate = (new Date(0)).valueOf(); + +qx.Proto._onmousewheel = function(e) +{ + // Make it a bit lazier than it could be + // Hopefully this is a better behaviour for fast scrolling users + var vDate = (new Date).valueOf(); + + if ((vDate - 50) < this._lastDate) { + return; + } + + this._lastDate = vDate; + + var vManager = this.getManager(); + var vItems = vManager.getEnabledItems(); + var vPos = vItems.indexOf(vManager.getSelected()); + + if (this.getWheelDelta(e) > 0) + { + var vNext = vItems[vPos+1]; + + if (!vNext) { + vNext = vItems[0]; + } + } + else if (vPos > 0) + { + var vNext = vItems[vPos-1]; + + if (!vNext) { + vNext = vItems[0]; + } + } + else + { + vNext = vItems[vItems.length-1]; + } + + vManager.setSelected(vNext); +} + +qx.Proto.getWheelDelta = function(e) { + return e.getWheelDelta(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + this.removeEventListener("mousewheel", this._onmousewheel); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js new file mode 100755 index 0000000000..3a130a1268 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js @@ -0,0 +1,222 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + + ************************************************************************ */ + +/* ************************************************************************ + + + ************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractButton", qx.ui.basic.Atom, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.basic.Atom.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + this.setTabIndex(1); + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + this.addEventListener("mousedown", this._onmousedown); + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/*! + If this tab is the currently selected/active one + */ +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false }); + +/*! + The attached page of this tab + */ +qx.OO.addProperty({ name : "page", type : "object" }); + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons + */ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + +/*! + The name of the radio group. All the radio elements in a group (registered by the same manager) + have the same name (and could have a different value). + */ +qx.OO.addProperty({ name : "name", type : "string" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- + */ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +}; + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- + */ + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +}; + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.getManager().remove(this); + } + + if (propValue) { + propValue.getManager().add(this); + } + + return qx.ui.basic.Atom.prototype._modifyParent.call(this, propValue, propOldValue, propData); +}; + +qx.Proto._modifyPage = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.setButton(null); + } + + if (propValue) { + propValue.setButton(this); + this.getChecked() ? propValue.show() : propValue.hide(); + } + + return true; +}; + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) { + if (this._hasParent) { + var vManager = this.getManager(); + if (vManager) { + vManager.handleItemChecked(this, propValue); + } + } + + propValue ? this.addState("checked") : this.removeState("checked"); + + var vPage = this.getPage(); + if (vPage) { + this.getChecked() ? vPage.show() : vPage.hide(); + } + + return true; +}; + +qx.Proto._modifyName = function(propValue, propOldValue, propData) { + if (this.getManager()) { + this.getManager().setName(propValue); + } + + return true; +}; + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- + */ + +qx.Proto._onmousedown = function(e) { + this.setChecked(true); +}; + +qx.Proto._onmouseover = function(e) { + this.addState("over"); +}; + +qx.Proto._onmouseout = function(e) { + this.removeState("over"); +}; + +qx.Proto._onkeydown = function(e) {}; +qx.Proto._onkeypress = function(e) {}; + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- + */ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + this.removeEventListener("mousedown", this._onmousedown); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + return qx.ui.basic.Atom.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js new file mode 100755 index 0000000000..fcf8a44029 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js @@ -0,0 +1,77 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPage", qx.ui.layout.CanvasLayout, +function(vButton) +{ + qx.ui.layout.CanvasLayout.call(this); + + if (vButton != null) { + this.setButton(vButton); + } +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The attached tab of this page. +*/ +qx.OO.addProperty({ name : "button", type : "object" }); + +/*! + Make element displayed (if switched to true the widget will be created, if needed, too). + Instead of qx.ui.core.Widget, the default is false here. +*/ +qx.OO.changeProperty({ name : "display", type : "boolean", defaultValue : false }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyButton = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.setPage(null); + } + + if (propValue) { + propValue.setPage(this); + } + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js new file mode 100755 index 0000000000..1119bd109c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js @@ -0,0 +1,86 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPageView", qx.ui.layout.BoxLayout, +function(vBarClass, vPaneClass) +{ + qx.ui.layout.BoxLayout.call(this); + + this._bar = new vBarClass; + this._pane = new vPaneClass; + + this.add(this._bar, this._pane); + this.setOrientation("vertical"); +}); + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPane = function() { + return this._pane; +} + +qx.Proto.getBar = function() { + return this._bar; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._bar) + { + this._bar.dispose(); + this._bar = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js new file mode 100755 index 0000000000..6a97fef36e --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js @@ -0,0 +1,29 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPane", qx.ui.layout.CanvasLayout, +function() { + qx.ui.layout.CanvasLayout.call(this); +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js new file mode 100644 index 0000000000..4a0cd8cd1a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js @@ -0,0 +1,77 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Bar", qx.ui.pageview.AbstractBar, +function() { + qx.ui.pageview.AbstractBar.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-bar" }); + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWheelDelta = function(e) +{ + var vWheelDelta = e.getWheelDelta(); + + switch(this.getParent().getBarPosition()) + { + case "left": + case "right": + vWheelDelta *= -1; + } + + return vWheelDelta; +} + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getParent().getBarPosition(); + + this._states.barLeft = vPos === "left"; + this._states.barRight = vPos === "right"; + this._states.barTop = vPos === "top"; + this._states.barBottom = vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js new file mode 100644 index 0000000000..7d2ee71fa0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js @@ -0,0 +1,122 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Button", qx.ui.pageview.AbstractButton, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.pageview.AbstractButton.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-button" }); + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeypress = function(e) +{ + switch(this.getView().getBarPosition()) + { + case "top": + case "bottom": + switch(e.getKeyIdentifier()) + { + case "Left": + var vPrevious = true; + break; + + case "Right": + var vPrevious = false; + break; + + default: + return; + } + + break; + + case "left": + case "right": + switch(e.getKeyIdentifier()) + { + case "Up": + var vPrevious = true; + break; + + case "Down": + var vPrevious = false; + break; + + default: + return; + } + + break; + + default: + return; + } + + var vChild = vPrevious ? this.isFirstChild() ? this.getParent().getLastChild() : this.getPreviousSibling() : this.isLastChild() ? this.getParent().getFirstChild() : this.getNextSibling(); + + // focus next/previous button + vChild.setFocused(true); + + // and naturally also check it + vChild.setChecked(true); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getView().getBarPosition(); + + this._states.barLeft = vPos === "left"; + this._states.barRight = vPos === "right"; + this._states.barTop = vPos === "top"; + this._states.barBottom = vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js new file mode 100644 index 0000000000..4e3521858c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js @@ -0,0 +1,100 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +/*! + One of the widgets which could be used to structurize the interface. + + qx.ui.pageview.buttonview.ButtonView creates the typical apple-like tabview-replacements which could also + be found in more modern versions of the settings dialog in Mozilla Firefox. +*/ +qx.OO.defineClass("qx.ui.pageview.buttonview.ButtonView", qx.ui.pageview.AbstractPageView, +function() +{ + qx.ui.pageview.AbstractPageView.call(this, qx.ui.pageview.buttonview.Bar, qx.ui.pageview.buttonview.Pane); + + this.setOrientation("vertical"); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "barPosition", type : "string", defaultValue : "top", possibleValues : [ "top", "right", "bottom", "left" ] }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBarPosition = function(propValue, propOldValue, propData) +{ + var vBar = this._bar; + + // move bar around and change orientation + switch(propValue) + { + case "top": + vBar.moveSelfToBegin(); + this.setOrientation("vertical"); + break; + + case "bottom": + vBar.moveSelfToEnd(); + this.setOrientation("vertical"); + break; + + case "left": + vBar.moveSelfToBegin(); + this.setOrientation("horizontal"); + break; + + case "right": + vBar.moveSelfToEnd(); + this.setOrientation("horizontal"); + break; + } + + // force re-apply of states for bar and pane + this._addChildrenToStateQueue(); + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js new file mode 100644 index 0000000000..b69fa88407 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js @@ -0,0 +1,32 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Page", qx.ui.pageview.AbstractPage, +function(vButton) { + qx.ui.pageview.AbstractPage.call(this, vButton); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-page" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js new file mode 100644 index 0000000000..df8b1a59ea --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Pane", qx.ui.pageview.AbstractPane, +function() { + qx.ui.pageview.AbstractPane.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-pane" }); + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getParent().getBarPosition(); + + this._states.barHorizontal = vPos === "top" || vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js new file mode 100644 index 0000000000..0ddc9a5909 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js @@ -0,0 +1,35 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Bar", qx.ui.pageview.AbstractBar, +function() +{ + qx.ui.pageview.AbstractBar.call(this); + + this.setZIndex(2); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-bar" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js new file mode 100644 index 0000000000..c9f22b226c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js @@ -0,0 +1,192 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) +#embed(qx.icontheme/16/actions/dialog-cancel.png) + +************************************************************************ */ + +/** + * @event closetab {qx.event.type.DataEvent} + */ +qx.OO.defineClass("qx.ui.pageview.tabview.Button", qx.ui.pageview.AbstractButton, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.pageview.AbstractButton.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-button" }); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/*! + default Close Tab Button + */ +qx.OO.addProperty({ name : "showCloseButton", type : "boolean", defaultValue : false }); + +/*! + Close Tab Icon + */ +qx.OO.addProperty({ name : "closeButtonImage", type : "string", defaultValue : "icon/16/actions/dialog-cancel.png"}); + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var identifier = e.getKeyIdentifier(); + if (identifier == "Enter" || identifier == "Space") { + // there is no toggeling, just make it checked + this.setChecked(true); + } +}; + + +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Left": + var vPrev = this.getPreviousActiveSibling(); + if (vPrev && vPrev != this) + { + // we want to enable the outline border, because + // the user used the keyboard for activation + delete qx.event.handler.FocusHandler.mouseFocus; + + // focus previous tab + vPrev.setFocused(true); + + // and naturally make it also checked + vPrev.setChecked(true); + } + break; + + case "Right": + var vNext = this.getNextActiveSibling(); + if (vNext && vNext != this) + { + // we want to enable the outline border, because + // the user used the keyboard for activation + delete qx.event.handler.FocusHandler.mouseFocus; + + // focus next tab + vNext.setFocused(true); + + // and naturally make it also checked + vNext.setChecked(true); + } + break; + } +}; + + +qx.Proto._ontabclose = function(e){ + this.createDispatchDataEvent("closetab", this); +} + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- + */ + +qx.Proto._modifyShowCloseButton = function(propValue, propOldValue, propData) { + + // if no image exists, then create one + if (!this._closeButtonImage) { + this._closeButtonImage = new qx.ui.basic.Image(this.getCloseButtonImage()); + } + if (propValue) { + this._closeButtonImage.addEventListener("click", this._ontabclose, this); + this.add(this._closeButtonImage); + } else { + this.remove(this._closeButtonImage); + this._closeButtonImage.removeEventListener("click", this._ontabclose); + } + + return true; +} + +qx.Proto._modifyCloseButtonImage = function(propValue, propOldValue, propData) { + if (this._closeButtonImage) { + this._closeButtonImage.setSource(propValue); + } + + return true; +} + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + this._states.firstChild = this.isFirstVisibleChild(); + this._states.lastChild = this.isLastVisibleChild(); + this._states.alignLeft = this.getView().getAlignTabsToLeft(); + this._states.barTop = this.getView().getPlaceBarOnTop(); + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- + */ + +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + if(this._closeButtonImage){ + this._closeButtonImage.dispose(); + this._closeButtonImage = null; + } + + return qx.ui.pageview.AbstractButton.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js new file mode 100644 index 0000000000..beac8fe41c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js @@ -0,0 +1,32 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Page", qx.ui.pageview.AbstractPage, +function(vButton) { + qx.ui.pageview.AbstractPage.call(this, vButton); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-page" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js new file mode 100644 index 0000000000..439d149d50 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js @@ -0,0 +1,35 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Pane", qx.ui.pageview.AbstractPane, +function() +{ + qx.ui.pageview.AbstractPane.call(this); + + this.setZIndex(1); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-pane" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js new file mode 100644 index 0000000000..c0093b295a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js @@ -0,0 +1,88 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.TabView", qx.ui.pageview.AbstractPageView, +function() { + qx.ui.pageview.AbstractPageView.call(this, qx.ui.pageview.tabview.Bar, qx.ui.pageview.tabview.Pane); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view" }); + +qx.OO.addProperty({ name : "alignTabsToLeft", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "placeBarOnTop", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyAlignTabsToLeft = function(propValue, propOldValue, propData) +{ + var vBar = this._bar; + + vBar.setHorizontalChildrenAlign(propValue ? "left" : "right"); + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} + +qx.Proto._modifyPlaceBarOnTop = function(propValue, propOldValue, propData) +{ + // This does not work if we use flexible zones + // this.setReverseChildrenOrder(!propValue); + + var vBar = this._bar; + + // move bar around + if (propValue) { + vBar.moveSelfToBegin(); + } else { + vBar.moveSelfToEnd(); + } + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js new file mode 100644 index 0000000000..edf6cd4065 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js @@ -0,0 +1,334 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) +#optional(qx.manager.object.MenuManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.popup.Popup", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + this.setZIndex(this._minZIndex); + + // Init Focus Handler + if (this._isFocusRoot) { + this.activateFocusRoot(); + } +}); + +qx.Proto._isFocusRoot = true; + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "popup" }); + +/*! + Whether to let the system decide when to hide the popup. Setting + this to false gives you better control but it also requires you + to handle the closing of the popup. +*/ +qx.OO.addProperty({ name : "autoHide", type : "boolean", defaultValue : true }); + +/*! + Make element displayed (if switched to true the widget will be created, if needed, too). + Instead of qx.ui.core.Widget, the default is false here. +*/ +qx.OO.changeProperty({ name : "display", type : "boolean", defaultValue : false }); + +/*! + Center the popup on open +*/ +qx.OO.addProperty({ name : "centered", type : "boolean", defaultValue : false }); + +/** + * Whether the popup should be restricted to the visible area of the page when opened. + */ +qx.OO.addProperty({ name : "restrictToPageOnOpen", type : "boolean", defaultValue : true }); + + +qx.Proto._showTimeStamp = (new Date(0)).valueOf(); +qx.Proto._hideTimeStamp = (new Date(0)).valueOf(); + + +/** + * The minimum offset to the left of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageLeft", "0"); + +/** + * The minimum offset to the right of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageRight", "0"); + +/** + * The minimum offset to the top of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageTop", "0"); + +/** + * The minimum offset to the bottom of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageBottom", "0"); + + + + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + qx.ui.layout.CanvasLayout.prototype._beforeAppear.call(this); + + if (this.getRestrictToPageOnOpen()) { + this._wantedLeft = this.getLeft(); + + if (this._wantedLeft != null) { + // Move the popup out of the view so its size could be calculated before + // it is positioned. + this.setLeft(10000); + if (this.getElement() != null) { + // The popup was already visible once before + // -> Move it immediately before it gets visible again + this.getElement().style.left = 10000; + } + } + } + + qx.manager.object.PopupManager.getInstance().add(this); + qx.manager.object.PopupManager.getInstance().update(this); + + this._showTimeStamp = (new Date).valueOf(); + this.bringToFront(); +} + +qx.Proto._beforeDisappear = function() +{ + qx.ui.layout.CanvasLayout.prototype._beforeDisappear.call(this); + + qx.manager.object.PopupManager.getInstance().remove(this); + + this._hideTimeStamp = (new Date).valueOf(); +} + +qx.Proto._afterAppear = function() { + qx.ui.layout.CanvasLayout.prototype._afterAppear.call(this); + + if (this.getRestrictToPageOnOpen()) { + var doc = qx.ui.core.ClientDocument.getInstance(); + var docWidth = doc.getClientWidth(); + var docHeight = doc.getClientHeight(); + var restrictToPageLeft = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageLeft")); + var restrictToPageRight = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageRight")); + var restrictToPageTop = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageTop")); + var restrictToPageBottom = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageBottom")); + var left = (this._wantedLeft == null) ? this.getLeft() : this._wantedLeft; + var top = this.getTop(); + var width = this.getBoxWidth(); + var height = this.getBoxHeight(); + + var oldLeft = this.getLeft(); + var oldTop = top; + + // NOTE: We check right and bottom first, because top and left should have + // priority, when both sides are violated. + if (left + width > docWidth - restrictToPageRight) { + left = docWidth - restrictToPageRight - width; + } + if (top + height > docHeight - restrictToPageBottom) { + top = docHeight - restrictToPageBottom - height; + } + if (left < restrictToPageLeft) { + left = restrictToPageLeft; + } + if (top < restrictToPageTop) { + top = restrictToPageTop; + } + + if (left != oldLeft || top != oldTop) { + var self = this; + window.setTimeout(function() { + self.setLeft(left); + self.setTop(top); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + } + } +}; + + + + + +/* +--------------------------------------------------------------------------- + ACTIVE/INACTIVE +--------------------------------------------------------------------------- +*/ + +qx.Proto._makeActive = function() { + this.getFocusRoot().setActiveChild(this); +} + +qx.Proto._makeInactive = function() +{ + var vRoot = this.getFocusRoot(); + var vCurrent = vRoot.getActiveChild(); + + if (vCurrent == this) { + vRoot.setActiveChild(vRoot); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + ZIndex Positioning +--------------------------------------------------------------------------- +*/ + +qx.Proto._minZIndex = 1e6; + +qx.Proto.bringToFront = function() +{ + this.forceZIndex(Infinity); + this._sendTo(); +} + +qx.Proto.sendToBack = function() +{ + this.forceZIndex(-Infinity); + this._sendTo(); +} + +qx.Proto._sendTo = function() +{ + var vPopups = qx.lang.Object.getValues(qx.manager.object.PopupManager.getInstance().getAll()); + + if (qx.OO.isAvailable("qx.manager.object.MenuManager")) + { + var vMenus = qx.lang.Object.getValues(qx.manager.object.MenuManager.getInstance().getAll()); + var vAll = vPopups.concat(vMenus).sort(qx.util.Compare.byZIndex); + } + else + { + var vAll = vPopups.sort(qx.util.Compare.byZIndex); + } + + var vLength = vAll.length; + var vIndex = this._minZIndex; + + for (var i=0; i<vLength; i++) { + vAll[i].setZIndex(vIndex++); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + TIMESTAMP HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getShowTimeStamp = function() { + return this._showTimeStamp; +} + +qx.Proto.getHideTimeStamp = function() { + return this._hideTimeStamp; +} + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +/** + * Positions the popup relative to some reference element. + * @param el {var} Reference DOM element/widget. + * @param offsetX {Integer} Offset in pixels in X direction (optional). + * @param offsetY {Integer} Offset in pixels in Y direction (optional). + */ +qx.Proto.positionRelativeTo = function(el, offsetX, offsetY) +{ + if (el instanceof qx.ui.core.Widget) { + el = el.getElement(); + } + if (el) { + var gecko = qx.core.Client.getInstance().isGecko(); + var loc = qx.html.Location; + this.setLocation(loc.getClientAreaLeft(el) - (gecko ? qx.html.Style.getBorderLeft(el):0) + (offsetX || 0), + loc.getClientAreaTop(el) - (gecko ? qx.html.Style.getBorderTop(el):0) + (offsetY || 0)); + } else { + this.warn('Missing reference element'); + } +} + +qx.Proto.centerToBrowser = function() +{ + var d = qx.ui.core.ClientDocument.getInstance(); + + var left = (d.getClientWidth() - this.getBoxWidth()) / 2; + var top = (d.getClientHeight() - this.getBoxHeight()) / 2; + + this.setLeft(left < 0 ? 0 : left); + this.setTop(top < 0 ? 0 : top); +} + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._showTimeStamp = null; + this._hideTimeStamp = null; + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/PopupAtom.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/PopupAtom.js new file mode 100644 index 0000000000..5dfe9ea746 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/PopupAtom.js @@ -0,0 +1,55 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.popup.PopupAtom", qx.ui.popup.Popup, +function(vLabel, vIcon) +{ + qx.ui.popup.Popup.call(this); + + this._atom = new qx.ui.basic.Atom(vLabel, vIcon); + this._atom.setParent(this); +}); + +qx.Proto._isFocusRoot = false; + +qx.Proto.getAtom = function() { + return this._atom; +} + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._atom) + { + this._atom.dispose(); + this._atom = null; + } + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/ToolTip.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/ToolTip.js new file mode 100644 index 0000000000..271ce2b1e4 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/popup/ToolTip.js @@ -0,0 +1,257 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) +#load(qx.manager.object.ToolTipManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.popup.ToolTip", qx.ui.popup.PopupAtom, +function(vLabel, vIcon) +{ + // ************************************************************************ + // INIT + // ************************************************************************ + + qx.ui.popup.PopupAtom.call(this, vLabel, vIcon); + + // Apply shadow + this.setStyleProperty("filter", "progid:DXImageTransform.Microsoft.Shadow(color='Gray', Direction=135, Strength=4)"); + + + // ************************************************************************ + // TIMER + // ************************************************************************ + + this._showTimer = new qx.client.Timer(this.getShowInterval()); + this._showTimer.addEventListener("interval", this._onshowtimer, this); + + this._hideTimer = new qx.client.Timer(this.getHideInterval()); + this._hideTimer.addEventListener("interval", this._onhidetimer, this); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseover); +}); + +qx.Proto._minZIndex = 1e7; + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tool-tip" }); + +qx.OO.addProperty({ name : "hideOnHover", type : "boolean", defaultValue : true }); + +qx.OO.addProperty({ name : "mousePointerOffsetX", type : "number", defaultValue : 1 }); +qx.OO.addProperty({ name : "mousePointerOffsetY", type : "number", defaultValue : 20 }); + +qx.OO.addProperty({ name : "showInterval", type : "number", defaultValue : 1000 }); +qx.OO.addProperty({ name : "hideInterval", type : "number", defaultValue : 4000 }); + +qx.OO.addProperty({ name : "boundToWidget", type : "object", instance : "qx.ui.core.Widget" }); + + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyHideInterval = function(propValue, propOldValue, propData) +{ + this._hideTimer.setInterval(propValue); + return true; +} + +qx.Proto._modifyShowInterval = function(propValue, propOldValue, propData) +{ + this._showTimer.setInterval(propValue); + return true; +} + +qx.Proto._modifyBoundToWidget = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this.setParent(propValue.getTopLevelWidget()); + } + else if (propOldValue) + { + this.setParent(null); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + qx.ui.popup.PopupAtom.prototype._beforeAppear.call(this); + + this._stopShowTimer(); + this._startHideTimer(); +} + +qx.Proto._beforeDisappear = function() { + qx.ui.popup.PopupAtom.prototype._beforeDisappear.call(this); + + this._stopHideTimer(); +} + + + + + + +/* +--------------------------------------------------------------------------- + TIMER +--------------------------------------------------------------------------- +*/ + +qx.Proto._startShowTimer = function() +{ + if(!this._showTimer.getEnabled()) { + this._showTimer.start(); + } +} + +qx.Proto._startHideTimer = function() +{ + if(!this._hideTimer.getEnabled()) { + this._hideTimer.start(); + } +} + +qx.Proto._stopShowTimer = function() +{ + if(this._showTimer.getEnabled()) { + this._showTimer.stop(); + } +} + +qx.Proto._stopHideTimer = function() +{ + if(this._hideTimer.getEnabled()) { + this._hideTimer.stop(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + if(this.getHideOnHover()) { + this.hide(); + } +} + +qx.Proto._onshowtimer = function(e) +{ + this.setLeft(qx.event.type.MouseEvent.getPageX() + this.getMousePointerOffsetX()); + this.setTop(qx.event.type.MouseEvent.getPageY() + this.getMousePointerOffsetY()); + + this.show(); + + // we need a manual flushing because it could be that + // there is currently no event which do this for us + // and so show the tooltip. + qx.ui.core.Widget.flushGlobalQueues(); + + return true; +} + +qx.Proto._onhidetimer = function(e) { + return this.hide(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseover); + + if (this._showTimer) + { + this._showTimer.removeEventListener("interval", this._onshowtimer, this); + this._showTimer.dispose(); + this._showTimer = null; + } + + if (this._hideTimer) + { + this._hideTimer.removeEventListener("interval", this._onhidetimer, this); + this._hideTimer.dispose(); + this._hideTimer = null; + } + + return qx.ui.popup.PopupAtom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/resizer/Resizer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/resizer/Resizer.js new file mode 100755 index 0000000000..1141534eb2 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/resizer/Resizer.js @@ -0,0 +1,419 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * David Perez (david-perez) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_resizer) + +************************************************************************ */ + +/** + * This class acts as a wrapper for other child, and allows it to be resized (not moved), normally in + * the right and/or bottom directions. Child can be e.g. a qx.ui.form.TextArea, + * qx.ui.table.Table or qx.ui.form.List. It is an alternative to splitters. + */ +qx.OO.defineClass('qx.ui.resizer.Resizer', qx.ui.layout.CanvasLayout, +function(child) +{ + qx.ui.layout.CanvasLayout.call(this); + + this._frame = new qx.ui.basic.Terminator; + this._frame.setAppearance("resizer-frame"); + + this._registerResizeEvents(); + + this.setAppearance('resizer'); + this.setResizeableWest(false); + this.setResizeableNorth(false); + + this.setMinWidth("auto"); + this.setMinHeight("auto"); + this.auto(); + + if (child) + { + // Remove child border, as the resizer has already its own border. + child.setBorder(new qx.renderer.border.Border(0)); + this.add(this._child = child); + } +}); + + + + + +/*! + If the window is resizeable in the left direction. +*/ +qx.OO.addProperty({ name : "resizeableWest", type : "boolean", defaultValue : true }); +/*! + If the window is resizeable in the top direction. +*/ +qx.OO.addProperty({ name : "resizeableNorth", type : "boolean", defaultValue : true }); +/*! + If the window is resizeable in the right direction. +*/ +qx.OO.addProperty({ name : "resizeableEast", type : "boolean", defaultValue : true }); +/*! + If the window is resizeable in the bottom direction. +*/ +qx.OO.addProperty({ name : "resizeableSouth", type : "boolean", defaultValue : true }); + +/*! + If the window is resizeable +*/ +qx.OO.addPropertyGroup({ name : "resizeable", members : [ "west", "north", "east", "south" ], mode : "shorthand" }); + +/*! + The resize method to use +*/ +qx.OO.addProperty({ name : "resizeMethod", type : "string", defaultValue : "frame", possibleValues : [ "opaque", "lazyopaque", "frame", "translucent" ] }); + +/*! + The resize method to use +*/ +qx.OO.addProperty({ name : "resizeMethod", type : "string", defaultValue : "frame", possibleValues : [ "opaque", "lazyopaque", "frame", "translucent" ] }); + + + + + + +/** + * Adjust so that it returns a boolean instead of an array. + * @return {Boolean} + */ +qx.Proto.isResizeable = qx.Proto.getResizeable = function() { + return this.getResizeableWest() || this.getResizeableEast() || this.getResizeableNorth() || this.getResizeableSouth(); +} + +qx.Proto._registerResizeEvents = function() { + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mousemove", this._onmousemove); +} + +qx.Proto._onmousedown = function(e) +{ + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + // enable capturing + this.setCapture(true); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor(this.getCursor()); + + // caching element + var el = this.getElement(); + + // measuring and caching of values for resize session + var pa = this.getTopLevelWidget(); + var pl = pa.getElement(); + + var l = qx.html.Location.getPageAreaLeft(pl); + var t = qx.html.Location.getPageAreaTop(pl); + var r = qx.html.Location.getPageAreaRight(pl); + var b = qx.html.Location.getPageAreaBottom(pl); + + // handle frame and translucently + switch(this.getResizeMethod()) + { + case "translucent": + this.setOpacity(0.5); + break; + + case "frame": + var f = this._frame; + + if (f.getParent() != pa) + { + f.setParent(pa); + qx.ui.core.Widget.flushGlobalQueues(); + } + + f._applyRuntimeLeft(qx.html.Location.getPageBoxLeft(el) - l); + f._applyRuntimeTop(qx.html.Location.getPageBoxTop(el) - t); + + f._applyRuntimeWidth(qx.html.Dimension.getBoxWidth(el)); + f._applyRuntimeHeight(qx.html.Dimension.getBoxHeight(el)); + + f.setZIndex(this.getZIndex() + 1); + + break; + } + + // create resize session + var s = this._resizeSession = {}; + var minRef = this._child; + + if (this._resizeWest) + { + s.boxWidth = qx.html.Dimension.getBoxWidth(el); + s.boxRight = qx.html.Location.getPageBoxRight(el); + } + + if (this._resizeWest || this._resizeEast) + { + s.boxLeft = qx.html.Location.getPageBoxLeft(el); + + s.parentAreaOffsetLeft = l; + s.parentAreaOffsetRight = r; + + s.minWidth = minRef.getMinWidthValue(); + s.maxWidth = minRef.getMaxWidthValue(); + } + + if (this._resizeNorth) + { + s.boxHeight = qx.html.Dimension.getBoxHeight(el); + s.boxBottom = qx.html.Location.getPageBoxBottom(el); + } + + if (this._resizeNorth || this._resizeSouth) + { + s.boxTop = qx.html.Location.getPageBoxTop(el); + + s.parentAreaOffsetTop = t; + s.parentAreaOffsetBottom = b; + + s.minHeight = minRef.getMinHeightValue(); + s.maxHeight = minRef.getMaxHeightValue(); + } + } + else + { + // cleanup resize session + delete this._resizeSession; + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._onmouseup = function(e) +{ + var s = this._resizeSession; + + if (s) + { + // disable capturing + this.setCapture(false); + + // deactivate global cursor + this.getTopLevelWidget().setGlobalCursor(null); + + // sync sizes to frame + switch(this.getResizeMethod()) + { + case "frame": + var o = this._frame; + if (!(o && o.getParent())) { + break; + } + // no break here + + case "lazyopaque": + if (s.lastLeft != null) { + this.setLeft(s.lastLeft); + } + + if (s.lastTop != null) { + this.setTop(s.lastTop); + } + + if (s.lastWidth != null) { + var child = this.getChildren()[0]; + if (child) { + child.setWidth(s.lastWidth); + } + } + + if (s.lastHeight != null) { + var child = this.getChildren()[0]; + if (child) { + child.setHeight(s.lastHeight); + } + } + + if (this.getResizeMethod() == "frame") { + this._frame.setParent(null); + } + break; + + case "translucent": + this.setOpacity(null); + break; + } + + // cleanup session + delete this._resizeNorth; + delete this._resizeEast; + delete this._resizeSouth; + delete this._resizeWest; + + delete this._resizeSession; + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._near = function(p, e) { + return e > (p - 5) && e < (p + 5); +} + +qx.Proto._onmousemove = function(e) +{ + var s = this._resizeSession; + + if (s) + { + if (this._resizeWest) + { + s.lastWidth = qx.lang.Number.limit(s.boxWidth + s.boxLeft - Math.max(e.getPageX(), s.parentAreaOffsetLeft), s.minWidth, s.maxWidth); + s.lastLeft = s.boxRight - s.lastWidth - s.parentAreaOffsetLeft; + } + else if (this._resizeEast) + { + s.lastWidth = qx.lang.Number.limit(Math.min(e.getPageX(), s.parentAreaOffsetRight) - s.boxLeft, s.minWidth, s.maxWidth); + } + + if (this._resizeNorth) + { + s.lastHeight = qx.lang.Number.limit(s.boxHeight + s.boxTop - Math.max(e.getPageY(), s.parentAreaOffsetTop), s.minHeight, s.maxHeight); + s.lastTop = s.boxBottom - s.lastHeight - s.parentAreaOffsetTop; + } + else if (this._resizeSouth) + { + s.lastHeight = qx.lang.Number.limit(Math.min(e.getPageY(), s.parentAreaOffsetBottom) - s.boxTop, s.minHeight, s.maxHeight); + } + + switch(this.getResizeMethod()) + { + case "opaque": + case "translucent": + if (this._resizeWest || this._resizeEast) + { + this.setWidth(s.lastWidth); + + if (this._resizeWest) { + this.setLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + this.setHeight(s.lastHeight); + + if (this._resizeNorth) { + this.setTop(s.lastTop); + } + } + + break; + + default: + var o = this.getResizeMethod() == "frame" ? this._frame : this; + + if (this._resizeWest || this._resizeEast) + { + o._applyRuntimeWidth(s.lastWidth); + + if (this._resizeWest) { + o._applyRuntimeLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + o._applyRuntimeHeight(s.lastHeight); + + if (this._resizeNorth) { + o._applyRuntimeTop(s.lastTop); + } + } + } + } + else + { + var resizeMode = ""; + var el = this.getElement(); + + this._resizeNorth = this._resizeSouth = this._resizeWest = this._resizeEast = false; + + if (this._near(qx.html.Location.getPageBoxTop(el), e.getPageY())) + { + if (this.getResizeableNorth()) { + resizeMode = "n"; + this._resizeNorth = true; + } + } + else if (this._near(qx.html.Location.getPageBoxBottom(el), e.getPageY())) + { + if (this.getResizeableSouth()) { + resizeMode = "s"; + this._resizeSouth = true; + } + } + + if (this._near(qx.html.Location.getPageBoxLeft(el), e.getPageX())) + { + if (this.getResizeableWest()) { + resizeMode += "w"; + this._resizeWest = true; + } + } + else if (this._near(qx.html.Location.getPageBoxRight(el), e.getPageX())) + { + if (this.getResizeableEast()) { + resizeMode += "e"; + this._resizeEast = true; + } + } + + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + this.setCursor(resizeMode + "-resize"); + } + else + { + this.setCursor(null); + } + } + + // stop event + e.stopPropagation(); +} + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js new file mode 100644 index 0000000000..6ff06929d5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js @@ -0,0 +1,60 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Volker Pauli + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) + +************************************************************************ */ + +/** + * + * Creates a new instance of a horizontal SplitPane.<br /><br /> + * + * new qx.ui.splitpane.HorizontalSplitPane()<br /> + * new qx.ui.splitpane.HorizontalSplitPane(firstSize, secondSize) + * + * @param firstSize {String} The size of the left pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + * @param secondSize {String} The size of the right pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.HorizontalSplitPane", qx.ui.splitpane.SplitPane, +function(firstSize, secondSize) { + qx.ui.splitpane.SplitPane.call(this, "horizontal", firstSize, secondSize); +}); + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.splitpane.SplitPane.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js new file mode 100644 index 0000000000..3ed9d4b766 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js @@ -0,0 +1,762 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Volker Pauli (vpauli) + * Sebastian Werner (wpbasti) + * Carsten Lergenmueller (carstenL) + + ************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) +#embed(qx.widgettheme/splitpane/*) + + ************************************************************************ */ + + +/** + * Creates a new instance of a SplitPane. It allows the user to dynamically resize + * the areas dropping the border between. + * + * new qx.ui.splitpane.SplitPane(orientation) + * new qx.ui.splitpane.SplitPane(orientation, firstSize, secondSize) + * + * @param orientation {String} The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical". This is the same type as used in {@link qx.ui.layout.BoxLayout#orientation}. + * @param firstSize {String} The size of the left (top) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + * @param secondSize {String} The size of the right (bottom) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.SplitPane", qx.ui.layout.CanvasLayout, +function(orientation, firstSize, secondSize) +{ + qx.ui.layout.CanvasLayout.call(this); + + // CREATE INNER BOX LAYOUT + var box = this._box = new qx.ui.layout.BoxLayout; + box.setEdge(0); + this.add(box); + + /* + + the splitpane itself is a boxlayout resides on top of a canvas for easier computing of positional values + + --------------------------------------------------------------------------------------- + | canvas | + | ----------------------------------------------------------------------------------- | + | | box | | + | | --------------------------- --- ----------------------------------------------- | | + | | | | | | | | | | + | | | firstArea | |s| | secondArea | | | + | | | | |p| | | | | + | | | | |l| | | | | + | | | | |i| | | | | + | | | | |t| | | | | + | | | | |t| | | | | + | | | | |e| | | | | + | | | | |r| | | | | + | | | | | | | | | | + | | --------------------------- --- ----------------------------------------------- | | + | ----------------------------------------------------------------------------------- | + | | + --------------------------------------------------------------------------------------- + + */ + + // CREATE SLIDER + this._slider = new qx.ui.layout.CanvasLayout; + this._slider.setAppearance("splitpane-slider"); + this._slider.setStyleProperty("fontSize", "0px"); + this._slider.setStyleProperty("lineHeight", "0px"); + this._slider.hide(); + this._slider._pane = this; + this.add(this._slider); + + // CREATE SPLITTER + this._splitter = new qx.ui.layout.CanvasLayout; + this._splitter.setStyleProperty("fontSize", "0px"); + this._splitter.setStyleProperty("lineHeight", "0px"); + this._splitter.setAppearance("splitpane-splitter"); + this._splitter._pane = this; + + // PATCH METHODS + this._slider._applyRuntimeLeft = this._splitter._applyRuntimeLeft = this._applyRuntimeLeftWrapper; + this._slider._applyRuntimeTop = this._splitter._applyRuntimeTop = this._applyRuntimeTopWrapper; + + // CREATE KNOB + this._knob = new qx.ui.basic.Image; + this._knob.setAppearance("splitpane-knob"); + this._knob.setVisibility(false); + this.add(this._knob); + + // CREATE AREAS + this._firstArea = new qx.ui.layout.CanvasLayout; + this._secondArea = new qx.ui.layout.CanvasLayout; + + // FILL BOX + box.add(this._firstArea, this._splitter, this._secondArea); + + // APPLY DIMENSIONS + this.setFirstSize(firstSize || "1*"); + this.setSecondSize(secondSize || "1*"); + + // APPLY ORIENTATION + this.setOrientation(orientation || "horizontal"); +}); + + + + + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/** + * Appearance change + */ +qx.OO.changeProperty({ name : "appearance", defaultValue : "splitpane" }); + +/** + * Show the knob + */ +qx.OO.addProperty({ name : "showKnob", type : "boolean", allowNull : false, defaultValue : false }); + +/** + * The layout method for the splitpane. If true, the content will updated immediatly. + */ +qx.OO.addProperty({ name : "liveResize", type : "boolean", allowNull : false, defaultValue : false, getAlias : "isLiveResize"}); + +/** + * The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical". + */ +qx.OO.addProperty({ name : "orientation", type : "string", possibleValues : [ "horizontal", "vertical" ] }); + +/** + * The size of the first (left/top) area. + */ +qx.OO.addProperty({ name : "firstSize" }); + +/** + * The size of the second (right/bottom) area. + */ +qx.OO.addProperty({ name : "secondSize" }); + +/** + * Size of the splitter + */ +qx.OO.addProperty({ name : "splitterSize", defaultValue : 4 }); + + + + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS +--------------------------------------------------------------------------- +*/ + + +/** + * adds one or more widget(s) to the left pane + * + *@param widget {qx.ui.core.Parent} + */ +qx.Proto.addLeft = function() { + var c = this.getFirstArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the top pane + * + *@param widget {qx.ui.core.Parent} + */ +qx.Proto.addTop = function() { + var c = this.getFirstArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the right pane + * + *@param widget {qx.ui.core.Parent} + */ +qx.Proto.addRight = function() { + var c = this.getSecondArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the bottom pane + * + *@param widget {qx.ui.core.Parent} + */ +qx.Proto.addBottom = function() { + var c = this.getSecondArea(); + return c.add.apply(c, arguments); +} + +/** + * Returns the splitter. + * + * @return {qx.ui.core.Widget} The splitter. + */ +qx.Proto.getSplitter = function() { + return this._splitter; +} + +/** + * Returns the knob. + * + * @return {qx.ui.core.Widget} The knob. + */ +qx.Proto.getKnob = function() { + return this._knob; +} + + + + + + +/** + * Returns the left area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getLeftArea = function() { + return this.getFirstArea(); +} + +/** + * Returns the top area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getTopArea = function() { + return this.getFirstArea(); +} + +/** + * Returns the right area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getRightArea = function() { + return this.getSecondArea(); +} + +/** + * Returns the bottom area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getBottomArea = function() { + return this.getSecondArea(); +} + +/** + * Returns the first area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getFirstArea = function() { + return this._firstArea; +} + +/** + * Returns the second area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getSecondArea = function() { + return this._secondArea; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyShowKnob = function(propValue, propOldValue, propData) +{ + this._knob.setVisibility(propValue); + return true; +} + +qx.Proto._modifyOrientation = function(propValue, propOldValue, propData) +{ + // sync orientation to layout + this._box.setOrientation(propValue); + + switch(propOldValue) + { + case "horizontal": + // remove old listeners + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpX, this); + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseUpX, this); + + // reconfigure states + this._splitter.removeState("horizontal"); + this._knob.removeState("horizontal"); + + // reset old dimensions + this._firstArea.setWidth(null); + this._secondArea.setWidth(null); + this._splitter.setWidth(null); + + break; + + case "vertical": + // remove old listeners + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpY, this); + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseUpY, this); + + // reconfigure states + this._splitter.removeState("vertical"); + this._knob.removeState("vertical"); + + // reset old dimensions + this._firstArea.setHeight(null); + this._secondArea.setHeight(null); + this._splitter.setHeight(null); + + break; + } + + switch(propValue) + { + case "horizontal": + // add new listeners + this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._splitter.addEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.addEventListener("mouseup", this._onSplitterMouseUpX, this); + this._knob.addEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._knob.addEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.addEventListener("mouseup", this._onSplitterMouseUpX, this); + + // reconfigure states + this._splitter.addState("horizontal"); + this._knob.addState("horizontal"); + + // apply images + this._knob.setSource("widget/splitpane/knob-horizontal.png"); + + break; + + case "vertical": + // add new listeners + this._splitter.addEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._splitter.addEventListener("mouseup", this._onSplitterMouseUpY, this); + this._knob.addEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.addEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._knob.addEventListener("mouseup", this._onSplitterMouseUpY, this); + + // reconfigure states + this._splitter.addState("vertical"); + this._knob.addState("vertical"); + + // apply images + this._knob.setSource("widget/splitpane/knob-vertical.png"); + + break; + } + + // apply new dimensions + this._syncFirstSize(); + this._syncSecondSize(); + this._syncSplitterSize(); + + return true; +}; + +qx.Proto._modifyFirstSize = function(propValue, propOldValue, propData) +{ + this._syncFirstSize(); + return true; +} + +qx.Proto._modifySecondSize = function(propValue, propOldValue, propData) +{ + this._syncSecondSize(); + return true; +} + +qx.Proto._modifySplitterSize = function(propValue, propOldValue, propData) +{ + this._syncSplitterSize(); + return true; +} + +qx.Proto._syncFirstSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._firstArea.setWidth(this.getFirstSize()); + break; + + case "vertical": + this._firstArea.setHeight(this.getFirstSize()); + break; + } +} + +qx.Proto._syncSecondSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._secondArea.setWidth(this.getSecondSize()); + break; + + case "vertical": + this._secondArea.setHeight(this.getSecondSize()); + break; + } +} + +qx.Proto._syncSplitterSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._splitter.setWidth(this.getSplitterSize()); + break; + + case "vertical": + this._splitter.setHeight(this.getSplitterSize()); + break; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +/** + * Initializes drag session in case of a mousedown event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseDownX = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._commonMouseDown(); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor("col-resize"); + this._slider.addState("dragging"); + this._knob.addState("dragging"); + + // initialize the drag session + this._dragMin = qx.html.Location.getPageInnerLeft(this._box.getElement()); + this._dragMax = this._dragMin + this._box.getInnerWidth() - this._splitter.getBoxWidth(); + this._dragOffset = e.getPageX() - qx.html.Location.getPageBoxLeft(this._splitter.getElement()); +} + +/** + * Initializes drag session in case of a mousedown event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseDownY = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._commonMouseDown(); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor("row-resize"); + this._slider.addState("dragging"); + this._knob.addState("dragging"); + + // initialize the drag session + // dragStart = position of layout + mouse offset on splitter + this._dragMin = qx.html.Location.getPageInnerTop(this._box.getElement()); + this._dragMax = this._dragMin + this._box.getInnerHeight() - this._splitter.getBoxHeight(); + this._dragOffset = e.getPageY() - qx.html.Location.getPageBoxTop(this._splitter.getElement()); +} + +qx.Proto._commonMouseDown = function() +{ + // enable capturing + this._splitter.setCapture(true); + + // initialize the slider + if(!this.isLiveResize()) + { + this._slider.setLeft(this._splitter.getOffsetLeft()); + this._slider.setTop(this._splitter.getOffsetTop()); + this._slider.setWidth(this._splitter.getBoxWidth()); + this._slider.setHeight(this._splitter.getBoxHeight()); + + this._slider.show(); + } +} + + + + + + + + +/** + * Move the splitter in case of a mousemove event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseMoveX = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + this.isLiveResize() ? this._syncX(e) : this._slider._applyRuntimeLeft(this._normalizeX(e)); + e.preventDefault(); +} + +/** + * Move the splitter in case of a mousemove event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseMoveY = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + this.isLiveResize() ? this._syncY(e) : this._slider._applyRuntimeTop(this._normalizeY(e)); + e.preventDefault(); +} + + + + + + + +/** + * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseUpX = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + if(!this.isLiveResize()) { + this._syncX(e); + } + + this._commonMouseUp(); +} + +/** + * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseUpY = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + if(!this.isLiveResize()) { + this._syncY(e); + } + + this._commonMouseUp(); +} + +qx.Proto._commonMouseUp = function() +{ + // hide helpers + this._slider.hide(); + + // disable capturing + this._splitter.setCapture(false); + + // reset the global cursor + this.getTopLevelWidget().setGlobalCursor(null); + + // cleanup dragsession + this._slider.removeState("dragging"); + this._knob.removeState("dragging"); +} + +qx.Proto._syncX = function(e) +{ + var first = this._normalizeX(e); + var second = this._box.getInnerWidth() - this._splitter.getBoxWidth() - first; + + this._syncCommon(first, second); +} + +qx.Proto._syncY = function(e) +{ + var first = this._normalizeY(e); + var second = this._box.getInnerHeight() - this._splitter.getBoxHeight() - first; + + this._syncCommon(first, second); +} + +qx.Proto._syncCommon = function(first, second) +{ + this.setFirstSize(first + "*"); + this.setSecondSize(second + "*"); +} + +qx.Proto._normalizeX = function(e) { + return qx.lang.Number.limit(e.getPageX() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin; +} + +qx.Proto._normalizeY = function(e) { + return qx.lang.Number.limit(e.getPageY() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin; +} + +qx.Proto._applyRuntimeLeftWrapper = function(v) +{ + if (this._pane.getOrientation() == "horizontal") { + this._pane._knob._applyRuntimeLeft(v); + } + + return this.constructor.prototype._applyRuntimeLeft.call(this, v); +} + +qx.Proto._applyRuntimeTopWrapper = function(v) +{ + if (this._pane.getOrientation() == "vertical") { + this._pane._knob._applyRuntimeTop(v); + } + + return this.constructor.prototype._applyRuntimeTop.call(this, v); +} + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if(this._firstArea) + { + this._firstArea.dispose(); + this._firstArea = null; + } + + if(this._secondArea) + { + this._secondArea.dispose(); + this._secondArea = null; + } + + if (this._splitter) + { + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveX, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpX, this); + + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveY, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpY, this); + + this._splitter.dispose(); + this._splitter._pane = null; + this._splitter = null; + } + + if (this._slider) + { + this._slider.dispose(); + this._slider._pane = null; + this._slider = null; + } + + if (this._knob) + { + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveX, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseUpX, this); + + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveY, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseUpY, this); + + this._knob.dispose(); + this._knob = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js new file mode 100644 index 0000000000..a922450039 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js @@ -0,0 +1,60 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Volker Pauli + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) + +************************************************************************ */ + +/** + * + * Creates a new instance of a vertical SplitPane.<br /><br /> + * + * new qx.ui.splitpane.VerticalSplitPane()<br /> + * new qx.ui.splitpane.VerticalSplitPane(firstSize, secondSize) + * + * @param firstSize {String} The size of the top pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + * @param secondSize {String} The size of the bottom pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.VerticalSplitPane", qx.ui.splitpane.SplitPane, +function(firstSize, secondSize) { + qx.ui.splitpane.SplitPane.call(this, "vertical", firstSize, secondSize); +}); + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.splitpane.SplitPane.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js new file mode 100644 index 0000000000..0e86e0fbdc --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js @@ -0,0 +1,130 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * An abstract data cell renderer that does the basic coloring + * (borders, selected look, ...). + */ +qx.OO.defineClass("qx.ui.table.AbstractDataCellRenderer", qx.ui.table.DataCellRenderer, +function() { + qx.ui.table.DataCellRenderer.call(this); +}); + + +// overridden +qx.Proto.createDataCellHtml = function(cellInfo) { + var AbstractDataCellRenderer = qx.ui.table.AbstractDataCellRenderer; + return AbstractDataCellRenderer.MAIN_DIV_START + this._getCellStyle(cellInfo) + + AbstractDataCellRenderer.MAIN_DIV_START_END + + this._getContentHtml(cellInfo) + AbstractDataCellRenderer.MAIN_DIV_END; +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + cellElement.innerHTML = this._getContentHtml(cellInfo); +} + + +/** + * Returns the CSS styles that should be applied to the main div of this cell. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return the CSS styles of the main div. + */ +qx.Proto._getCellStyle = function(cellInfo) { + return cellInfo.style + qx.ui.table.AbstractDataCellRenderer.MAIN_DIV_STYLE; +} + + +/** + * Returns the HTML that should be used inside the main div of this cell. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {String} the inner HTML of the main div. + */ +qx.Proto._getContentHtml = function(cellInfo) { + return cellInfo.value; +} + + +qx.Proto.createDataCellHtml_array_join = function(cellInfo, htmlArr) { + var AbstractDataCellRenderer = qx.ui.table.AbstractDataCellRenderer; + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(AbstractDataCellRenderer.TABLE_TD); + htmlArr.push(cellInfo.styleHeight); + htmlArr.push("px"); + } else { + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_LEFT); + htmlArr.push(cellInfo.styleLeft); + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_WIDTH); + htmlArr.push(cellInfo.styleWidth); + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_HEIGHT); + htmlArr.push(cellInfo.styleHeight); + htmlArr.push("px"); + } + + this._createCellStyle_array_join(cellInfo, htmlArr); + + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_START_END); + + this._createContentHtml_array_join(cellInfo, htmlArr); + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(AbstractDataCellRenderer.TABLE_TD_END); + } else { + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_END); + } +} + + +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + htmlArr.push(qx.ui.table.AbstractDataCellRenderer.MAIN_DIV_STYLE); +} + + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + htmlArr.push(cellInfo.value); +} + + +qx.Class.MAIN_DIV_START = '<div style="'; +qx.Class.MAIN_DIV_START_END = '">'; +qx.Class.MAIN_DIV_END = '</div>'; +/** main style */ +qx.Class.MAIN_DIV_STYLE = ';overflow:hidden;white-space:nowrap;border-right:1px solid #eeeeee;border-bottom:1px solid #eeeeee;padding-left:2px;padding-right:2px;cursor:default' + + (qx.core.Client.getInstance().isMshtml() ? '' : ';-moz-user-select:none;'); + +qx.Class.ARRAY_JOIN_MAIN_DIV_LEFT = '<div style="position:absolute;left:'; +qx.Class.ARRAY_JOIN_MAIN_DIV_WIDTH = 'px;top:0px;width:'; +qx.Class.ARRAY_JOIN_MAIN_DIV_HEIGHT = 'px;height:'; +qx.Class.ARRAY_JOIN_MAIN_DIV_START_END = '">'; +qx.Class.ARRAY_JOIN_MAIN_DIV_END = '</div>'; + +qx.Class.TABLE_TD = '<td style="height:'; +qx.Class.TABLE_TD_END = '</td>';
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractTableModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractTableModel.js new file mode 100644 index 0000000000..ba5e7506ff --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/AbstractTableModel.js @@ -0,0 +1,152 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * An abstract table model that performs the column handling, so subclasses only + * need to care for row handling. + */ +qx.OO.defineClass("qx.ui.table.AbstractTableModel", qx.ui.table.TableModel, +function() { + qx.ui.table.TableModel.call(this); + + this._columnIdArr = []; + this._columnNameArr = []; + this._columnIndexMap = {}; +}); + + +// overridden +qx.Proto.getColumnCount = function() { + return this._columnIdArr.length; +} + + +// overridden +qx.Proto.getColumnIndexById = function(columnId) { + return this._columnIndexMap[columnId]; +} + + +// overridden +qx.Proto.getColumnId = function(columnIndex) { + return this._columnIdArr[columnIndex]; +} + + +// overridden +qx.Proto.getColumnName = function(columnIndex) { + return this._columnNameArr[columnIndex]; +} + + +/** + * Sets the column IDs. These IDs may be used internally to identify a column. + * <p> + * Note: This will clear previously set column names. + * </p> + * + * @param columnIdArr {String[]} the IDs of the columns. + * @see #setColumns + */ +qx.Proto.setColumnIds = function(columnIdArr) { + this._columnIdArr = columnIdArr; + + // Create the reverse map + this._columnIndexMap = {}; + for (var i = 0; i < columnIdArr.length; i++) { + this._columnIndexMap[columnIdArr[i]] = i; + } + this._columnNameArr = new Array(columnIdArr.length); + + // Inform the listeners + if (!this._internalChange) { + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +/** + * Sets the column names. These names will be shown to the user. + * <p> + * Note: The column IDs have to be defined before. + * </p> + * + * @param columnNameArr {String[]} the names of the columns. + * @see #setColumnIds + */ +qx.Proto.setColumnNamesByIndex = function(columnNameArr) { + if (this._columnIdArr.length != columnNameArr.length) { + throw new Error("this._columnIdArr and columnNameArr have different length: " + + this._columnIdArr.length + " != " + columnNameArr.length); + } + this._columnNameArr = columnNameArr; + + // Inform the listeners + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Sets the column names. These names will be shown to the user. + * <p> + * Note: The column IDs have to be defined before. + * </p> + * + * @param columnNameMap {Map} a map containing the column IDs as keys and the + * column name as values. + * @see #setColumnIds + */ +qx.Proto.setColumnNamesById = function(columnNameMap) { + this._columnNameArr = new Array(this._columnIdArr.length); + for (var i = 0; i < this._columnIdArr.length; ++i) { + this._columnNameArr[i] = columnNameMap[this._columnIdArr[i]]; + } +} + + +/** + * Sets the columns. + * + * @param columnNameArr {String[]} The column names. These names will be shown to + * the user. + * @param columnIdArr {String[] ? null} The column IDs. These IDs may be used + * internally to identify a column. If null, the column names are used as + * IDs. + */ +qx.Proto.setColumns = function(columnNameArr, columnIdArr) { + if (columnIdArr == null) { + columnIdArr = columnNameArr; + } + + if (columnIdArr.length != columnNameArr.length) { + throw new Error("columnIdArr and columnNameArr have different length: " + + columnIdArr.length + " != " + columnNameArr.length); + } + + this._internalChange = true; + this.setColumnIds(columnIdArr); + this._internalChange = false; + this.setColumnNamesByIndex(columnNameArr); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js new file mode 100644 index 0000000000..44ec0d83ef --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#embed(qx.widgettheme/table/boolean-true.png) +#embed(qx.widgettheme/table/boolean-false.png) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * A data cell renderer for boolean values. + */ +qx.OO.defineClass("qx.ui.table.BooleanDataCellRenderer", qx.ui.table.IconDataCellRenderer, +function() { + qx.ui.table.IconDataCellRenderer.call(this); + + this._iconUrlTrue = qx.manager.object.AliasManager.getInstance().resolvePath("widget/table/boolean-true.png"); + this._iconUrlFalse = qx.manager.object.AliasManager.getInstance().resolvePath("widget/table/boolean-false.png"); + this._iconUrlNull = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + +}); + +//overridden +qx.Proto._identifyImage = function(cellInfo) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + var imageHints = { imageWidth:11, imageHeight:11 }; + switch (cellInfo.value) { + case true: imageHints.url = this._iconUrlTrue; break; + case false: imageHints.url = this._iconUrlFalse; break; + default: imageHints.url = this._iconUrlNull; break; + } + return imageHints; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js new file mode 100644 index 0000000000..9d699aed4d --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js @@ -0,0 +1,64 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A factory creating widgets to use for editing table cells. + */ +qx.OO.defineClass("qx.ui.table.CellEditorFactory", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates a cell editor. + * <p> + * The cellInfo map contains the following properties: + * <ul> + * <li>value (var): the cell's value.</li> + * <li>row (int): the model index of the row the cell belongs to.</li> + * <li>col (int): the model index of the column the cell belongs to.</li> + * <li>xPos (int): the x position of the cell in the table pane.</li> + * </ul> + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {qx.ui.core.Widget} the widget that should be used as cell editor. + */ +qx.Proto.createCellEditor = function(cellInfo) { + throw new Error("createCellEditor is abstract"); +} + + +/** + * Returns the current value of a cell editor. + * + * @param cellEditor {qx.ui.core.Widget} The cell editor formally created by + * {@link #createCellEditor}. + * @return {var} the current value from the editor. + */ +qx.Proto.getCellEditorValue = function(cellEditor) { + throw new Error("getCellEditorValue is abstract"); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js new file mode 100644 index 0000000000..cd9c461f98 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js @@ -0,0 +1,44 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 David Perez + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * David Perez (david-perez) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * For editing boolean data in a checkbox. It is advisable to use this in conjuntion with BooleanDataCellRenderer. + */ +qx.OO.defineClass("qx.ui.table.CheckBoxCellEditorFactory", qx.ui.table.CellEditorFactory, function() { + qx.ui.table.CellEditorFactory.call(this); +}); + +// overridden +qx.Proto.createCellEditor = function(cellInfo) { + var editor = new qx.ui.form.CheckBox; + editor.setChecked(cellInfo.value); + + return editor; +} + +// overridden +qx.Proto.getCellEditorValue = function(cellEditor) { + return cellEditor.getChecked(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js new file mode 100644 index 0000000000..553f071e55 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js @@ -0,0 +1,92 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell renderer for data cells. + */ +qx.OO.defineClass("qx.ui.table.DataCellRenderer", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates the HTML for a data cell. + * <p> + * The cellInfo map contains the following properties: + * <ul> + * <li>value (var): the cell's value.</li> + * <li>rowData (var): contains the row data for the row, the cell belongs to. + * The kind of this object depends on the table model, see + * {@link TableModel#getRowData()}</li> + * <li>row (int): the model index of the row the cell belongs to.</li> + * <li>col (int): the model index of the column the cell belongs to.</li> + * <li>table (qx.ui.table.Table): the table the cell belongs to.</li> + * <li>xPos (int): the x position of the cell in the table pane.</li> + * <li>selected (boolean): whether the cell is selected.</li> + * <li>focusedCol (boolean): whether the cell is in the same column as the + * focused cell.</li> + * <li>focusedRow (boolean): whether the cell is in the same row as the + * focused cell.</li> + * <li>editable (boolean): whether the cell is editable.</li> + * <li>style (string): The CSS styles that should be applied to the outer HTML + * element.</li> + * </ul> + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {String} the HTML of the data cell. + */ +qx.Proto.createDataCellHtml = function(cellInfo) { + throw new Error("createDataCellHtml is abstract"); +} + + +/** + * Updates the content of the pane. + * + * @param completeUpdate {Boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {Integer ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {Boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + throw new Error("updateDataCellElement is abstract"); +} + + +/** + * Updates the content of the pane using array joins. + * + * @param completeUpdate {Boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {Integer ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {Boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto.createDataCellHtml_array_join = function(cellInfo, htmlArr) { + throw new Error("createDataCellHtml_array_join is abstract"); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js new file mode 100644 index 0000000000..1dae6c85c9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js @@ -0,0 +1,56 @@ +/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2006 STZ-IDA, Germany, http://www.stz-ida.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Til Schneider (til132)
+
+************************************************************************ */
+
+/* ************************************************************************
+
+#module(ui_table)
+
+************************************************************************ */
+
+/**
+ * A cell renderer for data rows.
+ */
+qx.OO.defineClass("qx.ui.table.DataRowRenderer", qx.core.Object,
+function() {
+ qx.core.Object.call(this);
+});
+
+
+/**
+ * Updates a data row.
+ * <p>
+ * The rowInfo map contains the following properties:
+ * <ul>
+ * <li>rowData (var): contains the row data for the row.
+ * The kind of this object depends on the table model, see
+ * {@link TableModel#getRowData()}</li>
+ * <li>row (int): the model index of the row.</li>
+ * <li>selected (boolean): whether a cell in this row is selected.</li>
+ * <li>focusedRow (boolean): whether the focused cell is in this row.</li>
+ * <li>table (qx.ui.table.Table): the table the row belongs to.</li>
+ * </ul>
+ *
+ * @param rowInfo {Map} A map containing the information about the row to
+ * update. This map has the same structure as in {@link #createDataCell}.
+ * @param rowElement {element} the DOM element that renders the data rot. This
+ * is the same element formally created by the HTML from {@link #createDataCell}.
+ */
+qx.Proto.updateDataRowElement = function(rowInfo, rowElement) {
+ throw new Error("updateDataRowElement is abstract");
+}
diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js new file mode 100644 index 0000000000..cffdde9f51 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js @@ -0,0 +1,169 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +// This is needed because of the instantiation at the end of this file. +// I don't think this is a good idea. (wpbasti) +#require(qx.util.format.NumberFormat) + +************************************************************************ */ + +/** + * The default data cell renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultDataCellRenderer", qx.ui.table.AbstractDataCellRenderer, +function() { + qx.ui.table.AbstractDataCellRenderer.call(this); +}); + + +/** + * Whether the alignment should automatically be set according to the cell value. + * If true numbers will be right-aligned. + */ +qx.OO.addProperty({ name:"useAutoAlign", type:"boolean", defaultValue:true, allowNull:false }); + + +// overridden +qx.Proto._getCellStyle = function(cellInfo) { + var style = qx.ui.table.AbstractDataCellRenderer.prototype._getCellStyle(cellInfo); + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT){ + style += ";text-align:right"; + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_BOLD){ + style += ";font-weight:bold"; + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ITALIC){ + style += ";font-style:italic"; + } + + return style; +} + +/** + * Determines the styles to apply to the cell + * + * @param cellInfo {Object} cellInfo of the cell + * @return the sum of any of the STYLEFLAGS defined below + */ +qx.Proto._getStyleFlags = function(cellInfo) { + if (this.getUseAutoAlign()) { + if (typeof cellInfo.value == "number") { + return qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT; + } + } +} + + +// overridden +qx.Proto._getContentHtml = function(cellInfo) { + return qx.html.String.escape(this._formatValue(cellInfo)); +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + var clazz = qx.ui.table.DefaultDataCellRenderer; + var style = cellElement.style; + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & clazz.STYLEFLAG_ALIGN_RIGHT){ + style.textAlign = "right"; + } else { + style.textAlign = ""; + } + + if (stylesToApply & clazz.STYLEFLAG_BOLD){ + style.fontWeight = "bold"; + } else { + style.fontWeight = ""; + } + + if (stylesToApply & clazz.STYLEFLAG_ITALIC){ + style.fontStyle = "ital"; + } else { + style.fontStyle = ""; + } + + var textNode = cellElement.firstChild; + if (textNode != null) { + textNode.nodeValue = this._formatValue(cellInfo); + } else { + cellElement.innerHTML = qx.html.String.escape(this._formatValue(cellInfo)); + } +} + + +/** + * Formats a value. + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. This map has the same structure as in + * {@link DataCellRenderer#createDataCell}. + * @return {String} the formatted value. + */ +qx.Proto._formatValue = function(cellInfo) { + var value = cellInfo.value; + if (value == null) { + return ""; + } else if (typeof value == "number") { + return qx.ui.table.DefaultDataCellRenderer._numberFormat.format(value); + } else if (value instanceof Date) { + return qx.util.format.DateFormat.getDateInstance().format(value); + } else { + return value; + } +} + + +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + qx.ui.table.AbstractDataCellRenderer.prototype._createCellStyle_array_join(cellInfo, htmlArr); + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT){ + htmlArr.push(";text-align:right"); + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_BOLD){ + htmlArr.push(";font-weight:bold"); + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ITALIC){ + htmlArr.push(";font-style:italic"); + } +} + + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + htmlArr.push(qx.html.String.escape(this._formatValue(cellInfo))); +} + + +qx.Class._numberFormat = new qx.util.format.NumberFormat(); +qx.Class._numberFormat.setMaximumFractionDigits(2); + +qx.Class.STYLEFLAG_ALIGN_RIGHT = 1; +qx.Class.STYLEFLAG_BOLD = 2; +qx.Class.STYLEFLAG_ITALIC = 4; + + + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js new file mode 100644 index 0000000000..193f9ce155 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js @@ -0,0 +1,163 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The default data row renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultDataRowRenderer", qx.ui.table.DataRowRenderer, +function() { + qx.ui.table.DataRowRenderer.call(this); + + var Ddrr = qx.ui.table.DefaultDataRowRenderer; + + // Initialize to the default colors. + this._colors = + { + bgcolFocusedSelected : Ddrr.BGCOL_FOCUSED_SELECTED, + bgcolFocusedSelectedBlur : Ddrr.BGCOL_FOCUSED_SELECTED_BLUR, + bgcolFocused : Ddrr.BGCOL_FOCUSED, + bgcolFocusedBlur : Ddrr.BGCOL_FOCUSED_BLUR, + bgcolSelected : Ddrr.BGCOL_SELECTED, + bgcolSelectedBlur : Ddrr.BGCOL_SELECTED_BLUR, + bgcolEven : Ddrr.BGCOL_EVEN, + bgcolOdd : Ddrr.BGCOL_ODD, + colSelected : Ddrr.COL_SELECTED, + colNormal : Ddrr.COL_NORMAL + }; + +}); + + +/** Whether the focused row should be highlighted. */ +qx.OO.addProperty({ name:"highlightFocusRow", type:"boolean", allowNull:false, defaultValue:true}); + +/** + * Whether the focused row and the selection should be grayed out when the + * table hasn't the focus. + */ +qx.OO.addProperty({ name:"visualizeFocusedState", type:"boolean", allowNull:false, defaultValue:true}); + +/** The font family used for the data row */ +qx.OO.addProperty({ name:"fontFamily", type:"string", allowNull:false, defaultValue:"'Segoe UI', Corbel, Calibri, Tahoma, 'Lucida Sans Unicode', sans-serif" }); + +/** The font size used for the data row */ +qx.OO.addProperty({ name:"fontSize", type:"string", allowNull:false, defaultValue:"11px" }); + + +// overridden +qx.Proto.updateDataRowElement = function(rowInfo, rowElem) { + rowElem.style.fontFamily = this.getFontFamily(); + rowElem.style.fontSize = this.getFontSize(); + + if (rowInfo.focusedRow && this.getHighlightFocusRow()) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + rowElem.style.backgroundColor = rowInfo.selected ? this._colors.bgcolFocusedSelected : this._colors.bgcolFocused; + } else { + rowElem.style.backgroundColor = rowInfo.selected ? this._colors.bgcolFocusedSelectedBlur : this._colors.bgcolFocusedBlur; + } + } else { + if (rowInfo.selected) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + rowElem.style.backgroundColor = this._colors.bgcolSelected; + } else { + rowElem.style.backgroundColor = this._colors.bgcolSelectedBlur; + } + } else { + rowElem.style.backgroundColor = (rowInfo.row % 2 == 0) ? this._colors.bgcolEven : this._colors.bgcolOdd; + } + } + rowElem.style.color = rowInfo.selected ? this._colors.colSelected : this._colors.colNormal; +}; + + +// Array join test +qx.Proto._createRowStyle_array_join = function(rowInfo, htmlArr) { + htmlArr.push(";font-family:"); + htmlArr.push(this.getFontFamily()); + htmlArr.push(";font-size:"); + htmlArr.push(this.getFontSize()); + + htmlArr.push(";background-color:"); + if (rowInfo.focusedRow && this.getHighlightFocusRow()) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + htmlArr.push(rowInfo.selected ? this._colors.bgcolFocusedSelected : this._colors.bgcolFocused); + } else { + htmlArr.push(rowInfo.selected ? this._colors.bgcolFocusedSelectedBlur : this._colors.bgcolFocusedBlur); + } + } else { + if (rowInfo.selected) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + htmlArr.push(this._colors.bgcolSelected); + } else { + htmlArr.push(this._colors.bgcolSelectedBlur); + } + } else { + htmlArr.push((rowInfo.row % 2 == 0) ? this._colors.bgcolEven : this._colors.bgcolOdd); + } + } + htmlArr.push(';color:'); + htmlArr.push(rowInfo.selected ? this._colors.colSelected : this._colors.colNormal); +}; + + +/** + * Allow setting the table row colors. + * + * @param colors {Map} + * The value of each property in the map is a string containing either a + * number (e.g. "#518ad3") or color name ("white") representing the color + * for that type of display. The map may contain any or all of the + * following properties: + * <ul> + * <li>bgcolFocusedSelected</li> + * <li>bgcolFocusedSelectedBlur</li> + * <li>bgcolFocused</li> + * <li>bgcolFocusedBlur</li> + * <li>bgcolSelected</li> + * <li>bgcolSelectedBlur</li> + * <li>bgcolEven</li> + * <li>bgcolOdd</li> + * <li>colSelected</li> + * <li>colNormal</li> + * </ul> + */ +qx.Proto.setRowColors = function(colors) +{ + for (var color in colors) + { + this._colors[color] = colors[color]; + } +} + +qx.Class.BGCOL_FOCUSED_SELECTED = "#5a8ad3"; +qx.Class.BGCOL_FOCUSED_SELECTED_BLUR = "#b3bac6"; +qx.Class.BGCOL_FOCUSED = "#ddeeff"; +qx.Class.BGCOL_FOCUSED_BLUR = "#dae0e7"; +qx.Class.BGCOL_SELECTED = "#335ea8"; +qx.Class.BGCOL_SELECTED_BLUR = "#989ea8"; +qx.Class.BGCOL_EVEN = "#faf8f3"; +qx.Class.BGCOL_ODD = "white"; +qx.Class.COL_SELECTED = "white"; +qx.Class.COL_NORMAL = "black"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js new file mode 100644 index 0000000000..97b788b1a9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js @@ -0,0 +1,67 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#embed(qx.widgettheme/table/ascending.png) +#embed(qx.widgettheme/table/descending.png) + +************************************************************************ */ + +/** + * The default header cell renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultHeaderCellRenderer", qx.ui.table.HeaderCellRenderer, +function() { + qx.ui.table.HeaderCellRenderer.call(this); +}); + + +// overridden +qx.Proto.createHeaderCell = function(cellInfo) { + var widget = new qx.ui.basic.Atom(); + widget.setAppearance("table-header-cell"); + + this.updateHeaderCell(cellInfo, widget); + + return widget; +} + + +// overridden +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + var DefaultHeaderCellRenderer = qx.ui.table.DefaultHeaderCellRenderer; + + cellWidget.setLabel(cellInfo.name); + + cellWidget.setIcon(cellInfo.sorted ? (cellInfo.sortedAscending ? "widget/table/ascending.png" : "widget/table/descending.png") : null); + cellWidget.setState(DefaultHeaderCellRenderer.STATE_SORTED, cellInfo.sorted); + cellWidget.setState(DefaultHeaderCellRenderer.STATE_SORTED_ASCENDING, cellInfo.sortedAscending); +} + +/** + * (string) The state which will be set for header cells of sorted columns. + */ +qx.Class.STATE_SORTED = "sorted"; + +/** + * (string) The state which will be set when sorting is ascending. + */ +qx.Class.STATE_SORTED_ASCENDING = "sortedAscending"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js new file mode 100644 index 0000000000..8d66198bb0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js @@ -0,0 +1,71 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell renderer for header cells. + */ +qx.OO.defineClass("qx.ui.table.HeaderCellRenderer", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates a header cell. + * <p> + * The cellInfo map contains the following properties: + * <ul> + * <li>col (int): the model index of the column.</li> + * <li>xPos (int): the x position of the column in the table pane.</li> + * <li>name (string): the name of the column.</li> + * <li>editable (boolean): whether the column is editable.</li> + * <li>sorted (boolean): whether the column is sorted.</li> + * <li>sortedAscending (boolean): whether sorting is ascending.</li> + * </ul> + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {qx.ui.core.Widget} the widget that renders the header cell. + */ +qx.Proto.createHeaderCell = function(cellInfo) { + throw new Error("createHeaderCell is abstract"); +} + + +/** + * Updates a header cell. + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. This map has the same structure as in {@link #createHeaderCell}. + * @param cellWidget {qx.ui.core.Widget} the widget that renders the header cell. This is + * the same widget formally created by {@link #createHeaderCell}. + */ +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + throw new Error("updateHeaderCell is abstract"); +} + + +/** The preferred height of cells created by this header renderer. */ +qx.OO.addProperty({ name:"prefferedCellHeight", type:"number", defaultValue:16, allowNull:false }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js new file mode 100644 index 0000000000..2e89779355 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js @@ -0,0 +1,185 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#embed(qx.static/image/blank.gif) + +************************************************************************ */ + +/** + * A data cell renderer for boolean values. + */ +qx.OO.defineClass("qx.ui.table.IconDataCellRenderer", qx.ui.table.AbstractDataCellRenderer, +function() { + qx.ui.table.AbstractDataCellRenderer.call(this); + this.IMG_BLANK_URL = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); +}); + + +/** + * Identifies the Image to show. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {Map} A map having the following attributes: + * <ul> + * <li>"url": (type string) must be the URL of the image to show.</li> + * <li>"imageWidth": (type int) the width of the image in pixels.</li> + * <li>"imageHeight": (type int) the height of the image in pixels.</li> + * <li>"tooltip": (type string) must be the image tooltip text.</li> + * </ul> + */ +qx.Proto._identifyImage = function(cellInfo) { + throw new Error("_identifyImage is abstract"); +} + + +/** + * Retrieves the image infos. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {Map} Map with an "url" attribute (type string) + * holding the URL of the image to show + * and a "tooltip" attribute + * (type string) being the tooltip text (or null if none was specified) + * + */ +qx.Proto._getImageInfos= function(cellInfo) { + // Query the subclass about image and tooltip + var urlAndTooltipMap = this._identifyImage(cellInfo); + + // If subclass refuses to give map, construct it + if (urlAndTooltipMap == null || typeof urlAndTooltipMap == "string"){ + urlAndTooltipMap = {url:urlAndTooltipMap, tooltip:null}; + } + + // If subclass gave null as url, replace with url to empty image + if (urlAndTooltipMap.url == null){ + urlAndTooltipMap.url = this.IMG_BLANK_URL; + } + + return urlAndTooltipMap; +} + +// overridden +qx.Proto._getCellStyle = function(cellInfo) { + var style = qx.ui.table.AbstractDataCellRenderer.prototype._getCellStyle(cellInfo); + style += qx.ui.table.IconDataCellRenderer.MAIN_DIV_STYLE; + return style; +} + + +// overridden +qx.Proto._getContentHtml = function(cellInfo) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + + var urlAndToolTip = this._getImageInfos(cellInfo); + var html = IconDataCellRenderer.IMG_START; + if (qx.core.Client.getInstance().isMshtml() && /\.png$/i.test(urlAndToolTip.url)) { + html += qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif") + + '" style="filter:' + "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + urlAndToolTip.url + "',sizingMethod='scale')"; + } else { + html += urlAndToolTip.url + '" style="'; + } + + if (urlAndToolTip.imageWidth && urlAndToolTip.imageHeight) { + html += ';width:' + urlAndToolTip.imageWidth + 'px' + + ';height:' + urlAndToolTip.imageHeight + 'px'; + } + + var tooltip = urlAndToolTip.tooltip; + if (tooltip != null){ + html += IconDataCellRenderer.IMG_TITLE_START + tooltip; + } + html += IconDataCellRenderer.IMG_END; + return html; +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + // Set image and tooltip text + var urlAndToolTip = this._getImageInfos(cellInfo); + var img = cellElement.firstChild; + if (qx.core.Client.getInstance().isMshtml()) { + if (/\.png$/i.test(urlAndToolTip.url)) { + img.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + urlAndToolTip.url + "',sizingMethod='scale')"; + } else { + img.src = urlAndToolTip.url; + img.style.filter = ""; + } + } else { + img.src = urlAndToolTip.url; + } + + if (urlAndToolTip.imageWidth && urlAndToolTip.imageHeight) { + img.style.width = urlAndToolTip.imageWidth + "px"; + img.style.height = urlAndToolTip.imageHeight + "px"; + } + + if (urlAndToolTip.tooltip != null){ + img.setAttribute("title", urlAndToolTip.tooltip); + } +} + + +// overridden +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + qx.ui.table.AbstractDataCellRenderer.prototype._createCellStyle_array_join(cellInfo, htmlArr); + + htmlArr.push(qx.ui.table.IconDataCellRenderer.MAIN_DIV_STYLE); +} + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(IconDataCellRenderer.TABLE_DIV); + htmlArr.push(cellInfo.styleHeight - 2); // -1 for the border, -1 for the padding + htmlArr.push(IconDataCellRenderer.TABLE_DIV_CLOSE); + } + + htmlArr.push(IconDataCellRenderer.IMG_START); + var urlAndToolTip = this._getImageInfos(cellInfo); + htmlArr.push(urlAndToolTip.url); + var tooltip = urlAndToolTip.tooltip; + if (tooltip != null){ + IconDataCellRenderer.IMG_TITLE_START; + htmlArr.push(tooltip); + } + htmlArr.push(IconDataCellRenderer.IMG_END); + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(IconDataCellRenderer.TABLE_DIV_END); + } +} + +qx.Class.MAIN_DIV_STYLE = ';text-align:center;padding-top:1px;'; +qx.Class.IMG_START = '<img src="'; +qx.Class.IMG_END = '"/>'; +qx.Class.IMG_TITLE_START = '" title="'; +qx.Class.TABLE_DIV = '<div style="overflow:hidden;height:'; +qx.Class.TABLE_DIV_CLOSE = 'px">'; +qx.Class.TABLE_DIV_END = '</div>'; + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js new file mode 100644 index 0000000000..fd646e882c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js @@ -0,0 +1,86 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A header cell renderer which renders an icon (only). The icon cannot be combined + * with text. + * + * @param iconUrl {String} URL to the icon to show + * @param tooltip {String ? ""} Text of the tooltip to show if the mouse hovers over the + * icon + * + */ +qx.OO.defineClass("qx.ui.table.IconHeaderCellRenderer", qx.ui.table.DefaultHeaderCellRenderer, +function(iconUrl, tooltip) { + qx.ui.table.DefaultHeaderCellRenderer.call(this); + if (iconUrl == null){ + iconUrl = ""; + } + this.setIconUrl(iconUrl); + this.setToolTip(tooltip); +}); + +/** + * URL of the icon to show + */ +qx.OO.addProperty({ name:"iconUrl", type:"string", defaultValue:"", allowNull:false }); + +/** + * ToolTip to show if the mouse hovers of the icon + */ +qx.OO.addProperty({ name:"toolTip", type:"string", defaultValue:null, allowNull:true }); + +// overridden +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + qx.ui.table.DefaultHeaderCellRenderer.prototype.updateHeaderCell.call(this, cellInfo, cellWidget); + + // Set URL to icon + var img = cellWidget.getUserData("qx_ui_table_IconHeaderCellRenderer_icon"); + if (img == null){ + img = new qx.ui.basic.Image(); + cellWidget.setUserData("qx_ui_table_IconHeaderCellRenderer_icon", img); + cellWidget.addAtBegin(img); + } + img.setSource(this.getIconUrl()); + + // Set image tooltip if given + var widgetToolTip = cellWidget.getToolTip(); + if (this.getToolTip() != null){ + + //Create tooltip if necessary + if (true || widgetToolTip == null ){ + widgetToolTip = new qx.ui.popup.ToolTip(this.getToolTip()); + cellWidget.setToolTip(widgetToolTip); + //this.debug("Creating tooltip"); + } + + //Set tooltip text + widgetToolTip.getAtom().setLabel(this.getToolTip()); + //this.debug("Setting tooltip text " + this.getToolTip()); + } + +} + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js new file mode 100644 index 0000000000..1d59e1c48a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js @@ -0,0 +1,453 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A table model that loads its data from a backend. + * <p> + * Only those rows are loaded that are near the area the user is currently + * viewing. If the user scrolls, the rows he will see soon are loaded + * asynchroniously in the background. All loaded data is managed in a cache that + * automatically removes the last resently used rows when it gets full. + * <p> + * This class is abstract: The actual loading of row data must be done by + * subclasses. + */ +qx.OO.defineClass("qx.ui.table.RemoteTableModel", qx.ui.table.AbstractTableModel, +function() { + qx.ui.table.AbstractTableModel.call(this); + + this._sortColumnIndex = -1; + this._sortAscending = true; + this._rowCount = -1; + + this._lruCounter = 0; + + // Holds the index of the first block that is currently loading. + // Is -1 if there is currently no request on its way. + this._firstLoadingBlock = -1; + + // Holds the index of the first row that should be loaded when the response of + // the current request arrives. Is -1 we need no following request. + this._firstRowToLoad = -1; + + // Counterpart to _firstRowToLoad + this._lastRowToLoad = -1; + + // Holds whether the current request will bring obsolete data. When true the + // response of the current request will be ignored. + this._ignoreCurrentRequest = false; + + this._rowBlockCache = {}; + this._rowBlockCount = 0; +}); + + +/** The number of rows that are stored in one cache block. */ +qx.OO.addProperty({ name:"blockSize", type:"number", defaultValue:50, allowNull:false }); + +/** The maximum number of row blocks kept in the cache. */ +qx.OO.addProperty({ name:"maxCachedBlockCount", type:"number", defaultValue:15, allowNull:false }); + +/** + * Whether to clear the cache when some rows are removed. + * If false the rows are removed locally in the cache. + */ +qx.OO.addProperty({ name:"clearCacheOnRemove", type:"boolean", defaultValue:false, allowNull:false }); + + +// overridden +qx.Proto.getRowCount = function() { + if (this._rowCount == -1) { + this._loadRowCount(); + + // NOTE: _loadRowCount may set this._rowCount + return (this._rowCount == -1) ? 0 : this._rowCount; + } else { + return this._rowCount; + } +} + + +/** + * Loads the row count from the server. + * <p> + * Implementing classes have to call {@link _onRowDataLoaded()} when the server + * response arrived. That method has to be called! Even when there was an error. + */ +qx.Proto._loadRowCount = function() { + throw new Error("_loadRowCount is abstract"); +}; + + +/** + * Sets the row count. + * <p> + * Has to be called by {@link _loadRowCount()}. + * + * @param rowCount {Integer} the number of rows in this model or null if loading. + */ +qx.Proto._onRowCountLoaded = function(rowCount) { + // this.debug("row count loaded: " + rowCount); + if (rowCount == null) { + rowCount = 0; + } + this._rowCount = rowCount; + + // Inform the listeners + var data = { firstRow:0, lastRow:rowCount - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); +}; + + +/** + * Reloads the model and clears the local cache. + */ +qx.Proto.reloadData = function() { + this.clearCache(); + + // If there is currently a request on its way, then this request will bring + // obsolete data -> Ignore it + if (this._firstLoadingBlock != -1) { + this._ignoreCurrentRequest = true; + } + + // Forget a possibly outstanding request + // (_loadRowCount will tell the listeners anyway, that the whole table changed) + this._firstRowToLoad = -1; + this._lastRowToLoad = -1; + + // NOTE: This will inform the listeners as soon as the new row count is known + this._loadRowCount(); +}; + + +/** + * Clears the cache. + */ +qx.Proto.clearCache = function() { + this._rowBlockCache = {}; + this._rowBlockCount = 0; +}; + + +// overridden +qx.Proto.prefetchRows = function(firstRowIndex, lastRowIndex) { + // this.debug("Prefetch wanted: " + firstRowIndex + ".." + lastRowIndex); + if (this._firstLoadingBlock == -1) { + var blockSize = this.getBlockSize(); + var totalBlockCount = Math.ceil(this._rowCount / blockSize); + + // There is currently no request running -> Start a new one + // NOTE: We load one more block above and below to have a smooth + // scrolling into the next block without blank cells + var firstBlock = parseInt(firstRowIndex / blockSize) - 1; + if (firstBlock < 0) { + firstBlock = 0; + } + var lastBlock = parseInt(lastRowIndex / blockSize) + 1; + if (lastBlock >= totalBlockCount) { + lastBlock = totalBlockCount - 1; + } + + // Check which blocks we have to load + var firstBlockToLoad = -1; + var lastBlockToLoad = -1; + for (var block = firstBlock; block <= lastBlock; block++) { + if (this._rowBlockCache[block] == null || this._rowBlockCache[block].isDirty) { + // We don't have this block + if (firstBlockToLoad == -1) { + firstBlockToLoad = block; + } + lastBlockToLoad = block; + } + } + + // Load the blocks + if (firstBlockToLoad != -1) { + this._firstRowToLoad = -1; + this._lastRowToLoad = -1; + + this._firstLoadingBlock = firstBlockToLoad; + + // this.debug("Starting server request. rows: " + firstRowIndex + ".." + lastRowIndex + ", blocks: " + firstBlockToLoad + ".." + lastBlockToLoad); + this._loadRowData(firstBlockToLoad * blockSize, (lastBlockToLoad + 1) * blockSize - 1); + } + } else { + // There is already a request running -> Remember this request + // so it can be executed after the current one is finished. + this._firstRowToLoad = firstRowIndex; + this._lastRowToLoad = lastRowIndex; + } +}; + + +/** + * Loads some row data from the server. + * <p> + * Implementing classes have to call {@link _onRowDataLoaded()} when the server + * response arrived. That method has to be called! Even when there was an error. + * + * @param firstRow {Integer} The index of the first row to load. + * @param lastRow {Integer} The index of the last row to load. + */ +qx.Proto._loadRowData = function(firstRow, lastRow) { + throw new Error("_loadRowCount is abstract"); +}; + + +/** + * Sets row data. + * <p> + * Has to be called by {@link _loadRowData()}. + * + * @param rowDataArr {Map[]} the loaded row data or null if there was an error. + */ +qx.Proto._onRowDataLoaded = function(rowDataArr) { + if (rowDataArr != null && ! this._ignoreCurrentRequest) { + var blockSize = this.getBlockSize(); + var blockCount = Math.ceil(rowDataArr.length / blockSize); + if (blockCount == 1) { + // We got one block -> Use the rowData directly + this._setRowBlockData(this._firstLoadingBlock, rowDataArr); + } else { + // We got more than one block -> We've to split the rowData + for (var i = 0; i < blockCount; i++) { + var rowOffset = i * blockSize; + var blockRowData = []; + var mailCount = Math.min(blockSize, rowDataArr.length - rowOffset); + for (var row = 0; row < mailCount; row++) { + blockRowData.push(rowDataArr[rowOffset + row]); + } + + this._setRowBlockData(this._firstLoadingBlock + i, blockRowData); + } + } + // this.debug("Got server answer. blocks: " + this._firstLoadingBlock + ".." + (this._firstLoadingBlock + blockCount - 1) + ". mail count: " + rowDataArr.length + " block count:" + blockCount); + + // Inform the listeners + var data = { + firstRow:this._firstLoadingBlock * blockSize, + lastRow:(this._firstLoadingBlock + blockCount + 1) * blockSize - 1, + firstColumn:0, + lastColumn:this.getColumnCount() - 1 + }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + // We're not loading any blocks any more + this._firstLoadingBlock = -1; + this._ignoreCurrentRequest = false; + + // Check whether we have to start a new request + if (this._firstRowToLoad != -1) { + this.prefetchRows(this._firstRowToLoad, this._lastRowToLoad); + } +}; + + +/** + * Sets the data of one block. + * + * @param block {Integer} the index of the block. + * @param rowDataArr {var[][]} the data to set. + */ +qx.Proto._setRowBlockData = function(block, rowDataArr) { + if (this._rowBlockCache[block] == null) { + // This is a new block -> Check whether we have to remove another block first + this._rowBlockCount++; + + while (this._rowBlockCount > this.getMaxCachedBlockCount()) { + // Find the last recently used block + // NOTE: We never remove block 0 and 1 + var lruBlock; + var minLru = this._lruCounter; + for (var currBlock in this._rowBlockCache) { + var currLru = this._rowBlockCache[currBlock].lru; + if (currLru < minLru && currBlock > 1) { + minLru = currLru; + lruBlock = currBlock; + } + } + + // Remove that block + // this.debug("Removing block: " + lruBlock + ". current LRU: " + this._lruCounter); + delete this._rowBlockCache[lruBlock]; + this._rowBlockCount--; + } + } + + this._rowBlockCache[block] = { lru:++this._lruCounter, rowDataArr:rowDataArr }; +}; + + +/** + * Removes a rows from the model. + * + * @param rowIndex {Integer} the index of the row to remove. + */ +qx.Proto.removeRow = function(rowIndex) { + if (this.getClearCacheOnRemove()) { + this.clearCache(); + + // Inform the listeners + var data = { firstRow:0, lastRow:rowCount - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } else { + var blockSize = this.getBlockSize(); + var blockCount = Math.ceil(this.getRowCount() / blockSize); + var startBlock = parseInt(rowIndex / blockSize); + + // Remove the row and move the rows of all following blocks + for (var block = startBlock; block <= blockCount; block++) { + var blockData = this._rowBlockCache[block]; + if (blockData != null) { + // Remove the row in the start block + // NOTE: In the other blocks the first row is removed + // (This is the row that was) + var removeIndex = 0; + if (block == startBlock) { + removeIndex = rowIndex - block * blockSize; + } + blockData.rowDataArr.splice(removeIndex, 1); + + if (block == blockCount - 1) { + // This is the last block + if (blockData.rowDataArr.length == 0) { + // It is empty now -> Remove it + delete this._rowBlockCache[block]; + } + } else { + // Try to copy the first row of the next block to the end of this block + // so this block can stays clean + var nextBlockData = this._rowBlockCache[block + 1]; + if (nextBlockData != null) { + blockData.rowDataArr.push(nextBlockData.rowDataArr[0]); + } else { + // There is no row to move -> Mark this block as dirty + blockData.isDirty = true; + } + } + } + } + + if (this._rowCount != -1) { + this._rowCount--; + } + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:rowIndex, lastRow:this.getRowCount() - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + } +}; + + +/** + * <p>See overridden method for details.</p> + * + * @param rowIndex {Integer} the model index of the row. + * @return {Object} Map containing a value for each column. + */ +qx.Proto.getRowData = function(rowIndex) { + var blockSize = this.getBlockSize(); + var block = parseInt(rowIndex / blockSize); + var blockData = this._rowBlockCache[block]; + if (blockData == null) { + // This block is not (yet) loaded + return null; + } else { + var rowData = blockData.rowDataArr[rowIndex - (block * blockSize)]; + + // Update the last recently used counter + if (blockData.lru != this._lruCounter) { + blockData.lru = ++this._lruCounter; + } + + return rowData; + } +}; + + +// overridden +qx.Proto.getValue = function(columnIndex, rowIndex) { + var rowData = this.getRowData(rowIndex); + if (rowData == null) { + return null; + } else { + var columnId = this.getColumnId(columnIndex); + return rowData[columnId]; + } +}; + + +/** + * Sets whether a column is sortable. + * + * @param columnIndex {Integer} the column of which to set the sortable state. + * @param sortable {Boolean} whether the column should be sortable. + */ +qx.Proto.setColumnSortable = function(columnIndex, sortable) { + if (sortable != this.isColumnSortable(columnIndex)) { + if (this._sortableColArr == null) { + this._sortableColArr = []; + } + this._sortableColArr[columnIndex] = sortable; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.isColumnSortable = function(columnIndex) { + return this._sortableColArr ? (this._sortableColArr[columnIndex] == true) : false; +} + + +// overridden +qx.Proto.sortByColumn = function(columnIndex, ascending) { + if (this._sortColumnIndex != columnIndex || this._sortAscending != ascending) { + this._sortColumnIndex = columnIndex; + this._sortAscending = ascending; + + this.clearCache(); + + // Inform the listeners + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +}; + + +// overridden +qx.Proto.getSortColumnIndex = function() { + return this._sortColumnIndex; +} + + +// overridden +qx.Proto.isSortAscending = function() { + return this._sortAscending; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js new file mode 100644 index 0000000000..6f7fb11eed --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js @@ -0,0 +1,165 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A selection manager. This is a helper class that handles all selection + * related events and updates a SelectionModel. + * <p> + * Widgets that support selection should use this manager. This way the only + * thing the widget has to do is mapping mouse or key events to indexes and + * call the corresponding handler method. + * + * @see SelectionModel + */ +qx.OO.defineClass("qx.ui.table.SelectionManager", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * The selection model where to set the selection changes. + */ +qx.OO.addProperty({ name:"selectionModel", type:"object", instance:"qx.ui.table.SelectionModel" }); + + +/** + * Handles the mouse down event. + * + * @param index {Integer} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleMouseDown = function(index, evt) { + if (evt.isLeftButtonPressed()) { + var selectionModel = this.getSelectionModel(); + if (!selectionModel.isSelectedIndex(index)) { + // This index is not selected -> We react when the mouse is pressed (because of drag and drop) + this._handleSelectEvent(index, evt); + this._lastMouseDownHandled = true; + } else { + // This index is already selected -> We react when the mouse is released (because of drag and drop) + this._lastMouseDownHandled = false; + } + } else if (evt.isRightButtonPressed() && evt.getModifiers() == 0) { + var selectionModel = this.getSelectionModel(); + if (!selectionModel.isSelectedIndex(index)) { + // This index is not selected -> Set the selection to this index + selectionModel.setSelectionInterval(index, index); + } + } +} + + +/** + * Handles the mouse up event. + * + * @param index {Integer} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleMouseUp = function(index, evt) { + if (evt.isLeftButtonPressed() && !this._lastMouseDownHandled) { + this._handleSelectEvent(index, evt); + } +} + + +/** + * Handles the mouse click event. + * + * @param index {Integer} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleClick = function(index, evt) { +} + + +/** + * Handles the key down event that is used as replacement for mouse clicks + * (Normally space). + * + * @param index {Integer} the index that is currently focused. + * @param evt {Map} the key event. + */ +qx.Proto.handleSelectKeyDown = function(index, evt) { + this._handleSelectEvent(index, evt); +}; + + +/** + * Handles a key down event that moved the focus (E.g. up, down, home, end, ...). + * + * @param index {Integer} the index that is currently focused. + * @param evt {Map} the key event. + */ +qx.Proto.handleMoveKeyDown = function(index, evt) { + var selectionModel = this.getSelectionModel(); + switch (evt.getModifiers()) { + case 0: + selectionModel.setSelectionInterval(index, index); + break; + case qx.event.type.DomEvent.SHIFT_MASK: + var anchor = selectionModel.getAnchorSelectionIndex(); + if (anchor == -1) { + selectionModel.setSelectionInterval(index, index); + } else { + selectionModel.setSelectionInterval(anchor, index); + } + break; + } +} + + +/** + * Handles a select event. + * + * @param index {Integer} the index the event is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto._handleSelectEvent = function(index, evt) { + var selectionModel = this.getSelectionModel(); + if (evt.isShiftPressed()) { + var leadIndex = selectionModel.getLeadSelectionIndex(); + if (index != leadIndex || selectionModel.isSelectionEmpty()) { + // The lead selection index was changed + var anchorIndex = selectionModel.getAnchorSelectionIndex(); + if (anchorIndex == -1) { + anchorIndex = index; + } + if (evt.isCtrlOrCommandPressed()) { + selectionModel.addSelectionInterval(anchorIndex, index); + } else { + selectionModel.setSelectionInterval(anchorIndex, index); + } + } + } else if (evt.isCtrlOrCommandPressed()) { + if (selectionModel.isSelectedIndex(index)) { + selectionModel.removeSelectionInterval(index, index); + } else { + selectionModel.addSelectionInterval(index, index); + } + } else { + selectionModel.setSelectionInterval(index, index); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js new file mode 100644 index 0000000000..2e03a1fc8c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js @@ -0,0 +1,431 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A selection model. + * + * @event changeSelection {qx.event.type.Event} Fired when the selection has + * changed. + */ +qx.OO.defineClass("qx.ui.table.SelectionModel", qx.core.Target, +function() { + qx.core.Target.call(this); + + this._selectedRangeArr = []; + this._anchorSelectionIndex = -1; + this._leadSelectionIndex = -1; + this.hasBatchModeRefCount = 0; + this._hadChangeEventInBatchMode = false; +}); + + +/** {int} The selection mode "none". Nothing can ever be selected. */ +qx.Class.NO_SELECTION = 1; + +/** {int} The selection mode "single". This mode only allows one selected item. */ +qx.Class.SINGLE_SELECTION = 2; + +/** + * (int) The selection mode "single interval". This mode only allows one + * continuous interval of selected items. + */ +qx.Class.SINGLE_INTERVAL_SELECTION = 3; + +/** + * (int) The selection mode "multiple interval". This mode only allows any + * selection. + */ +qx.Class.MULTIPLE_INTERVAL_SELECTION = 4; + + +/** + * (int) the selection mode. + */ +qx.OO.addProperty({ name:"selectionMode", type:"number", + defaultValue:qx.Class.SINGLE_SELECTION, + allowNull:false, + possibleValues:[ qx.Class.NO_SELECTION, + qx.Class.SINGLE_SELECTION, + qx.Class.SINGLE_INTERVAL_SELECTION, + qx.Class.MULTIPLE_INTERVAL_SELECTION ] }); + +// selectionMode property modifier +qx.Proto._modifySelectionMode = function(selectionMode) { + if (selectionMode == qx.ui.table.SelectionModel.NO_SELECTION) { + this.clearSelection(); + } + return true; +} + + +/** + * <p>Activates / Deactivates batch mode. In batch mode, no change events will be thrown but + * will be collected instead. When batch mode is turned off again and any events have + * been collected, one event is thrown to inform the listeners.</p> + * + * <p>This method supports nested calling, i. e. batch mode can be turned more than once. + * In this case, batch mode will not end until it has been turned off once for each + * turning on.</p> + * + * @param batchMode {Boolean} true to activate batch mode, false to deactivate + * @return {Boolean} true if batch mode is active, false otherwise + * @throws Error if batch mode is turned off once more than it has been turned on + */ +qx.Proto.setBatchMode = function(batchMode) { + if (batchMode){ + this.hasBatchModeRefCount += 1; + } else { + if (this.hasBatchModeRefCount == 0){ + throw new Error("Try to turn off batch mode althoug it was not turned on.") + } + this.hasBatchModeRefCount -= 1; + if (this._hadChangeEventInBatchMode){ + this._hadChangeEventInBatchMode = false; + this._fireChangeSelection(); + } + } + return this.hasBatchMode(); +} + + +/** + * <p>Returns whether batch mode is active. See setter for a description of batch mode.</p> + * + * @return {Boolean} true if batch mode is active, false otherwise + */ +qx.Proto.hasBatchMode = function() { + return this.hasBatchModeRefCount > 0; +} + + +/** + * Returns the first argument of the last call to {@link #setSelectionInterval()}, + * {@link #addSelectionInterval()} or {@link #removeSelectionInterval()}. + * + * @return {Integer} the ancor selection index. + */ +qx.Proto.getAnchorSelectionIndex = function() { + return this._anchorSelectionIndex; +} + + +/** + * Returns the second argument of the last call to {@link #setSelectionInterval()}, + * {@link #addSelectionInterval()} or {@link #removeSelectionInterval()}. + * + * @return {Integer} the lead selection index. + */ +qx.Proto.getLeadSelectionIndex = function() { + return this._leadSelectionIndex; +} + + +/** + * Clears the selection. + */ +qx.Proto.clearSelection = function() { + if (! this.isSelectionEmpty()) { + this._clearSelection(); + this._fireChangeSelection(); + } +} + + +/** + * Returns whether the selection is empty. + * + * @return {Boolean} whether the selection is empty. + */ +qx.Proto.isSelectionEmpty = function() { + return this._selectedRangeArr.length == 0; +} + + +/** + * Returns the number of selected items. + * + * @return {Integer} the number of selected items. + */ +qx.Proto.getSelectedCount = function() { + var selectedCount = 0; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + selectedCount += range.maxIndex - range.minIndex + 1; + } + + return selectedCount; +} + + +/** + * Returns whether a index is selected. + * + * @param index {Integer} the index to check. + * @return {Boolean} whether the index is selected. + */ +qx.Proto.isSelectedIndex = function(index) { + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (index >= range.minIndex && index <= range.maxIndex) { + return true; + } + } + + return false; +} + + +/** + * Returns the selected ranges as an array. Each array element has a + * <code>minIndex</code> and a <code>maxIndex</code> property. + * + * @return {Map[]} the selected ranges. + */ +qx.Proto.getSelectedRanges = function() { + // clone the selection array and the individual elements - this prevents the + // caller from messing with the internal model + var retVal = []; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + retVal.push({minIndex: this._selectedRangeArr[i].minIndex, + maxIndex: this._selectedRangeArr[i].maxIndex}); + } + return retVal; +} + + +/** + * Calls a iterator function for each selected index. + * <p> + * Usage Example: + * <pre> + * var selectedRowData = []; + * mySelectionModel.iterateSelection(function(index) { + * selectedRowData.push(myTableModel.getRowData(index)); + * }); + * </pre> + * + * @param iterator {Function} the function to call for each selected index. + * Gets the current index as parameter. + * @param object {var ? null} the object to use when calling the handler. + * (this object will be available via "this" in the iterator) + */ +qx.Proto.iterateSelection = function(iterator, object) { + for (var i = 0; i < this._selectedRangeArr.length; i++) { + for (var j = this._selectedRangeArr[i].minIndex; j <= this._selectedRangeArr[i].maxIndex; j++) { + iterator.call(object, j); + } + } +}; + + +/** + * Sets the selected interval. This will clear the former selection. + * + * @param fromIndex {Integer} the first index of the selection (including). + * @param toIndex {Integer} the last index of the selection (including). + */ +qx.Proto.setSelectionInterval = function(fromIndex, toIndex) { + var SelectionModel = qx.ui.table.SelectionModel; + + switch(this.getSelectionMode()) { + case SelectionModel.NO_SELECTION: + return; + case SelectionModel.SINGLE_SELECTION: + fromIndex = toIndex; + break; + } + + this._clearSelection(); + this._addSelectionInterval(fromIndex, toIndex); + + this._fireChangeSelection(); +} + + +/** + * Adds a selection interval to the current selection. + * + * @param fromIndex {Integer} the first index of the selection (including). + * @param toIndex {Integer} the last index of the selection (including). + */ +qx.Proto.addSelectionInterval = function(fromIndex, toIndex) { + var SelectionModel = qx.ui.table.SelectionModel; + switch (this.getSelectionMode()) { + case SelectionModel.NO_SELECTION: + return; + case SelectionModel.MULTIPLE_INTERVAL_SELECTION: + this._addSelectionInterval(fromIndex, toIndex); + this._fireChangeSelection(); + break; + default: + this.setSelectionInterval(fromIndex, toIndex); + break; + } +} + + +/** + * Removes a interval from the current selection. + * + * @param fromIndex {Integer} the first index of the interval (including). + * @param toIndex {Integer} the last index of the interval (including). + */ +qx.Proto.removeSelectionInterval = function(fromIndex, toIndex) { + this._anchorSelectionIndex = fromIndex; + this._leadSelectionIndex = toIndex; + + var minIndex = Math.min(fromIndex, toIndex); + var maxIndex = Math.max(fromIndex, toIndex); + + // Crop the affected ranges + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (range.minIndex > maxIndex) { + // We are done + break; + } else if (range.maxIndex >= minIndex) { + // This range is affected + var minIsIn = (range.minIndex >= minIndex) && (range.minIndex <= maxIndex); + var maxIsIn = (range.maxIndex >= minIndex) && (range.maxIndex <= maxIndex); + + if (minIsIn && maxIsIn) { + // This range is removed completely + this._selectedRangeArr.splice(i, 1); + + // Check this index another time + i--; + } else if (minIsIn) { + // The range is cropped from the left + range.minIndex = maxIndex + 1; + } else if (maxIsIn) { + // The range is cropped from the right + range.maxIndex = minIndex - 1; + } else { + // The range is split + var newRange = { minIndex:maxIndex + 1, maxIndex:range.maxIndex } + this._selectedRangeArr.splice(i + 1, 0, newRange); + + range.maxIndex = minIndex - 1; + + // We are done + break; + } + } + } + + //this._dumpRanges(); + + this._fireChangeSelection(); +} + + +/** + * Clears the selection, but doesn't inform the listeners. + */ +qx.Proto._clearSelection = function() { + this._selectedRangeArr = []; + this._anchorSelectionIndex = -1; + this._leadSelectionIndex = -1; +} + + +/** + * Adds a selection interval to the current selection, but doesn't inform + * the listeners. + * + * @param fromIndex {Integer} the first index of the selection (including). + * @param toIndex {Integer} the last index of the selection (including). + */ +qx.Proto._addSelectionInterval = function(fromIndex, toIndex) { + this._anchorSelectionIndex = fromIndex; + this._leadSelectionIndex = toIndex; + + var minIndex = Math.min(fromIndex, toIndex); + var maxIndex = Math.max(fromIndex, toIndex); + + // Find the index where the new range should be inserted + var newRangeIndex = 0; + for (; newRangeIndex < this._selectedRangeArr.length; newRangeIndex++) { + var range = this._selectedRangeArr[newRangeIndex]; + if (range.minIndex > minIndex) { + break; + } + } + + // Add the new range + this._selectedRangeArr.splice(newRangeIndex, 0, { minIndex:minIndex, maxIndex:maxIndex }); + + // Merge overlapping ranges + var lastRange = this._selectedRangeArr[0]; + for (var i = 1; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (lastRange.maxIndex + 1 >= range.minIndex) { + // The ranges are overlapping -> merge them + lastRange.maxIndex = Math.max(lastRange.maxIndex, range.maxIndex); + + // Remove the current range + this._selectedRangeArr.splice(i, 1); + + // Check this index another time + i--; + } else { + lastRange = range; + } + } + + //this._dumpRanges(); +} + + +/** + * Logs the current ranges for debug perposes. + */ +qx.Proto._dumpRanges = function() { + var text = "Ranges:"; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + text += " [" + range.minIndex + ".." + range.maxIndex + "]"; + } + this.debug(text); +} + + +/** + * Fires the "changeSelection" event to all registered listeners. If the selection model + * currently is in batch mode, only one event will be thrown when batch mode is ended. + */ +qx.Proto._fireChangeSelection = function() { + //In batch mode, remember event but do not throw (yet) + if (this.hasBatchMode()){ + this._hadChangeEventInBatchMode = true; + + //If not in batch mode, throw event + } else if (this.hasEventListeners("changeSelection")) { + this.dispatchEvent(new qx.event.type.Event("changeSelection"), true); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js new file mode 100644 index 0000000000..4db88ddb32 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js @@ -0,0 +1,337 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A simple table model that provides an API for changing the model data. + */ +qx.OO.defineClass("qx.ui.table.SimpleTableModel", qx.ui.table.AbstractTableModel, +function() { + qx.ui.table.AbstractTableModel.call(this); + + this._rowArr = []; + this._sortColumnIndex = -1; + this._sortAscending; + + this._editableColArr = null; +}); + + +/** + * <p>See overridden method for details.</p> + * + * @param rowIndex {Integer} the model index of the row. + * @return {Array} Array containing a value for each column. + */ +qx.Proto.getRowData = function(rowIndex) { + return this._rowArr[rowIndex]; +}; + + +/** + * Returns the data of one row as map containing the column IDs as key and the + * cell values as value. + * + * @param rowIndex {Integer} the model index of the row. + * @return {Map} a Map containing the column values. + */ +qx.Proto.getRowDataAsMap = function(rowIndex) { + var columnArr = this._rowArr[rowIndex]; + var map = {}; + for (var col = 0; col < this.getColumnCount(); col++) { + map[this.getColumnId(col)] = columnArr[col]; + } + return map; +}; + + +/** + * Sets all columns editable or not editable. + * + * @param editable {Boolean} whether all columns are editable. + */ +qx.Proto.setEditable = function(editable) { + this._editableColArr = []; + for (var col = 0; col < this.getColumnCount(); col++) { + this._editableColArr[col] = editable; + } + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Sets whether a column is editable. + * + * @param columnIndex {Integer} the column of which to set the editable state. + * @param editable {Boolean} whether the column should be editable. + */ +qx.Proto.setColumnEditable = function(columnIndex, editable) { + if (editable != this.isColumnEditable(columnIndex)) { + if (this._editableColArr == null) { + this._editableColArr = []; + } + this._editableColArr[columnIndex] = editable; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.isColumnEditable = function(columnIndex) { + return this._editableColArr ? (this._editableColArr[columnIndex] == true) : false; +} + + +// overridden +qx.Proto.isColumnSortable = function(columnIndex) { + return true; +} + + +// overridden +qx.Proto.sortByColumn = function(columnIndex, ascending) { + // NOTE: We use different comperators for ascending and descending, + // because comperators should be really fast. + var comperator; + if (ascending) { + comperator = function(row1, row2) { + var obj1 = row1[columnIndex]; + var obj2 = row2[columnIndex]; + return (obj1 > obj2) ? 1 : ((obj1 == obj2) ? 0 : -1); + } + } else { + comperator = function(row1, row2) { + var obj1 = row1[columnIndex]; + var obj2 = row2[columnIndex]; + return (obj1 < obj2) ? 1 : ((obj1 == obj2) ? 0 : -1); + } + } + + this._rowArr.sort(comperator); + + this._sortColumnIndex = columnIndex; + this._sortAscending = ascending; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Clears the sorting. + */ +qx.Proto._clearSorting = function() { + if (this._sortColumnIndex != -1) { + this._sortColumnIndex = -1; + this._sortAscending = true; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.getSortColumnIndex = function() { + return this._sortColumnIndex; +} + + +// overridden +qx.Proto.isSortAscending = function() { + return this._sortAscending; +} + + +// overridden +qx.Proto.getRowCount = function() { + return this._rowArr.length; +} + + +// overridden +qx.Proto.getValue = function(columnIndex, rowIndex) { + if (rowIndex < 0 || rowIndex >= this._rowArr.length) { + throw new Error("this._rowArr out of bounds: " + rowIndex + " (0.." + this._rowArr.length + ")"); + } + + return this._rowArr[rowIndex][columnIndex]; +} + + +// overridden +qx.Proto.setValue = function(columnIndex, rowIndex, value) { + if (this._rowArr[rowIndex][columnIndex] != value) { + this._rowArr[rowIndex][columnIndex] = value; + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:rowIndex, lastRow:rowIndex, + firstColumn:columnIndex, lastColumn:columnIndex } + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + if (columnIndex == this._sortColumnIndex) { + this._clearSorting(); + } + } +} + + +/** + * Sets the whole data in a bulk. + * + * @param rowArr {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto.setData = function(rowArr) { + this._rowArr = rowArr; + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED); + } + + this._clearSorting(); +} + + +/** + * Returns the data of this model. + * <p> + * Warning: Do not alter this array! If you want to change the data use + * {@link #setData}, {@link #setDataAsMapArray} or {@link #setValue} instead. + * + * @return {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto.getData = function() { + return this._rowArr; +}; + + +/** + * Sets the whole data in a bulk. + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + */ +qx.Proto.setDataAsMapArray = function(mapArr) { + this.setData(this._mapArray2RowArr(mapArr)); +}; + + +/** + * Adds some rows to the model. + * <p> + * Warning: The given array will be altered! + * + * @param rowArr {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + * @param startIndex {Integer ? null} The index where to insert the new rows. If null, + * the rows are appended to the end. + */ +qx.Proto.addRows = function(rowArr, startIndex) { + if (startIndex == null) { + startIndex = this._rowArr.length; + } + + // Prepare the rowArr so it can be used for apply + rowArr.splice(0, 0, startIndex, 0); + + // Insert the new rows + Array.prototype.splice.apply(this._rowArr, rowArr); + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:startIndex, lastRow:this._rowArr.length - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + this._clearSorting(); +}; + + +/** + * Adds some rows to the model. + * <p> + * Warning: The given array (mapArr) will be altered! + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + * @param startIndex {Integer ? null} The index where to insert the new rows. If null, + * the rows are appended to the end. + */ +qx.Proto.addRowsAsMapArray = function(mapArr, startIndex) { + this.addRows(this._mapArray2RowArr(mapArr), startIndex); +}; + + +/** + * Removes some rows from the model. + * + * @param startIndex {Integer} the index of the first row to remove. + * @param howMany {Integer} the number of rows to remove. + */ +qx.Proto.removeRows = function(startIndex, howMany) { + this._rowArr.splice(startIndex, howMany); + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:startIndex, lastRow:this._rowArr.length - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + this._clearSorting(); +}; + + +/** + * Creates an array of maps to an array of arrays. + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + * @return {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto._mapArray2RowArr = function(mapArr) { + var rowCount = mapArr.length; + var columnCount = this.getColumnCount(); + var dataArr = new Array(rowCount); + var columnArr; + var j; + for (var i = 0; i < rowCount; ++i) { + columnArr = new Array(columnCount); + for (var j = 0; j < columnCount; ++j) { + columnArr[j] = mapArr[i][this.getColumnId(j)]; + } + dataArr[i] = columnArr; + } + + return dataArr; +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/Table.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/Table.js new file mode 100644 index 0000000000..1fda3f52f2 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/Table.js @@ -0,0 +1,1067 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#require(qx.ui.table.DefaultDataRowRenderer) +#embed(qx.widgettheme/table/selectColumnOrder.png) + +************************************************************************ */ + +/** + * A table. + * + * @param tableModel {qx.ui.table.TableModel, null} The table model to read the + * data from. + */ +qx.OO.defineClass("qx.ui.table.Table", qx.ui.layout.VerticalBoxLayout, +function(tableModel) { + qx.ui.layout.VerticalBoxLayout.call(this); + + // Create the child widgets + this._scrollerParent = new qx.ui.layout.HorizontalBoxLayout; + this._scrollerParent.setDimension("100%", "1*"); + this._scrollerParent.setSpacing(1); + + this._statusBar = new qx.ui.basic.Label; + this._statusBar.setAppearance("table-focus-statusbar"); + this._statusBar.setDimension("100%", "auto"); + + this.add(this._scrollerParent, this._statusBar); + + this._columnVisibilityBt = new qx.ui.toolbar.Button(null, "widget/table/selectColumnOrder.png"); + this._columnVisibilityBt.addEventListener("execute", this._onColumnVisibilityBtExecuted, this); + + // Create the models + this._selectionManager = new qx.ui.table.SelectionManager; + + this.setSelectionModel(new qx.ui.table.SelectionModel); + this.setTableColumnModel(new qx.ui.table.TableColumnModel); + if (tableModel != null) { + this.setTableModel(tableModel); + } + + // create the main meta column + this.setMetaColumnCounts([ -1 ]); + + // Make focusable + this.setTabIndex(1); + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("changeFocused", this._onFocusChanged); + + this._focusedCol = 0; + this._focusedRow = 0; +}); + + +/** The default row renderer to use when {@link #dataRowRenderer} is null. */ +qx.Class.DEFAULT_DATA_ROW_RENDERER = new qx.ui.table.DefaultDataRowRenderer(); + + +/** The selection model. */ +qx.OO.addProperty({ name:"selectionModel", type:"object", instance : "qx.ui.table.SelectionModel" }); + +/** The table model. */ +qx.OO.addProperty({ name:"tableModel", type:"object", instance : "qx.ui.table.TableModel" }); + +/** The table column model. */ +qx.OO.addProperty({ name:"tableColumnModel", type:"object", instance : "qx.ui.table.TableColumnModel" }); + +/** The height of the table rows. */ +qx.OO.addProperty({ name:"rowHeight", type:"number", defaultValue:15 }); + +/** Whether to show the status bar */ +qx.OO.addProperty({ name:"statusBarVisible", type:"boolean", defaultValue:true }); + +/** Whether to show the column visibility button */ +qx.OO.addProperty({ name:"columnVisibilityButtonVisible", type:"boolean", defaultValue:true }); + +/** + * {int[]} The number of columns per meta column. If the last array entry is -1, + * this meta column will get the remaining columns. + */ +qx.OO.addProperty({ name:"metaColumnCounts", type:"object" }); + +/** + * Whether the focus should moved when the mouse is moved over a cell. If false + * the focus is only moved on mouse clicks. + */ +qx.OO.addProperty({ name:"focusCellOnMouseMove", type:"boolean", defaultValue:false }); + +/** + * Whether the table should keep the first visible row complete. If set to false, + * the first row may be rendered partial, depending on the vertical scroll value. + */ +qx.OO.addProperty({ name:"keepFirstVisibleRowComplete", type:"boolean", defaultValue:true }); + +/** + * Whether the table cells should be updated when only the selection or the + * focus changed. This slows down the table update but allows to react on a + * changed selection or a changed focus in a cell renderer. + */ +qx.OO.addProperty({ name:"alwaysUpdateCells", type:"boolean", defaultValue:false }); + +/** The height of the header cells. */ +qx.OO.addProperty({ name:"headerCellHeight", type:"number", defaultValue:16, allowNull:false }); + +/** The renderer to use for styling the rows. */ +qx.OO.addProperty({ name:"dataRowRenderer", type:"object", instance:"qx.ui.table.DataRowRenderer", defaultValue:qx.Class.DEFAULT_DATA_ROW_RENDERER, allowNull:false }); + + +// property modifier +qx.Proto._modifySelectionModel = function(propValue, propOldValue, propData) { + this._selectionManager.setSelectionModel(propValue); + + if (propOldValue != null) { + propOldValue.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + propValue.addEventListener("changeSelection", this._onSelectionChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyTableModel = function(propValue, propOldValue, propData) { + this.getTableColumnModel().init(propValue.getColumnCount()); + + if (propOldValue != null) { + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + + // Update the status bar + this._updateStatusBar(); + + return true; +} + + +// property modifier +qx.Proto._modifyTableColumnModel = function(propValue, propOldValue, propData) { + if (propOldValue != null) { + propOldValue.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propOldValue.removeEventListener("widthChanged", this._onColWidthChanged, this); + propOldValue.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + propValue.addEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propValue.addEventListener("widthChanged", this._onColWidthChanged, this); + propValue.addEventListener("orderChanged", this._onColOrderChanged, this); + + return true; +}; + + +// property modifier +qx.Proto._modifyStatusBarVisible = function(propValue, propOldValue, propData) { + this._statusBar.setDisplay(propValue); + + if (propValue) { + this._updateStatusBar(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyColumnVisibilityButtonVisible = function(propValue, propOldValue, propData) { + this._columnVisibilityBt.setDisplay(propValue); + + return true; +}; + + +// property modifier +qx.Proto._modifyMetaColumnCounts = function(propValue, propOldValue, propData) { + var metaColumnCounts = propValue; + var scrollerArr = this._getPaneScrollerArr(); + + // Remove the panes not needed any more + this._cleanUpMetaColumns(metaColumnCounts.length); + + // Update the old panes + var leftX = 0; + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var paneModel = paneScroller.getTablePaneModel(); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + } + + // Add the new panes + if (metaColumnCounts.length > scrollerArr.length) { + var selectionModel = this.getSelectionModel(); + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + + for (var i = scrollerArr.length; i < metaColumnCounts.length; i++) { + var paneModel = new qx.ui.table.TablePaneModel(columnModel); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + + var paneScroller = new qx.ui.table.TablePaneScroller(this); + paneScroller.setTablePaneModel(paneModel); + + // Register event listener for vertical scrolling + paneScroller.addEventListener("changeScrollY", this._onScrollY, this); + + this._scrollerParent.add(paneScroller); + } + } + + // Update all meta columns + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var isLast = (i == (scrollerArr.length - 1)); + + // Set the right header height + paneScroller.getHeader().setHeight(this.getHeaderCellHeight()); + + // Put the _columnVisibilityBt in the top right corner of the last meta column + paneScroller.setTopRightWidget(isLast ? this._columnVisibilityBt : null); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); + + return true; +} + + +// property modifier +qx.Proto._modifyFocusCellOnMouseMove = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusCellOnMouseMove(propValue); + } + return true; +}; + + +// property modifier +qx.Proto._modifyKeepFirstVisibleRowComplete = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onKeepFirstVisibleRowCompleteChanged(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyHeaderCellHeight = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].getHeader().setHeight(propValue); + } + return true; +}; + + +/** + * Returns the selection manager. + * + * @return {SelectionManager} the selection manager. + */ +qx.Proto._getSelectionManager = function() { + return this._selectionManager; +}; + + +/** + * Returns an array containing all TablePaneScrollers in this table. + * + * @return {TablePaneScroller[]} all TablePaneScrollers in this table. + */ +qx.Proto._getPaneScrollerArr = function() { + return this._scrollerParent.getChildren(); +} + + +/** + * Returns a TablePaneScroller of this table. + * + * @param metaColumn {Integer} the meta column to get the TablePaneScroller for. + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function(metaColumn) { + return this._getPaneScrollerArr()[metaColumn]; +} + + +/** + * Cleans up the meta columns. + * + * @param fromMetaColumn {Integer} the first meta column to clean up. All following + * meta columns will be cleaned up, too. All previous meta columns will + * stay unchanged. If 0 all meta columns will be cleaned up. + */ +qx.Proto._cleanUpMetaColumns = function(fromMetaColumn) { + var scrollerArr = this._getPaneScrollerArr(); + if (scrollerArr != null) { + for (var i = scrollerArr.length - 1; i >= fromMetaColumn; i--) { + var paneScroller = scrollerArr[i]; + paneScroller.removeEventListener("changeScrollY", this._onScrollY, this); + this._scrollerParent.remove(paneScroller); + paneScroller.dispose(); + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onSelectionChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelMetaDataChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelDataChanged(evt); + } + + var rowCount = this.getTableModel().getRowCount(); + if (rowCount != this._lastRowCount) { + this._lastRowCount = rowCount; + + this._updateScrollBarVisibility(); + this._updateStatusBar(); + } +}; + + +/** + * Event handler. Called when a TablePaneScroller has been scrolled vertically. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollY = function(evt) { + if (! this._internalChange) { + this._internalChange = true; + + // Set the same scroll position to all meta columns + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setScrollY(evt.getData()); + } + + this._internalChange = false; + } +} + + +/** + * Event handler. Called when a key was pressed. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeydown = function(evt) { + var identifier = evt.getKeyIdentifier(); + + var consumed = false; + var oldFocusedRow = this._focusedRow; + if (this.isEditing()) { + // Editing mode + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "Enter": + this.stopEditing(); + var oldFocusedRow = this._focusedRow; + this.moveFocusedCell(0, 1); + if (this._focusedRow != oldFocusedRow) { + this.startEditing(); + } + break; + case "Escape": + this.cancelEditing(); + this.focus(); + break; + default: + consumed = false; + break; + } + } + } else { + // No editing mode + + // Handle keys that are independant from the modifiers + consumed = true; + switch (identifier) { + case "Home": + this.setFocusedCell(this._focusedCol, 0, true); + break; + case "End": + var rowCount = this.getTableModel().getRowCount(); + this.setFocusedCell(this._focusedCol, rowCount - 1, true); + break; + default: + consumed = false; + break; + } + + // Handle keys that depend on modifiers + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "F2": + case "Enter": + this.startEditing(); + break; + default: + consumed = false; + break; + } + } else if (evt.isCtrlPressed()) { + consumed = true; + switch (identifier) { + case "A": // Ctrl + A + var rowCount = this.getTableModel().getRowCount(); + if (rowCount > 0) { + this.getSelectionModel().setSelectionInterval(0, rowCount - 1); + } + break; + default: + consumed = false; + break; + } + } + } + + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +qx.Proto._onkeypress = function(evt) +{ + if (this.isEditing()) { return } + // No editing mode + var oldFocusedRow = this._focusedRow; + var consumed = true; + + // Handle keys that are independant from the modifiers + var identifier = evt.getKeyIdentifier(); + switch (identifier) { + case "Space": + this._selectionManager.handleSelectKeyDown(this._focusedRow, evt); + break; + + case "Left": + this.moveFocusedCell(-1, 0); + break; + + case "Right": + this.moveFocusedCell(1, 0); + break; + + case "Up": + this.moveFocusedCell(0, -1); + break; + + case "Down": + this.moveFocusedCell(0, 1); + break; + + case "PageUp": + case "PageDown": + var scroller = this.getPaneScroller(0); + var pane = scroller.getTablePane(); + var rowCount = pane.getVisibleRowCount() - 1; + var rowHeight = this.getRowHeight(); + var direction = (identifier == "PageUp") ? -1 : 1; + scroller.setScrollY(scroller.getScrollY() + direction * rowCount * rowHeight); + this.moveFocusedCell(0, direction * rowCount); + break; + + default: + consumed = false; + } + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +/** + * Event handler. Called when the table gets the focus. + */ +qx.Proto._onFocusChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onFocusChanged(evt); + } +}; + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColVisibilityChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColWidthChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColOrderChanged(evt); + } + + // A column may have been moved between meta columns + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Gets the TablePaneScroller at a certain x position in the page. If there is + * no TablePaneScroller at this postion, null is returned. + * + * @param pageX {Integer} the position in the page to check (in pixels). + * @return {TablePaneScroller} the TablePaneScroller or null. + * + * @see TablePaneScrollerPool + */ +qx.Proto.getTablePaneScrollerAtPageX = function(pageX) { + var metaCol = this._getMetaColumnAtPageX(pageX); + return (metaCol != -1) ? this.getPaneScroller(metaCol) : null; +} + + +/** + * Sets the currently focused cell. + * + * @param col {Integer} the model index of the focused cell's column. + * @param row {Integer} the model index of the focused cell's row. + * @param scrollVisible {Boolean ? false} whether to scroll the new focused cell + * visible. + * + * @see TablePaneScrollerPool + */ +qx.Proto.setFocusedCell = function(col, row, scrollVisible) { + if (!this.isEditing() && (col != this._focusedCol || row != this._focusedRow)) { + this._focusedCol = col; + this._focusedRow = row; + + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusedCell(col, row); + } + + if (scrollVisible) { + this.scrollCellVisible(col, row); + } + } +} + + +/** + * Returns the column of the currently focused cell. + * + * @return {Integer} the model index of the focused cell's column. + */ +qx.Proto.getFocusedColumn = function() { + return this._focusedCol; +}; + + +/** + * Returns the row of the currently focused cell. + * + * @return {Integer} the model index of the focused cell's column. + */ +qx.Proto.getFocusedRow = function() { + return this._focusedRow; +}; + + +/** + * Moves the focus. + * + * @param deltaX {Integer} The delta by which the focus should be moved on the x axis. + * @param deltaY {Integer} The delta by which the focus should be moved on the y axis. + */ +qx.Proto.moveFocusedCell = function(deltaX, deltaY) { + var col = this._focusedCol; + var row = this._focusedRow; + + if (deltaX != 0) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + var colCount = columnModel.getVisibleColumnCount(); + x = qx.lang.Number.limit(x + deltaX, 0, colCount - 1); + col = columnModel.getVisibleColumnAtX(x); + } + + if (deltaY != 0) { + var tableModel = this.getTableModel(); + row = qx.lang.Number.limit(row + deltaY, 0, tableModel.getRowCount() - 1); + } + + this.setFocusedCell(col, row, true); +} + + +/** + * Scrolls a cell visible. + * + * @param col {Integer} the model index of the column the cell belongs to. + * @param row {Integer} the model index of the row the cell belongs to. + */ +qx.Proto.scrollCellVisible = function(col, row) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + + var metaColumn = this._getMetaColumnAtColumnX(x); + if (metaColumn != -1) { + this.getPaneScroller(metaColumn).scrollCellVisible(col, row); + } +} + + +/** + * Returns whether currently a cell is editing. + * + * @return whether currently a cell is editing. + */ +qx.Proto.isEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).isEditing(); + } +} + + +/** + * Starts editing the currently focused cell. Does nothing if already editing + * or if the column is not editable. + * + * @return {Boolean} whether editing was started + */ +qx.Proto.startEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).startEditing(); + } + return false; +} + + +/** + * Stops editing and writes the editor's value to the model. + */ +qx.Proto.stopEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).stopEditing(); + } +} + + +/** + * Stops editing without writing the editor's value to the model. + */ +qx.Proto.cancelEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).cancelEditing(); + } +} + + +/** + * Gets the meta column at a certain x position in the page. If there is no + * meta column at this postion, -1 is returned. + * + * @param pageX {Integer} the position in the page to check (in pixels). + * @return {Integer} the index of the meta column or -1. + */ +qx.Proto._getMetaColumnAtPageX = function(pageX) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var elem = scrollerArr[i].getElement(); + if (pageX >= qx.html.Location.getPageBoxLeft(elem) + && pageX <= qx.html.Location.getPageBoxRight(elem)) + { + return i; + } + } + + return -1; +} + + +/** + * Returns the meta column a column is shown in. If the column is not shown at + * all, -1 is returned. + * + * @param visXPos {Integer} the visible x position of the column. + * @return {Integer} the meta column the column is shown in. + */ +qx.Proto._getMetaColumnAtColumnX = function(visXPos) { + var metaColumnCounts = this.getMetaColumnCounts(); + var rightXPos = 0; + for (var i = 0; i < metaColumnCounts.length; i++) { + var counts = metaColumnCounts[i]; + rightXPos += counts; + + if (counts == -1 || visXPos < rightXPos) { + return i; + } + } + + return -1; +} + + +/** + * Updates the text shown in the status bar. + */ +qx.Proto._updateStatusBar = function() { + if (this.getStatusBarVisible()) { + var selectedRowCount = this.getSelectionModel().getSelectedCount(); + var rowCount = this.getTableModel().getRowCount(); + + var text; + if (selectedRowCount == 0) { + text = rowCount + ((rowCount == 1) ? " row" : " rows"); + } else { + text = selectedRowCount + " of " + rowCount + + ((rowCount == 1) ? " row" : " rows") + " selected"; + } + this._statusBar.setHtml(text); + } +} + + +/** + * Updates the widths of all scrollers. + */ +qx.Proto._updateScrollerWidths = function() { +/* no longer needed, per Til, and removing it does not appear to add problems. + * qx.ui.core.Widget.flushGlobalQueues(); + */ + + // Give all scrollers except for the last one the wanted width + // (The last one has a flex with) + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + var width = isLast ? "1*" : scrollerArr[i].getTablePaneModel().getTotalWidth(); + scrollerArr[i].setWidth(width); + } +} + + +/** + * Updates the visibility of the scrollbars in the meta columns. + */ +qx.Proto._updateScrollBarVisibility = function() { + if (this.isSeeable()) { + var horBar = qx.ui.table.TablePaneScroller.HORIZONTAL_SCROLLBAR; + var verBar = qx.ui.table.TablePaneScroller.VERTICAL_SCROLLBAR; + var scrollerArr = this._getPaneScrollerArr(); + + // Check which scroll bars are needed + var horNeeded = false; + var verNeeded = false; + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + var bars = scrollerArr[i].getNeededScrollBars(horNeeded, !isLast); + + if (bars & horBar) { + horNeeded = true; + } + if (isLast && (bars & verBar)) { + verNeeded = true; + } + } + + // Set the needed scrollbars + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + scrollerArr[i].setHorizontalScrollBarVisible(horNeeded); + scrollerArr[i].setVerticalScrollBarVisible(isLast && verNeeded); + } + } +} + + +/** + * Event handler. Called when the column visibiliy button was executed. + */ +qx.Proto._onColumnVisibilityBtExecuted = function() { + if ((this._columnVisibilityMenuCloseTime == null) + || (new Date().getTime() > this._columnVisibilityMenuCloseTime + 200)) + { + this._toggleColumnVisibilityMenu(); + } +} + + +/** + * Toggels the visibility of the menu used to change the visibility of columns. + */ +qx.Proto._toggleColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu == null || !this._columnVisibilityMenu.isSeeable()) { + // Show the menu + + // Create the new menu + var menu = new qx.ui.menu.Menu; + + menu.addEventListener("disappear", function(evt) { + this._columnVisibilityMenuCloseTime = new Date().getTime(); + }, this); + + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + for (var x = 0; x < columnModel.getOverallColumnCount(); x++) { + var col = columnModel.getOverallColumnAtX(x); + var visible = columnModel.isColumnVisible(col); + var cmd = { col:col } + var bt = new qx.ui.menu.CheckBox(tableModel.getColumnName(col), null, visible); + + var handler = this._createColumnVisibilityCheckBoxHandler(col); + bt._handler = handler; + bt.addEventListener("execute", handler, this); + + menu.add(bt); + } + + menu.setParent(this.getTopLevelWidget()); + + this._columnVisibilityMenu = menu; + + // Show the menu + var btElem = this._columnVisibilityBt.getElement(); + menu.setRestrictToPageOnOpen(false); + menu.setTop(qx.html.Location.getClientBoxBottom(btElem)); + menu.setLeft(-1000); + + // NOTE: We have to show the menu in a timeout, otherwise it won't be shown + // at all. + window.setTimeout(function() { + menu.show(); + qx.ui.core.Widget.flushGlobalQueues(); + + menu.setLeft(qx.html.Location.getClientBoxRight(btElem) - menu.getOffsetWidth()); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + } else { + // hide the menu + menu.hide(); + this._cleanupColumnVisibilityMenu(); + } +} + + +/** + * Cleans up the column visibility menu. + */ +qx.Proto._cleanupColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu != null && ! this._columnVisibilityMenu.getDisposed()) { + this._columnVisibilityMenu.dispose(); + this._columnVisibilityMenu = null; + } +} + + +/** + * Creates a handler for a check box of the column visibility menu. + * + * @param col {Integer} the model index of column to create the handler for. + */ +qx.Proto._createColumnVisibilityCheckBoxHandler = function(col) { + return function(evt) { + var columnModel = this.getTableColumnModel(); + columnModel.setColumnVisible(col, !columnModel.isColumnVisible(col)); + } +} + + +/** + * Sets the width of a column. + * + * @param col {Integer} the model index of column. + * @param width {Integer} the new width in pixels. + */ +qx.Proto.setColumnWidth = function(col, width) { + this.getTableColumnModel().setColumnWidth(col, width); +} + + +// overridden +qx.Proto._changeInnerWidth = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerWidth.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._changeInnerHeight = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerHeight.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.VerticalBoxLayout.prototype._afterAppear.call(this); + + this._updateScrollBarVisibility(); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this._tableModel) { + this._tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + } + + this._columnVisibilityBt.removeEventListener("execute", this._onColumnVisibilityBtExecuted, this); + this._columnVisibilityBt.dispose(); + + this._cleanupColumnVisibilityMenu(); + + this._cleanUpMetaColumns(0); + + var selectionModel = this.getSelectionModel(); + if (selectionModel != null) { + selectionModel.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + + var tableModel = this.getTableModel(); + if (tableModel != null) { + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + + var tableColumnModel = this.getTableColumnModel(); + if (tableColumnModel) { + tableColumnModel.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + tableColumnModel.removeEventListener("widthChanged", this._onColWidthChanged, this); + tableColumnModel.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js new file mode 100644 index 0000000000..9a018d7206 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js @@ -0,0 +1,401 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +// These are needed because of their instantiation at bottom. I don't think this +// is a good idea. (wpbasti) +#require(qx.ui.table.DefaultHeaderCellRenderer) +#require(qx.ui.table.DefaultDataCellRenderer) +#require(qx.ui.table.TextFieldCellEditorFactory) + +************************************************************************ */ + +/** + * A model that contains all meta data about columns, such as width, renderers, + * visibility and order. + * + * @event widthChanged {qx.event.type.DataEvent} Fired when the width of a + * column has changed. The data property of the event is a map having the + * following attributes: + * <ul> + * <li>col: The model index of the column the width of which has changed.</li> + * <li>newWidth: The new width of the column in pixels.</li> + * <li>oldWidth: The old width of the column in pixels.</li> + * </ul> + * @event visibilityChangedPre {qx.event.type.DataEvent} Fired when the + * visibility of a column has changed. This event is equal to + * "visibilityChanged", but is fired right before. + * @event visibilityChanged {qx.event.type.DataEvent} Fired when the + * visibility of a column has changed. The data property of the + * event is a map having the following attributes: + * <ul> + * <li>col: The model index of the column the visibility of which has changed.</li> + * <li>visible: Whether the column is now visible.</li> + * </ul> + * @event orderChanged {qx.event.type.DataEvent} Fired when the column order + * has changed. The data property of the + * event is a map having the following attributes: + * <ul> + * <li>col: The model index of the column that was moved.</li> + * <li>fromOverXPos: The old overall x position of the column.</li> + * <li>toOverXPos: The new overall x position of the column.</li> + * </ul> + * + * @see com.ptvag.webcomponent.ui.table.TableModel + */ +qx.OO.defineClass("qx.ui.table.TableColumnModel", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + +/** + * Initializes the column model. + * + * @param colCount {Integer} the number of columns the model should have. + */ +qx.Proto.init = function(colCount) { + this._columnDataArr = []; + + var width = qx.ui.table.TableColumnModel.DEFAULT_WIDTH; + var headerRenderer = qx.ui.table.TableColumnModel.DEFAULT_HEADER_RENDERER; + var dataRenderer = qx.ui.table.TableColumnModel.DEFAULT_DATA_RENDERER; + var editorFactory = qx.ui.table.TableColumnModel.DEFAULT_EDITOR_FACTORY; + this._overallColumnArr = []; + this._visibleColumnArr = []; + for (var col = 0; col < colCount; col++) { + this._columnDataArr[col] = { width:width, headerRenderer:headerRenderer, + dataRenderer:dataRenderer, editorFactory:editorFactory } + this._overallColumnArr[col] = col; + this._visibleColumnArr[col] = col; + } + + this._colToXPosMap = null; +} + + +/** + * Sets the width of a column. + * + * @param col {Integer} the model index of the column. + * @param width {Integer} the new width the column should get in pixels. + */ +qx.Proto.setColumnWidth = function(col, width) { + var oldWidth = this._columnDataArr[col].width; + if (oldWidth != width) { + this._columnDataArr[col].width = width; + if (this.hasEventListeners("widthChanged")) { + var data = { col:col, newWidth:width, oldWidth:oldWidth } + this.dispatchEvent(new qx.event.type.DataEvent("widthChanged", data), true); + } + } +} + + +/** + * Returns the width of a column. + * + * @param col {Integer} the model index of the column. + * @return {Integer} the width of the column in pixels. + */ +qx.Proto.getColumnWidth = function(col) { + return this._columnDataArr[col].width; +} + + +/** + * Sets the header renderer of a column. + * + * @param col {Integer} the model index of the column. + * @param renderer {HeaderCellRenderer} the new header renderer the column + * should get. + */ +qx.Proto.setHeaderCellRenderer = function(col, renderer) { + this._columnDataArr[col].headerRenderer = renderer; +} + + +/** + * Returns the header renderer of a column. + * + * @param col {Integer} the model index of the column. + * @return {HeaderCellRenderer} the header renderer of the column. + */ +qx.Proto.getHeaderCellRenderer = function(col) { + return this._columnDataArr[col].headerRenderer; +} + + +/** + * Sets the data renderer of a column. + * + * @param col {Integer} the model index of the column. + * @param renderer {DataCellRenderer} the new data renderer the column should get. + */ +qx.Proto.setDataCellRenderer = function(col, renderer) { + this._columnDataArr[col].dataRenderer = renderer; +} + + +/** + * Returns the data renderer of a column. + * + * @param col {Integer} the model index of the column. + * @return {DataCellRenderer} the data renderer of the column. + */ +qx.Proto.getDataCellRenderer = function(col) { + return this._columnDataArr[col].dataRenderer; +} + + +/** + * Sets the cell editor factory of a column. + * + * @param col {Integer} the model index of the column. + * @param factory {CellEditorFactory} the new cell editor factory the column should get. + */ +qx.Proto.setCellEditorFactory = function(col, factory) { + this._columnDataArr[col].editorFactory = factory; +} + + +/** + * Returns the cell editor factory of a column. + * + * @param col {Integer} the model index of the column. + * @return {CellEditorFactory} the cell editor factory of the column. + */ +qx.Proto.getCellEditorFactory = function(col) { + return this._columnDataArr[col].editorFactory; +} + + +/** + * Returns the map that translates model indexes to x positions. + * <p> + * The returned map contains for a model index (int) a map having two + * properties: overX (the overall x position of the column, int) and + * visX (the visible x position of the column, int). visX is missing for + * hidden columns. + * + * @return the "column to x postion" map. + */ +qx.Proto._getColToXPosMap = function() { + if (this._colToXPosMap == null) { + this._colToXPosMap = {}; + for (var overX = 0; overX < this._overallColumnArr.length; overX++) { + var col = this._overallColumnArr[overX]; + this._colToXPosMap[col] = { overX:overX } + } + for (var visX = 0; visX < this._visibleColumnArr.length; visX++) { + var col = this._visibleColumnArr[visX]; + this._colToXPosMap[col].visX = visX; + } + } + return this._colToXPosMap; +} + + +/** + * Returns the number of visible columns. + * + * @return {Integer} the number of visible columns. + */ +qx.Proto.getVisibleColumnCount = function() { + return this._visibleColumnArr.length; +} + + +/** + * Returns the model index of a column at a certain visible x position. + * + * @param visXPos {Integer} the visible x position of the column. + * @return {Integer} the model index of the column. + */ +qx.Proto.getVisibleColumnAtX = function(visXPos) { + return this._visibleColumnArr[visXPos]; +} + + +/** + * Returns the visible x position of a column. + * + * @param col {Integer} the model index of the column. + * @return {Integer} the visible x position of the column. + */ +qx.Proto.getVisibleX = function(col) { + return this._getColToXPosMap()[col].visX; +} + + +/** + * Returns the overall number of columns (including hidden columns). + * + * @return {Integer} the overall number of columns. + */ +qx.Proto.getOverallColumnCount = function() { + return this._overallColumnArr.length; +} + + +/** + * Returns the model index of a column at a certain overall x position. + * + * @param overXPos {Integer} the overall x position of the column. + * @return {Integer} the model index of the column. + */ +qx.Proto.getOverallColumnAtX = function(overXPos) { + return this._overallColumnArr[overXPos]; +} + + +/** + * Returns the overall x position of a column. + * + * @param col {Integer} the model index of the column. + * @return {Integer} the overall x position of the column. + */ +qx.Proto.getOverallX = function(col) { + return this._getColToXPosMap()[col].overX; +} + + +/** + * Returns whether a certain column is visible. + * + * @param col {Integer} the model index of the column. + * @return {Boolean} whether the column is visible. + */ +qx.Proto.isColumnVisible = function(col) { + return (this._getColToXPosMap()[col].visX != null); +} + + +/** + * Sets whether a certain column is visible. + * + * @param col {Integer} the model index of the column. + * @param visible {Boolean} whether the column should be visible. + */ +qx.Proto.setColumnVisible = function(col, visible) { + if (visible != this.isColumnVisible(col)) { + if (visible) { + var colToXPosMap = this._getColToXPosMap(); + + var overX = colToXPosMap[col].overX; + if (overX == null) { + throw new Error("Showing column failed: " + col + + ". The column is not added to this TablePaneModel."); + } + + // get the visX of the next visible column after the column to show + var nextVisX; + for (var x = overX + 1; x < this._overallColumnArr.length; x++) { + var currCol = this._overallColumnArr[x]; + var currVisX = colToXPosMap[currCol].visX; + if (currVisX != null) { + nextVisX = currVisX; + break; + } + } + + // If there comes no visible column any more, then show the column + // at the end + if (nextVisX == null) { + nextVisX = this._visibleColumnArr.length; + } + + // Add the column to the visible columns + this._visibleColumnArr.splice(nextVisX, 0, col); + } else { + var visX = this.getVisibleX(col); + this._visibleColumnArr.splice(visX, 1); + } + + // Invalidate the _colToXPosMap + this._colToXPosMap = null; + + // Inform the listeners + if (! this._internalChange) { + if (this.hasEventListeners("visibilityChangedPre")) { + var data = { col:col, visible:visible } + this.dispatchEvent(new qx.event.type.DataEvent("visibilityChangedPre", data), true); + } + if (this.hasEventListeners("visibilityChanged")) { + var data = { col:col, visible:visible } + this.dispatchEvent(new qx.event.type.DataEvent("visibilityChanged", data), true); + } + } + + //this.debug("setColumnVisible col:"+col+",visible:"+visible+",this._overallColumnArr:"+this._overallColumnArr+",this._visibleColumnArr:"+this._visibleColumnArr); + } +} + + +/** + * Moves a column. + * + * @param fromOverXPos {Integer} the overall x postion of the column to move. + * @param toOverXPos {Integer} the overall x postion of where the column should be + * moved to. + */ +qx.Proto.moveColumn = function(fromOverXPos, toOverXPos) { + this._internalChange = true; + + var col = this._overallColumnArr[fromOverXPos]; + var visible = this.isColumnVisible(col); + + if (visible) { + this.setColumnVisible(col, false); + } + + this._overallColumnArr.splice(fromOverXPos, 1); + this._overallColumnArr.splice(toOverXPos, 0, col); + + // Invalidate the _colToXPosMap + this._colToXPosMap = null; + + if (visible) { + this.setColumnVisible(col, true); + } + + this._internalChange = false; + + // Inform the listeners + if (this.hasEventListeners("orderChanged")) { + var data = { col:col, fromOverXPos:fromOverXPos, toOverXPos:toOverXPos } + this.dispatchEvent(new qx.event.type.DataEvent("orderChanged", data), true); + } +} + + +/** {int} the default width of a column in pixels. */ +qx.Class.DEFAULT_WIDTH = 100; + +/** {DefaultDataCellRenderer} the default header cell renderer. */ +qx.Class.DEFAULT_HEADER_RENDERER = new qx.ui.table.DefaultHeaderCellRenderer; + +/** {DefaultDataCellRenderer} the default data cell renderer. */ +qx.Class.DEFAULT_DATA_RENDERER = new qx.ui.table.DefaultDataCellRenderer; + +/** {TextFieldCellEditorFactory} the default editor factory. */ +qx.Class.DEFAULT_EDITOR_FACTORY = new qx.ui.table.TextFieldCellEditorFactory; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js new file mode 100644 index 0000000000..643aac3c4f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js @@ -0,0 +1,245 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The data model of a table. + * + * @event dataChanged {qx.event.type.DataEvent} Fired when the table data changed + * (the stuff shown in the table body). The data property of the event + * may be null or a map having the following attributes: + * <ul> + * <li>firstRow: The index of the first row that has changed.</li> + * <li>lastRow: The index of the last row that has changed.</li> + * <li>firstColumn: The model index of the first column that has changed.</li> + * <li>lastColumn: The model index of the last column that has changed.</li> + * </ul> + * @event metaDataChanged {qx.event.type.Event} Fired when the meta data changed + * (the stuff shown in the table header). + */ +qx.OO.defineClass("qx.ui.table.TableModel", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + +/** + * Returns the number of rows in the model. + * + * @return {Integer} the number of rows. + */ +qx.Proto.getRowCount = function() { + throw new Error("getRowCount is abstract"); +} + + +/** + * <p>Returns the data of one row. This function may be overriden by models which hold + * all data of a row in one object. By using this function, clients have a way of + * quickly retrieving the entire row data.</p> + * + * <p><b>Important:</b>Models which do not have their row data accessible in one object + * may return null.</p> + * + * @param rowIndex {Integer} the model index of the row. + * @return {Object} the row data as an object or null if the model does not support row data + * objects. The details on the object returned are determined by the model + * implementation only. + */ +qx.Proto.getRowData = function(rowIndex) { + return null; +} + + +/** + * Returns the number of columns in the model. + * + * @return {Integer} the number of columns. + */ +qx.Proto.getColumnCount = function() { + throw new Error("getColumnCount is abstract"); +} + + +/** + * Returns the ID of column. The ID may be used to identify columns + * independent from their index in the model. E.g. for being aware of added + * columns when saving the width of a column. + * + * @param columnIndex {Integer} the index of the column. + * @return {String} the ID of the column. + */ +qx.Proto.getColumnId = function(columnIndex) { + throw new Error("getColumnId is abstract"); +} + + +/** + * Returns the index of a column. + * + * @param columnId {String} the ID of the column. + * @return {Integer} the index of the column. + */ +qx.Proto.getColumnIndexById = function(columnId) { + throw new Error("getColumnIndexById is abstract"); +} + + +/** + * Returns the name of a column. This name will be shown to the user in the + * table header. + * + * @param columnIndex {Integer} the index of the column. + * @return {String} the name of the column. + */ +qx.Proto.getColumnName = function(columnIndex) { + throw new Error("getColumnName is abstract"); +} + + +/** + * Returns whether a column is editable. + * + * @param columnIndex {Integer} the column to check. + * @return {Boolean} whether the column is editable. + */ +qx.Proto.isColumnEditable = function(columnIndex) { + return false; +} + + +/** + * Returns whether a column is sortable. + * + * @param columnIndex {Integer} the column to check. + * @return {Boolean} whether the column is sortable. + */ +qx.Proto.isColumnSortable = function(columnIndex) { + return false; +} + + +/** + * Sorts the model by a column. + * + * @param columnIndex {Integer} the column to sort by. + * @param ascending {Boolean} whether to sort ascending. + */ +qx.Proto.sortByColumn = function(columnIndex, ascending) { +} + + +/** + * Returns the column index the model is sorted by. If the model is not sorted + * -1 is returned. + * + * @return {Integer} the column index the model is sorted by. + */ +qx.Proto.getSortColumnIndex = function() { + return -1; +} + + +/** + * Returns whether the model is sorted ascending. + * + * @return {Boolean} whether the model is sorted ascending. + */ +qx.Proto.isSortAscending = function() { + return true; +} + + +/** + * Prefetches some rows. This is a hint to the model that the specified rows + * will be read soon. + * + * @param firstRowIndex {Integer} the index of first row. + * @param lastRowIndex {Integer} the index of last row. + */ +qx.Proto.prefetchRows = function(firstRowIndex, lastRowIndex) { +} + + +/** + * Returns a cell value by column index. + * + * @param columnIndex {Integer} the index of the column. + * @param rowIndex {Integer} the index of the row. + * @return {var} The value of the cell. + * @see #getValueById{} + */ +qx.Proto.getValue = function(columnIndex, rowIndex) { + throw new Error("getValue is abstract"); +} + + +/** + * Returns a cell value by column ID. + * <p> + * Whenever you have the choice, use {@link #getValue()} instead, + * because this should be faster. + * + * @param columnId {String} the ID of the column. + * @param rowIndex {Integer} the index of the row. + * @return {var} the value of the cell. + */ +qx.Proto.getValueById = function(columnId, rowIndex) { + return this.getValue(this.getColumnIndexById(columnId), rowIndex); +} + + +/** + * Sets a cell value by column index. + * + * @param columnIndex {Integer} The index of the column. + * @param rowIndex {Integer} the index of the row. + * @param value {var} The new value. + * @see #setValueById{} + */ +qx.Proto.setValue = function(columnIndex, rowIndex, value) { + throw new Error("setValue is abstract"); +} + + +/** + * Sets a cell value by column ID. + * <p> + * Whenever you have the choice, use {@link #setValue()} instead, + * because this should be faster. + * + * @param columnId {String} The ID of the column. + * @param rowIndex {Integer} The index of the row. + * @param value {var} The new value. + */ +qx.Proto.setValueById = function(columnId, rowIndex, value) { + return this.setValue(this.getColumnIndexById(columnId), rowIndex, value); +} + + +/** {string} The type of the event fired when the data changed. */ +qx.Class.EVENT_TYPE_DATA_CHANGED = "dataChanged"; + +/** {string} The type of the event fired when the meta data changed. */ +qx.Class.EVENT_TYPE_META_DATA_CHANGED = "metaDataChanged"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js new file mode 100644 index 0000000000..ffb4d9e4cf --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js @@ -0,0 +1,511 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The table pane that shows a certain section from a table. This class handles + * the display of the data part of a table and is therefore the base for virtual + * scrolling. + * + * @param paneScroller {TablePaneScroller} the TablePaneScroller the header belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePane", qx.ui.basic.Terminator, +function(paneScroller) { + qx.ui.basic.Terminator.call(this); + + this._paneScroller = paneScroller; + + // this.debug("USE_ARRAY_JOIN:" + qx.ui.table.TablePane.USE_ARRAY_JOIN + ", USE_TABLE:" + qx.ui.table.TablePane.USE_TABLE); + + this._lastColCount = 0; + this._lastRowCount = 0; +}); + +/** The index of the first row to show. */ +qx.OO.addProperty({ name:"firstVisibleRow", type:"number", defaultValue:0 }); + +/** The number of rows to show. */ +qx.OO.addProperty({ name:"visibleRowCount", type:"number", defaultValue:0 }); + + +// property modifier +qx.Proto._modifyFirstVisibleRow = function(propValue, propOldValue, propData) { + this._updateContent(); + return true; +} + + +// property modifier +qx.Proto._modifyVisibleRowCount = function(propValue, propOldValue, propData) { + this._updateContent(); + return true; +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + if (this._updateWantedWhileInvisible) { + // We are visible now and an update was wanted while we were invisible + // -> Do the update now + this._updateContent(); + this._updateWantedWhileInvisible = false; + } +}; + + +/** + * Returns the TablePaneScroller this pane belongs to. + * + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function() { + return this._paneScroller; +}; + + +/** + * Returns the table this pane belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._paneScroller.getTable(); +}; + + +/** + * Sets the currently focused cell. + * + * @param col {Integer} the model index of the focused cell's column. + * @param row {Integer} the model index of the focused cell's row. + * @param massUpdate {Boolean ? false} Whether other updates are planned as well. + * If true, no repaint will be done. + */ +qx.Proto.setFocusedCell = function(col, row, massUpdate) { + if (col != this._focusedCol || row != this._focusedRow) { + var oldCol = this._focusedCol; + var oldRow = this._focusedRow; + this._focusedCol = col; + this._focusedRow = row; + + // Update the focused row background + if (row != oldRow && !massUpdate) { + // NOTE: Only the old and the new row need update + this._updateContent(false, oldRow, true); + this._updateContent(false, row, true); + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + this._updateContent(false, null, true); +} + + +/** + * Event handler. Called when the table gets or looses the focus. + * + * @param evt {Map} the event. + */ +qx.Proto._onFocusChanged = function(evt) { + this._updateContent(false, null, true); +}; + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the table model data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + var data = evt.getData ? evt.getData() : null; + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + if (data == null || data.lastRow == -1 + || data.lastRow >= firstRow && data.firstRow < firstRow + rowCount) + { + // The change intersects this pane + this._updateContent(); + } +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._updateContent(); +} + + +/** + * Updates the content of the pane. + * + * @param completeUpdate {Boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {Integer ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {Boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto._updateContent = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + if (! this.isSeeable()) { + this._updateWantedWhileInvisible = true; + return; + } + + if (qx.ui.table.TablePane.USE_ARRAY_JOIN) { + this._updateContent_array_join(completeUpdate, onlyRow, onlySelectionOrFocusChanged); + } else { + this._updateContent_orig(completeUpdate, onlyRow, onlySelectionOrFocusChanged); + } +} + + +/** + * Updates the content of the pane (implemented using array joins). + * + * @param completeUpdate {Boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {Integer ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {Boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto._updateContent_array_join = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + var TablePane = qx.ui.table.TablePane; + + var table = this.getTable(); + + var selectionModel = table.getSelectionModel(); + var tableModel = table.getTableModel(); + var columnModel = table.getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + var rowRenderer = table.getDataRowRenderer(); + + var colCount = paneModel.getColumnCount(); + var rowHeight = table.getRowHeight(); + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + var modelRowCount = tableModel.getRowCount(); + if (firstRow + rowCount > modelRowCount) { + rowCount = Math.max(0, modelRowCount - firstRow); + } + + var cellInfo = { table:table }; + cellInfo.styleHeight = rowHeight; + + var htmlArr = []; + var rowWidth = paneModel.getTotalWidth(); + + if (TablePane.USE_TABLE) { + // The table test + htmlArr.push('<table cellspacing\="0" cellpadding\="0" style\="table-layout:fixed;font-family:'); + htmlArr.push(qx.ui.table.TablePane.CONTENT_ROW_FONT_FAMILY_TEST); + htmlArr.push(';font-size:'); + htmlArr.push(qx.ui.table.TablePane.CONTENT_ROW_FONT_SIZE_TEST); + htmlArr.push(';width:'); + htmlArr.push(rowWidth); + htmlArr.push('px"><colgroup>'); + + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + + htmlArr.push('<col width="'); + htmlArr.push(columnModel.getColumnWidth(col)); + htmlArr.push('"/>'); + } + + htmlArr.push('</colgroup><tbody>'); + } + + tableModel.prefetchRows(firstRow, firstRow + rowCount - 1); + for (var y = 0; y < rowCount; y++) { + var row = firstRow + y; + + cellInfo.row = row; + cellInfo.selected = selectionModel.isSelectedIndex(row); + cellInfo.focusedRow = (this._focusedRow == row); + cellInfo.rowData = tableModel.getRowData(row); + + // Update this row + if (TablePane.USE_TABLE) { + htmlArr.push('<tr style\="height:'); + htmlArr.push(rowHeight); + } else { + htmlArr.push('<div style\="position:absolute;left:0px;top:'); + htmlArr.push(y * rowHeight); + htmlArr.push('px;width:'); + htmlArr.push(rowWidth); + htmlArr.push('px;height:'); + htmlArr.push(rowHeight); + htmlArr.push('px'); + } + + rowRenderer._createRowStyle_array_join(cellInfo, htmlArr); + + htmlArr.push('">'); + + var left = 0; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.focusedCol = (this._focusedCol == col); + cellInfo.value = tableModel.getValue(col, row); + var cellWidth = columnModel.getColumnWidth(col); + + cellInfo.styleLeft = left; + cellInfo.styleWidth = cellWidth; + + var cellRenderer = columnModel.getDataCellRenderer(col); + cellRenderer.createDataCellHtml_array_join(cellInfo, htmlArr); + + left += cellWidth; + } + + if (TablePane.USE_TABLE) { + htmlArr.push('</tr>'); + } else { + htmlArr.push('</div>'); + } + } + + if (TablePane.USE_TABLE) { + htmlArr.push('</tbody></table>'); + } + + var elem = this.getElement(); + // this.debug(">>>" + htmlArr.join("") + "<<<") + elem.innerHTML = htmlArr.join(""); + + this.setHeight(rowCount * rowHeight); + + this._lastColCount = colCount; + this._lastRowCount = rowCount; +} + + +/** + * Updates the content of the pane (old implementation). + * + * @param completeUpdate {Boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {Integer ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {Boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto._updateContent_orig = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + var TablePane = qx.ui.table.TablePane; + + var table = this.getTable(); + + var alwaysUpdateCells = table.getAlwaysUpdateCells(); + + var selectionModel = table.getSelectionModel(); + var tableModel = table.getTableModel(); + var columnModel = table.getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + var rowRenderer = table.getDataRowRenderer(); + + var colCount = paneModel.getColumnCount(); + var rowHeight = table.getRowHeight(); + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + var modelRowCount = tableModel.getRowCount(); + if (firstRow + rowCount > modelRowCount) { + rowCount = Math.max(0, modelRowCount - firstRow); + } + + // Remove the rows that are not needed any more + if (completeUpdate || this._lastRowCount > rowCount) { + var firstRowToRemove = completeUpdate ? 0 : rowCount; + this._cleanUpRows(firstRowToRemove); + } + + if (TablePane.USE_TABLE) { + throw new Error("Combination of USE_TABLE==true and USE_ARRAY_JOIN==false is not yet implemented"); + } + + var elem = this.getElement(); + var childNodes = elem.childNodes; + var cellInfo = { table:table }; + tableModel.prefetchRows(firstRow, firstRow + rowCount - 1); + for (var y = 0; y < rowCount; y++) { + var row = firstRow + y; + if ((onlyRow != null) && (row != onlyRow)) { + continue; + } + + cellInfo.row = row; + cellInfo.selected = selectionModel.isSelectedIndex(row); + cellInfo.focusedRow = (this._focusedRow == row); + cellInfo.rowData = tableModel.getRowData(row); + + // Update this row + var rowElem; + var recyleRowElem; + if (y < childNodes.length) { + rowElem = childNodes[y]; + recyleRowElem = true + } else { + var rowElem = document.createElement("div"); + + //rowElem.style.position = "relative"; + rowElem.style.position = "absolute"; + rowElem.style.left = "0px"; + rowElem.style.top = (y * rowHeight) + "px"; + + rowElem.style.height = rowHeight + "px"; + elem.appendChild(rowElem); + recyleRowElem = false; + } + + rowRenderer.updateDataRowElement(cellInfo, rowElem); + + if (alwaysUpdateCells || !recyleRowElem || !onlySelectionOrFocusChanged) { + var html = ""; + var left = 0; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.focusedCol = (this._focusedCol == col); + cellInfo.value = tableModel.getValue(col, row); + var width = columnModel.getColumnWidth(col); + cellInfo.style = 'position:absolute;left:' + left + + 'px;top:0px;width:' + width + + 'px; height:' + rowHeight + "px"; + + var cellRenderer = columnModel.getDataCellRenderer(col); + if (recyleRowElem) { + var cellElem = rowElem.childNodes[x]; + cellRenderer.updateDataCellElement(cellInfo, cellElem); + } else { + html += cellRenderer.createDataCellHtml(cellInfo); + } + + left += width; + } + if (! recyleRowElem) { + rowElem.style.width = left + "px"; + rowElem.innerHTML = html; + } + } + } + + this.setHeight(rowCount * rowHeight); + + this._lastColCount = colCount; + this._lastRowCount = rowCount; +} + + +/** + * Cleans up the row widgets. + * + * @param firstRowToRemove {Integer} the visible index of the first row to clean up. + * All following rows will be cleaned up, too. + */ +qx.Proto._cleanUpRows = function(firstRowToRemove) { + var elem = this.getElement(); + if (elem) { + var childNodes = this.getElement().childNodes; + var paneModel = this.getPaneScroller().getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + for (var y = childNodes.length - 1; y >= firstRowToRemove; y--) { + elem.removeChild(childNodes[y]); + } + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + this._cleanUpRows(0); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} + + +qx.Class.USE_ARRAY_JOIN = false; +qx.Class.USE_TABLE = false; + + +qx.Class.CONTENT_ROW_FONT_FAMILY_TEST = "'Segoe UI', Corbel, Calibri, Tahoma, 'Lucida Sans Unicode', sans-serif"; +qx.Class.CONTENT_ROW_FONT_SIZE_TEST = "11px"; + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js new file mode 100644 index 0000000000..6b7ffff6d6 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js @@ -0,0 +1,277 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * Shows the header of a table. + * + * @param paneScroller {TablePaneScroller} the TablePaneScroller the header belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePaneHeader", qx.ui.layout.HorizontalBoxLayout, +function(paneScroller) { + qx.ui.layout.HorizontalBoxLayout.call(this); + + this._paneScroller = paneScroller; +}); + + +/** + * Returns the TablePaneScroller this header belongs to. + * + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function() { + return this._paneScroller; +}; + + +/** + * Returns the table this header belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._paneScroller.getTable(); +}; + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + var data = evt.getData(); + this.setColumnWidth(data.col, data.newWidth); +} + + +/** + * Event handler. Called the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._updateContent(); +} + + +/** + * Sets the column width. This overrides the width from the column model. + * + * @param col {Integer} the column to change the width for. + * @param width {Integer} the new width. + */ +qx.Proto.setColumnWidth = function(col, width) { + var x = this.getPaneScroller().getTablePaneModel().getX(col); + var children = this.getChildren(); + if (children[x] != null) { + children[x].setWidth(width); + } +} + + +/** + * Sets the column the mouse is currently over. + * + * @param col {Integer} the model index of the column the mouse is currently over or + * null if the mouse is over no column. + */ +qx.Proto.setMouseOverColumn = function(col) { + if (col != this._lastMouseOverColumn) { + var paneModel = this.getPaneScroller().getTablePaneModel(); + var children = this.getChildren(); + + if (this._lastMouseOverColumn != null) { + var widget = children[paneModel.getX(this._lastMouseOverColumn)]; + if (widget != null) { + widget.removeState("mouseover"); + } + } + if (col != null) { + children[paneModel.getX(col)].addState("mouseover"); + } + + this._lastMouseOverColumn = col; + } +} + + +/** + * Shows the feedback shown while a column is moved by the user. + * + * @param col {Integer} the model index of the column to show the move feedback for. + * @param x {Integer} the x position the left side of the feeback should have + * (in pixels, relative to the left side of the header). + */ +qx.Proto.showColumnMoveFeedback = function(col, x) { + var elem = this.getElement(); + if (this._moveFeedback == null) { + var xPos = this.getPaneScroller().getTablePaneModel().getX(col); + var cellWidget = this.getChildren()[xPos]; + + // Create the feedback + // Workaround: Since a cloned widget throws an exception when it is + // added to another component we have to create a new one + // using the renderer + //this._moveFeedback = cellWidget.clone(); + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + var cellInfo = { xPos:xPos, col:col, name:tableModel.getColumnName(col) } + var cellRenderer = columnModel.getHeaderCellRenderer(col); + + var feedback = cellRenderer.createHeaderCell(cellInfo); + // Configure the feedback + feedback.setWidth(cellWidget.getBoxWidth()); + feedback.setHeight(cellWidget.getBoxHeight()); + feedback.setZIndex(1000000); + feedback.setOpacity(0.8); + feedback.setTop(qx.html.Location.getClientBoxTop(elem)); + this.getTopLevelWidget().add(feedback); + this._moveFeedback = feedback; + } + + this._moveFeedback.setLeft(qx.html.Location.getClientBoxLeft(elem) + x); +} + + +/** + * Hides the feedback shown while a column is moved by the user. + */ +qx.Proto.hideColumnMoveFeedback = function() { + if (this._moveFeedback != null) { + this.getTopLevelWidget().remove(this._moveFeedback); + this._moveFeedback.dispose(); + this._moveFeedback = null; + } +} + + +/** + * Returns whether the column move feedback is currently shown. + */ +qx.Proto.isShowingColumnMoveFeedback = function() { + return this._moveFeedback != null; +} + + +/** + * Updates the content of the header. + * + * @param completeUpdate {Boolean} if true a complete update is performed. On a + * complete update all header widgets are recreated. + */ +qx.Proto._updateContent = function(completeUpdate) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + + var children = this.getChildren(); + var oldColCount = children.length; + var colCount = paneModel.getColumnCount(); + + var sortedColum = tableModel.getSortColumnIndex(); + + // Remove all widgets on the complete update + if (completeUpdate) { + this._cleanUpCells(); + } + + // Update the header + var cellInfo = {}; + cellInfo.sortedAscending = tableModel.isSortAscending(); + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + + var colWidth = columnModel.getColumnWidth(col); + + // TODO: Get real cell renderer + var cellRenderer = columnModel.getHeaderCellRenderer(col); + + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.name = tableModel.getColumnName(col); + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.sorted = (col == sortedColum); + + // Get the cached widget + var cachedWidget = children[x]; + + // Create or update the widget + if (cachedWidget == null) { + // We have no cached widget -> create it + cachedWidget = cellRenderer.createHeaderCell(cellInfo); + cachedWidget.set({ width:colWidth, height:"100%" }); + + this.add(cachedWidget); + } else { + // This widget already created before -> recycle it + cellRenderer.updateHeaderCell(cellInfo, cachedWidget); + } + } +} + + +/** + * Cleans up all header cells. + */ +qx.Proto._cleanUpCells = function() { + var children = this.getChildren(); + for (var x = children.length - 1; x >= 0; x--) { + var cellWidget = children[x]; + //this.debug("disposed:" + cellWidget.getDisposed() + ",has parent: " + (cellWidget.getParent() != null) + ",x:"+x); + this.remove(cellWidget); + cellWidget.dispose(); + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js new file mode 100644 index 0000000000..7e77757f9f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js @@ -0,0 +1,181 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The model of a table pane. This model works as proxy to a + * {@link TableColumnModel} and manages the visual order of the columns shown in + * a {@link TablePane}. + * + * @param tableColumnModel {TableColumnModel} The TableColumnModel of which this + * model is the proxy. + * + * @event modelChanged {qx.event.type.Event} Fired when the model changed. + */ +qx.OO.defineClass("qx.ui.table.TablePaneModel", qx.core.Target, +function(tableColumnModel) { + qx.core.Target.call(this); + + tableColumnModel.addEventListener("visibilityChangedPre", this._onColVisibilityChanged, this); + + this._tableColumnModel = tableColumnModel; +}); + + +/** The visible x position of the first column this model should contain. */ +qx.OO.addProperty({ name : "firstColumnX", type : "number", defaultValue : 0 }); + +/** + * The maximum number of columns this model should contain. If -1 this model will + * contain all remaining columns. + */ +qx.OO.addProperty({ name : "maxColumnCount", type : "number", defaultValue : -1 }); + + +// property modifier +qx.Proto._modifyFirstColumnX = function(propValue, propOldValue, propData) { + this._columnCount = null; + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); + return true; +} + + +// property modifier +qx.Proto._modifyMaxColumnCount = function(propValue, propOldValue, propData) { + this._columnCount = null; + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); + return true; +} + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + this._columnCount = null; + + // TODO: Check whether the column is in this model (This is a little bit + // tricky, because the column could _have been_ in this model, but is + // not in it after the change) + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); +} + + +/** + * Returns the number of columns in this model. + * + * @return {Integer} the number of columns in this model. + */ +qx.Proto.getColumnCount = function() { + if (this._columnCount == null) { + var firstX = this.getFirstColumnX(); + var maxColCount = this.getMaxColumnCount(); + var totalColCount = this._tableColumnModel.getVisibleColumnCount(); + + if (maxColCount == -1 || (firstX + maxColCount) > totalColCount) { + this._columnCount = totalColCount - firstX; + } else { + this._columnCount = maxColCount; + } + } + return this._columnCount; +} + + +/** + * Returns the model index of the column at the position <code>xPos</code>. + * + * @param xPos {Integer} the x postion in the table pane of the column. + * @return {Integer} the model index of the column. + */ +qx.Proto.getColumnAtX = function(xPos) { + var firstX = this.getFirstColumnX(); + return this._tableColumnModel.getVisibleColumnAtX(firstX + xPos); +} + + +/** + * Returns the x position of the column <code>col</code>. + * + * @param col {Integer} the model index of the column. + * @return {Integer} the x postion in the table pane of the column. + */ +qx.Proto.getX = function(col) { + var firstX = this.getFirstColumnX(); + var maxColCount = this.getMaxColumnCount(); + + var x = this._tableColumnModel.getVisibleX(col) - firstX; + if (x >= 0 && (maxColCount == -1 || x < maxColCount)) { + return x; + } else { + return -1; + } +} + + +/** + * Gets the position of the left side of a column (in pixels, relative to the + * left side of the table pane). + * <p> + * This value corresponds to the sum of the widths of all columns left of the + * column. + * + * @param col {Integer} the model index of the column. + * @return the position of the left side of the column. + */ +qx.Proto.getColumnLeft = function(col) { + var left = 0; + var colCount = this.getColumnCount(); + for (var x = 0; x < colCount; x++) { + var currCol = this.getColumnAtX(x); + if (currCol == col) { + return left; + } + + left += this._tableColumnModel.getColumnWidth(currCol); + } + return -1; +} + + +/** + * Returns the total width of all columns in the model. + * + * @return {Integer} the total width of all columns in the model. + */ +qx.Proto.getTotalWidth = function() { + var totalWidth = 0; + var colCount = this.getColumnCount(); + for (var x = 0; x < colCount; x++) { + var col = this.getColumnAtX(x); + totalWidth += this._tableColumnModel.getColumnWidth(col); + } + return totalWidth; +} + + +/** {string} The type of the event fired when the model changed. */ +qx.Class.EVENT_TYPE_MODEL_CHANGED = "modelChanged"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js new file mode 100644 index 0000000000..8629be1fc0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js @@ -0,0 +1,1346 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * Shows a whole meta column. This includes a {@link TablePaneHeader}, + * a {@link TablePane} and the needed scroll bars. This class handles the + * virtual scrolling and does all the mouse event handling. + * + * @param table {Table} the table the scroller belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePaneScroller", qx.ui.layout.VerticalBoxLayout, +function(table) { + qx.ui.layout.VerticalBoxLayout.call(this); + + this._table = table; + + // init scrollbars + this._verScrollBar = new qx.ui.core.ScrollBar(false); + this._horScrollBar = new qx.ui.core.ScrollBar(true); + + var scrollBarWidth = this._verScrollBar.getPreferredBoxWidth(); + + this._verScrollBar.setWidth("auto"); + this._horScrollBar.setHeight("auto"); + this._horScrollBar.setPaddingRight(scrollBarWidth); + //this._verScrollBar.setMergeEvents(true); + + this._horScrollBar.addEventListener("changeValue", this._onScrollX, this); + this._verScrollBar.addEventListener("changeValue", this._onScrollY, this); + + // init header + this._header = new qx.ui.table.TablePaneHeader(this); + this._header.set({ width:"auto", height:"auto" }); + + this._headerClipper = new qx.ui.layout.CanvasLayout; + this._headerClipper.setDimension("1*", "auto"); + this._headerClipper.setOverflow("hidden"); + this._headerClipper.add(this._header); + + this._spacer = new qx.ui.basic.Terminator; + this._spacer.setWidth(scrollBarWidth); + + this._top = new qx.ui.layout.HorizontalBoxLayout; + this._top.setHeight("auto"); + this._top.add(this._headerClipper, this._spacer); + + // init pane + this._tablePane = new qx.ui.table.TablePane(this); + this._tablePane.set({ width:"auto", height:"auto" }); + + this._focusIndicator = new qx.ui.layout.HorizontalBoxLayout; + this._focusIndicator.setAppearance("table-focus-indicator"); + this._focusIndicator.hide(); + + // Workaround: If the _focusIndicator has no content if always gets a too + // high hight in IE. + var dummyContent = new qx.ui.basic.Terminator; + dummyContent.setWidth(0); + this._focusIndicator.add(dummyContent); + + this._paneClipper = new qx.ui.layout.CanvasLayout; + this._paneClipper.setWidth("1*"); + this._paneClipper.setOverflow("hidden"); + this._paneClipper.add(this._tablePane, this._focusIndicator); + this._paneClipper.addEventListener("mousewheel", this._onmousewheel, this); + + // add all child widgets + var scrollerBody = new qx.ui.layout.HorizontalBoxLayout; + scrollerBody.setHeight("1*"); + scrollerBody.add(this._paneClipper, this._verScrollBar); + + this.add(this._top, scrollerBody, this._horScrollBar); + + // init event handlers + this.addEventListener("mousemove", this._onmousemove, this); + this.addEventListener("mousedown", this._onmousedown, this); + this.addEventListener("mouseup", this._onmouseup, this); + this.addEventListener("click", this._onclick, this); + this.addEventListener("dblclick", this._ondblclick, this); + this.addEventListener("mouseout", this._onmouseout, this); +}); + +/** Whether to show the horizontal scroll bar */ +qx.OO.addProperty({ name:"horizontalScrollBarVisible", type:"boolean", defaultValue:true }); + +/** Whether to show the vertical scroll bar */ +qx.OO.addProperty({ name:"verticalScrollBarVisible", type:"boolean", defaultValue:true }); + +/** The table pane model. */ +qx.OO.addProperty({ name:"tablePaneModel", type:"object", instance:"qx.ui.table.TablePaneModel" }); + +/** The current position of the the horizontal scroll bar. */ +qx.OO.addProperty({ name:"scrollX", type:"number", allowNull:false, defaultValue:0 }); + +/** The current position of the the vertical scroll bar. */ +qx.OO.addProperty({ name:"scrollY", type:"number", allowNull:false, defaultValue:0 }); + +/** + * Whether column resize should be live. If false, during resize only a line is + * shown and the real resize happens when the user releases the mouse button. + */ +qx.OO.addProperty({ name:"liveResize", type:"boolean", defaultValue:false }); + +/** + * Whether the focus should moved when the mouse is moved over a cell. If false + * the focus is only moved on mouse clicks. + */ +qx.OO.addProperty({ name:"focusCellOnMouseMove", type:"boolean", defaultValue:false }); + +/** + * Whether to handle selections via the selection manager before setting the + * focus. The traditional behavior is to handle selections after setting the + * focus, but setting the focus means redrawing portions of the table, and + * some subclasses may want to modify the data to be displayed based on the + * selection. + */ +qx.OO.addProperty({ name:"selectBeforeFocus", type:"boolean", defaultValue:false }); + + +// property modifier +qx.Proto._modifyHorizontalScrollBarVisible = function(propValue, propOldValue, propData) { + // Workaround: We can't use setDisplay, because the scroll bar needs its + // correct height in order to check its value. When using + // setDisplay(false) the height isn't relayouted any more + if (propValue) { + this._horScrollBar.setHeight("auto"); + } else { + this._horScrollBar.setHeight(0); + } + this._horScrollBar.setVisibility(propValue); + + // NOTE: We have to flush the queues before updating the content so the new + // layout has been applied and _updateContent is able to work with + // correct values. + qx.ui.core.Widget.flushGlobalQueues(); + this._updateContent(); + + return true; +} + + +// property modifier +qx.Proto._modifyVerticalScrollBarVisible = function(propValue, propOldValue, propData) { + // Workaround: See _modifyHorizontalScrollBarVisible + if (propValue) { + this._verScrollBar.setWidth("auto"); + } else { + this._verScrollBar.setWidth(0); + } + this._verScrollBar.setVisibility(propValue); + + var scrollBarWidth = propValue ? this._verScrollBar.getPreferredBoxWidth() : 0; + this._horScrollBar.setPaddingRight(scrollBarWidth); + this._spacer.setWidth(scrollBarWidth); + + return true; +} + + +// property modifier +qx.Proto._modifyTablePaneModel = function(propValue, propOldValue, propData) { + if (propOldValue != null) { + propOldValue.removeEventListener("modelChanged", this._onPaneModelChanged, this); + } + propValue.addEventListener("modelChanged", this._onPaneModelChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyScrollX = function(propValue, propOldValue, propData) { + this._horScrollBar.setValue(propValue); + return true; +} + + +// property modifier +qx.Proto._modifyScrollY = function(propValue, propOldValue, propData) { + this._verScrollBar.setValue(propValue); + return true; +} + + +/** + * Returns the table this scroller belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._table; +}; + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + this._updateHorScrollBarMaximum(); + this._updateFocusIndicator(); +} + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + this._header._onColWidthChanged(evt); + this._tablePane._onColWidthChanged(evt); + + var data = evt.getData(); + var paneModel = this.getTablePaneModel(); + var x = paneModel.getX(data.col); + if (x != -1) { + // The change was in this scroller + this._updateHorScrollBarMaximum(); + this._updateFocusIndicator(); + } +} + + +/** + * Event handler. Called when the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._header._onColOrderChanged(evt); + this._tablePane._onColOrderChanged(evt); + + this._updateHorScrollBarMaximum(); +} + + +/** + * Event handler. Called when the table model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + this._tablePane._onTableModelDataChanged(evt); + + var rowCount = this.getTable().getTableModel().getRowCount(); + if (rowCount != this._lastRowCount) { + this._lastRowCount = rowCount; + + this._updateVerScrollBarMaximum(); + if (this.getFocusedRow() >= rowCount) { + if (rowCount == 0) { + this.setFocusedCell(null, null); + } else { + this.setFocusedCell(this.getFocusedColumn(), rowCount - 1); + } + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + this._tablePane._onSelectionChanged(evt); +}; + + +/** + * Event handler. Called when the table gets or looses the focus. + * + * @param evt {Map} the event. + */ +qx.Proto._onFocusChanged = function(evt) { + this._focusIndicator.setState("tableHasFocus", this.getTable().getFocused()); + + this._tablePane._onFocusChanged(evt); +}; + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._header._onTableModelMetaDataChanged(evt); + this._tablePane._onTableModelMetaDataChanged(evt); +}; + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._header._onPaneModelChanged(evt); + this._tablePane._onPaneModelChanged(evt); +}; + + +/** + * Updates the maximum of the horizontal scroll bar, so it corresponds to the + * total width of the columns in the table pane. + */ +qx.Proto._updateHorScrollBarMaximum = function() { + this._horScrollBar.setMaximum(this.getTablePaneModel().getTotalWidth()); +} + + +/** + * Updates the maximum of the vertical scroll bar, so it corresponds to the + * number of rows in the table. + */ +qx.Proto._updateVerScrollBarMaximum = function() { + var rowCount = this.getTable().getTableModel().getRowCount(); + var rowHeight = this.getTable().getRowHeight(); + + if (this.getTable().getKeepFirstVisibleRowComplete()) { + this._verScrollBar.setMaximum((rowCount + 1) * rowHeight); + } else { + this._verScrollBar.setMaximum(rowCount * rowHeight); + } +} + + +/** + * Event handler. Called when the table property "keepFirstVisibleRowComplete" + * changed. + */ +qx.Proto._onKeepFirstVisibleRowCompleteChanged = function() { + this._updateVerScrollBarMaximum(); + this._updateContent(); +}; + + +// overridden +qx.Proto._changeInnerHeight = function(newValue, oldValue) { + // The height has changed -> Update content + this._postponedUpdateContent(); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerHeight.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.VerticalBoxLayout.prototype._afterAppear.call(this); + + var self = this; + this.getElement().onselectstart = qx.lang.Function.returnFalse; + + this._updateContent(); + this._header._updateContent(); + this._updateHorScrollBarMaximum(); + this._updateVerScrollBarMaximum(); +} + + +/** + * Event handler. Called when the horizontal scroll bar moved. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollX = function(evt) { + // Workaround: See _updateContent + this._header.setLeft(-evt.getData()); + + this._paneClipper.setScrollLeft(evt.getData()); + this.setScrollX(evt.getData()); +} + + +/** + * Event handler. Called when the vertical scroll bar moved. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollY = function(evt) { + this._postponedUpdateContent(); + this.setScrollY(evt.getData()); +} + + +/** + * Event handler. Called when the user moved the mouse wheel. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousewheel = function(evt) { + this._verScrollBar.setValue(this._verScrollBar.getValue() + - evt.getWheelDelta() * this.getTable().getRowHeight()); + + // Update the focus + if (this._lastMousePageX && this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(this._lastMousePageX, this._lastMousePageY); + } +} + + +/** + * Event handler. Called when the user moved the mouse. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousemove = function(evt) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + + var useResizeCursor = false; + var mouseOverColumn = null; + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + + // Workaround: In onmousewheel the event has wrong coordinates for pageX + // and pageY. So we remember the last move event. + this._lastMousePageX = pageX; + this._lastMousePageY = pageY; + + if (this._resizeColumn != null) { + // We are currently resizing -> Update the position + var minColumnWidth = qx.ui.table.TablePaneScroller.MIN_COLUMN_WIDTH; + var newWidth = Math.max(minColumnWidth, this._lastResizeWidth + pageX - this._lastResizeMousePageX); + + if (this.getLiveResize()) { + columnModel.setColumnWidth(this._resizeColumn, newWidth); + } else { + this._header.setColumnWidth(this._resizeColumn, newWidth); + + var paneModel = this.getTablePaneModel(); + this._showResizeLine(paneModel.getColumnLeft(this._resizeColumn) + newWidth); + } + + useResizeCursor = true; + this._lastResizeMousePageX += newWidth - this._lastResizeWidth; + this._lastResizeWidth = newWidth; + } else if (this._moveColumn != null) { + // We are moving a column + + // Check whether we moved outside the click tolerance so we can start + // showing the column move feedback + // (showing the column move feedback prevents the onclick event) + var clickTolerance = qx.ui.table.TablePaneScroller.CLICK_TOLERANCE; + if (this._header.isShowingColumnMoveFeedback() + || pageX > this._lastMoveMousePageX + clickTolerance + || pageX < this._lastMoveMousePageX - clickTolerance) + { + this._lastMoveColPos += pageX - this._lastMoveMousePageX; + + this._header.showColumnMoveFeedback(this._moveColumn, this._lastMoveColPos); + + // Get the responsible scroller + var targetScroller = this._table.getTablePaneScrollerAtPageX(pageX); + if (this._lastMoveTargetScroller && this._lastMoveTargetScroller != targetScroller) { + this._lastMoveTargetScroller.hideColumnMoveFeedback(); + } + if (targetScroller != null) { + this._lastMoveTargetX = targetScroller.showColumnMoveFeedback(pageX); + } else { + this._lastMoveTargetX = null; + } + + this._lastMoveTargetScroller = targetScroller; + this._lastMoveMousePageX = pageX; + } + } else { + // This is a normal mouse move + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // The mouse is over the header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol != -1) { + // The mouse is over a resize region -> Show the right cursor + useResizeCursor = true; + } else { + var col = this._getColumnForPageX(pageX); + if (col != null && tableModel.isColumnSortable(col)) { + mouseOverColumn = col; + } + } + } else if (row != null) { + // The mouse is over the data -> update the focus + if (this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(pageX, pageY); + } + } + } + + // Workaround: Setting the cursor to the right widget doesn't work + //this._header.setCursor(useResizeCursor ? "e-resize" : null); + this.getTopLevelWidget().setGlobalCursor(useResizeCursor ? qx.ui.table.TablePaneScroller.CURSOR_RESIZE_HORIZONTAL : null); + + this._header.setMouseOverColumn(mouseOverColumn); +} + + +/** + * Event handler. Called when the user pressed a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousedown = function(evt) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // mouse is in header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol != -1) { + // The mouse is over a resize region -> Start resizing + this._resizeColumn = resizeCol; + this._lastResizeMousePageX = pageX; + this._lastResizeWidth = columnModel.getColumnWidth(this._resizeColumn); + this.setCapture(true); + } else { + // The mouse is not in a resize region + var col = this._getColumnForPageX(pageX); + if (col != null) { + // Prepare column moving + this._moveColumn = col; + this._lastMoveMousePageX = pageX; + this._lastMoveColPos = this.getTablePaneModel().getColumnLeft(col); + this.setCapture(true); + } + } + } else if (row != null) { + var selectBeforeFocus = this.getSelectBeforeFocus(); + + if (selectBeforeFocus) { + this.getTable()._getSelectionManager().handleMouseDown(row, evt); + } + + // The mouse is over the data -> update the focus + if (! this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(pageX, pageY); + } + + if (! selectBeforeFocus) { + this.getTable()._getSelectionManager().handleMouseDown(row, evt); + } + } +} + + +/** + * Event handler. Called when the user released a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onmouseup = function(evt) { + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + + if (this._resizeColumn != null) { + // We are currently resizing -> Finish resizing + if (! this.getLiveResize()) { + this._hideResizeLine(); + columnModel.setColumnWidth(this._resizeColumn, this._lastResizeWidth); + } + + this._resizeColumn = null; + this.setCapture(false); + + this.getTopLevelWidget().setGlobalCursor(null); + } else if (this._moveColumn != null) { + // We are moving a column -> Drop the column + this._header.hideColumnMoveFeedback(); + if (this._lastMoveTargetScroller) { + this._lastMoveTargetScroller.hideColumnMoveFeedback(); + } + + if (this._lastMoveTargetX != null) { + var fromVisXPos = paneModel.getFirstColumnX() + paneModel.getX(this._moveColumn); + var toVisXPos = this._lastMoveTargetX; + if (toVisXPos != fromVisXPos && toVisXPos != fromVisXPos + 1) { + // The column was really moved to another position + // (and not moved before or after itself, which is a noop) + + // Translate visible positions to overall positions + var fromCol = columnModel.getVisibleColumnAtX(fromVisXPos); + var toCol = columnModel.getVisibleColumnAtX(toVisXPos); + var fromOverXPos = columnModel.getOverallX(fromCol); + var toOverXPos = (toCol != null) ? columnModel.getOverallX(toCol) : columnModel.getOverallColumnCount(); + + if (toOverXPos > fromOverXPos) { + // Don't count the column itself + toOverXPos--; + } + + // Move the column + columnModel.moveColumn(fromOverXPos, toOverXPos); + } + } + + this._moveColumn = null; + this._lastMoveTargetX = null; + this.setCapture(false); + } else { + // This is a normal mouse up + var row = this._getRowForPagePos(evt.getPageX(), evt.getPageY()); + if (row != -1 && row != null) { + this.getTable()._getSelectionManager().handleMouseUp(row, evt); + } + } +} + + +/** + * Event handler. Called when the user clicked a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onclick = function(evt) { + var tableModel = this.getTable().getTableModel(); + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // mouse is in header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol == -1) { + // mouse is not in a resize region + var col = this._getColumnForPageX(pageX); + if (col != null && tableModel.isColumnSortable(col)) { + // Sort that column + var sortCol = tableModel.getSortColumnIndex(); + var ascending = (col != sortCol) ? true : !tableModel.isSortAscending(); + + tableModel.sortByColumn(col, ascending); + this.getTable().getSelectionModel().clearSelection(); + } + } + } else if (row != null) { + this.getTable()._getSelectionManager().handleClick(row, evt); + } +} + + +/** + * Event handler. Called when the user double clicked a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._ondblclick = function(evt) { + if (! this.isEditing()) { + this._focusCellAtPagePos(evt.getPageX(), evt.getPageY()); + this.startEditing(); + } +} + + +/** + * Event handler. Called when the mouse moved out. + * + * @param evt {Map} the event. + */ +qx.Proto._onmouseout = function(evt) { + /* + // Workaround: See _onmousemove + this._lastMousePageX = null; + this._lastMousePageY = null; + */ + + // Reset the resize cursor when the mouse leaves the header + // If currently a column is resized then do nothing + // (the cursor will be reset on mouseup) + if (this._resizeColumn == null) { + this.getTopLevelWidget().setGlobalCursor(null); + } + + this._header.setMouseOverColumn(null); +} + + +/** + * Shows the resize line. + * + * @param x {Integer} the position where to show the line (in pixels, relative to + * the left side of the pane). + */ +qx.Proto._showResizeLine = function(x) { + var resizeLine = this._resizeLine; + if (resizeLine == null) { + resizeLine = new qx.ui.basic.Terminator; + resizeLine.setBackgroundColor("#D6D5D9"); + resizeLine.setWidth(3); + this._paneClipper.add(resizeLine); + qx.ui.core.Widget.flushGlobalQueues(); + + this._resizeLine = resizeLine; + } + + resizeLine._applyRuntimeLeft(x - 2); // -1 for the width + resizeLine._applyRuntimeHeight(this._paneClipper.getBoxHeight() + this._paneClipper.getScrollTop()); + + this._resizeLine.removeStyleProperty("visibility"); +} + + +/** + * Hides the resize line. + */ +qx.Proto._hideResizeLine = function() { + this._resizeLine.setStyleProperty("visibility", "hidden"); +} + + +/** + * Shows the feedback shown while a column is moved by the user. + * + * @param pageX {Integer} the x position of the mouse in the page (in pixels). + * @return {Integer} the visible x position of the column in the whole table. + */ +qx.Proto.showColumnMoveFeedback = function(pageX) { + var paneModel = this.getTablePaneModel(); + var columnModel = this.getTable().getTableColumnModel(); + var paneLeftX = qx.html.Location.getClientBoxLeft(this._tablePane.getElement()); + var colCount = paneModel.getColumnCount(); + + var targetXPos = 0; + var targetX = 0; + var currX = paneLeftX; + for (var xPos = 0; xPos < colCount; xPos++) { + var col = paneModel.getColumnAtX(xPos); + var colWidth = columnModel.getColumnWidth(col); + + if (pageX < currX + colWidth / 2) { + break; + } + + currX += colWidth; + targetXPos = xPos + 1; + targetX = currX - paneLeftX; + } + + // Ensure targetX is visible + var clipperLeftX = qx.html.Location.getClientBoxLeft(this._paneClipper.getElement()); + var clipperWidth = this._paneClipper.getBoxWidth(); + var scrollX = clipperLeftX - paneLeftX; + // NOTE: +2/-1 because of feedback width + targetX = qx.lang.Number.limit(targetX, scrollX + 2, scrollX + clipperWidth - 1); + + this._showResizeLine(targetX); + + // Return the overall target x position + return paneModel.getFirstColumnX() + targetXPos; +} + + +/** + * Hides the feedback shown while a column is moved by the user. + */ +qx.Proto.hideColumnMoveFeedback = function() { + this._hideResizeLine(); +} + + +/** + * Sets the focus to the cell that's located at the page position + * <code>pageX</code>/<code>pageY</code>. If there is no cell at that position, + * nothing happens. + * + * @param pageX {Integer} the x position in the page (in pixels). + * @param pageY {Integer} the y position in the page (in pixels). + */ +qx.Proto._focusCellAtPagePos = function(pageX, pageY) { + var row = this._getRowForPagePos(pageX, pageY); + if (row != -1 && row != null) { + // The mouse is over the data -> update the focus + var col = this._getColumnForPageX(pageX); + if (col != null) { + this._table.setFocusedCell(col, row); + } + } +} + + +/** + * Sets the currently focused cell. + * + * @param col {Integer} the model index of the focused cell's column. + * @param row {Integer} the model index of the focused cell's row. + */ +qx.Proto.setFocusedCell = function(col, row) { + if (!this.isEditing()) { + this._tablePane.setFocusedCell(col, row, this._updateContentPlanned); + + this._focusedCol = col; + this._focusedRow = row; + + // Move the focus indicator + if (! this._updateContentPlanned) { + this._updateFocusIndicator(); + } + } +} + + +/** + * Returns the column of currently focused cell. + * + * @return {Integer} the model index of the focused cell's column. + */ +qx.Proto.getFocusedColumn = function() { + return this._focusedCol; +}; + + +/** + * Returns the row of currently focused cell. + * + * @return {Integer} the model index of the focused cell's column. + */ +qx.Proto.getFocusedRow = function() { + return this._focusedRow; +}; + + +/** + * Scrolls a cell visible. + * + * @param col {Integer} the model index of the column the cell belongs to. + * @param row {Integer} the model index of the row the cell belongs to. + */ +qx.Proto.scrollCellVisible = function(col, row) { + var paneModel = this.getTablePaneModel(); + var xPos = paneModel.getX(col); + + if (xPos != -1) { + var columnModel = this.getTable().getTableColumnModel(); + + var colLeft = paneModel.getColumnLeft(col); + var colWidth = columnModel.getColumnWidth(col); + var rowHeight = this.getTable().getRowHeight(); + var rowTop = row * rowHeight; + + var scrollX = this.getScrollX(); + var scrollY = this.getScrollY(); + var viewWidth = this._paneClipper.getBoxWidth(); + var viewHeight = this._paneClipper.getBoxHeight(); + + // NOTE: We don't use qx.lang.Number.limit, because min should win if max < min + var minScrollX = Math.min(colLeft, colLeft + colWidth - viewWidth); + var maxScrollX = colLeft; + this.setScrollX(Math.max(minScrollX, Math.min(maxScrollX, scrollX))); + + var minScrollY = rowTop + rowHeight - viewHeight; + if (this.getTable().getKeepFirstVisibleRowComplete()) { + minScrollY += rowHeight - 1; + } + var maxScrollY = rowTop; + this.setScrollY(Math.max(minScrollY, Math.min(maxScrollY, scrollY))); + } +} + + +/** + * Returns whether currently a cell is editing. + * + * @return whether currently a cell is editing. + */ +qx.Proto.isEditing = function() { + return this._cellEditor != null; +} + + +/** + * Starts editing the currently focused cell. Does nothing if already editing + * or if the column is not editable. + * + * @return {Boolean} whether editing was started + */ +qx.Proto.startEditing = function() { + var tableModel = this.getTable().getTableModel(); + var col = this._focusedCol; + + if (!this.isEditing() && (col != null) && tableModel.isColumnEditable(col)) { + var row = this._focusedRow; + var xPos = this.getTablePaneModel().getX(col); + var value = tableModel.getValue(col, row); + + this._cellEditorFactory = this.getTable().getTableColumnModel().getCellEditorFactory(col); + var cellInfo = { col:col, row:row, xPos:xPos, value:value } + this._cellEditor = this._cellEditorFactory.createCellEditor(cellInfo); + this._cellEditor.set({ width:"100%", height:"100%" }); + + this._focusIndicator.add(this._cellEditor); + this._focusIndicator.addState("editing"); + + this._cellEditor.addEventListener("changeFocused", this._onCellEditorFocusChanged, this); + + // Workaround: Calling focus() directly has no effect + var editor = this._cellEditor; + window.setTimeout(function() { + editor.focus(); + }, 0); + + return true; + } + + return false; +} + + +/** + * Stops editing and writes the editor's value to the model. + */ +qx.Proto.stopEditing = function() { + this.flushEditor(); + this.cancelEditing(); +} + + +/** + * Writes the editor's value to the model. + */ +qx.Proto.flushEditor = function() { + if (this.isEditing()) { + var value = this._cellEditorFactory.getCellEditorValue(this._cellEditor); + this.getTable().getTableModel().setValue(this._focusedCol, this._focusedRow, value); + + this._table.focus(); + } +} + + +/** + * Stops editing without writing the editor's value to the model. + */ +qx.Proto.cancelEditing = function() { + if (this.isEditing()) { + this._focusIndicator.remove(this._cellEditor); + this._focusIndicator.removeState("editing"); + this._cellEditor.dispose(); + + this._cellEditor.removeEventListener("changeFocused", this._onCellEditorFocusChanged, this); + this._cellEditor = null; + this._cellEditorFactory = null; + } +} + + +/** + * Event handler. Called when the focused state of the cell editor changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onCellEditorFocusChanged = function(evt) { + if (!this._cellEditor.getFocused()) { + this.stopEditing(); + } +} + + +/** + * Returns the model index of the column the mouse is over or null if the mouse + * is not over a column. + * + * @param pageX {Integer} the x position of the mouse in the page (in pixels). + * @return {Integer} the model index of the column the mouse is over. + */ +qx.Proto._getColumnForPageX = function(pageX) { + var headerLeftX = qx.html.Location.getClientBoxLeft(this._header.getElement()); + + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + var currX = headerLeftX; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + var colWidth = columnModel.getColumnWidth(col); + currX += colWidth; + + if (pageX < currX) { + return col; + } + } + + return null; +} + + +/** + * Returns the model index of the column that should be resized when dragging + * starts here. Returns -1 if the mouse is in no resize region of any column. + * + * @param pageX {Integer} the x position of the mouse in the page (in pixels). + * @return {Integer} the column index. + */ +qx.Proto._getResizeColumnForPageX = function(pageX) { + var headerLeftX = qx.html.Location.getClientBoxLeft(this._header.getElement()); + + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + var currX = headerLeftX; + var regionRadius = qx.ui.table.TablePaneScroller.RESIZE_REGION_RADIUS; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + var colWidth = columnModel.getColumnWidth(col); + currX += colWidth; + + if (pageX >= (currX - regionRadius) && pageX <= (currX + regionRadius)) { + return col; + } + } + + return -1; +} + + +/** + * Returns the model index of the row the mouse is currently over. Returns -1 if + * the mouse is over the header. Returns null if the mouse is not over any + * column. + * + * @param pageX {Integer} the mouse x position in the page. + * @param pageY {Integer} the mouse y position in the page. + * @return {Integer} the model index of the row the mouse is currently over. + */ +qx.Proto._getRowForPagePos = function(pageX, pageY) { + var paneClipperElem = this._paneClipper.getElement(); + var paneClipperLeftX = qx.html.Location.getClientBoxLeft(paneClipperElem); + var paneClipperRightX = qx.html.Location.getClientBoxRight(paneClipperElem); + if (pageX < paneClipperLeftX || pageX > paneClipperRightX) { + // There was no cell or header cell hit + return null; + } + + var paneClipperTopY = qx.html.Location.getClientBoxTop(paneClipperElem); + var paneClipperBottomY = qx.html.Location.getClientBoxBottom(paneClipperElem); + if (pageY >= paneClipperTopY && pageY <= paneClipperBottomY) { + // This event is in the pane -> Get the row + var rowHeight = this.getTable().getRowHeight(); + + var scrollY = this._verScrollBar.getValue(); + if (this.getTable().getKeepFirstVisibleRowComplete()) { + scrollY = Math.floor(scrollY / rowHeight) * rowHeight; + } + + var tableY = scrollY + pageY - paneClipperTopY; + var row = Math.floor(tableY / rowHeight); + + var rowCount = this.getTable().getTableModel().getRowCount(); + return (row < rowCount) ? row : null; + } + + var headerElem = this._headerClipper.getElement(); + if (pageY >= qx.html.Location.getClientBoxTop(headerElem) + && pageY <= qx.html.Location.getClientBoxBottom(headerElem) + && pageX <= qx.html.Location.getClientBoxRight(headerElem)) + { + // This event is in the pane -> Return -1 for the header + return -1; + } + + return null; +} + + +/** + * Sets the widget that should be shown in the top right corner. + * <p> + * The widget will not be disposed, when this table scroller is disposed. So the + * caller has to dispose it. + * + * @param widget {qx.ui.core.Widget} The widget to set. May be null. + */ +qx.Proto.setTopRightWidget = function(widget) { + var oldWidget = this._topRightWidget; + if (oldWidget != null) { + this._top.remove(oldWidget); + } + + if (widget != null) { + this._top.remove(this._spacer); + this._top.add(widget); + } else if (oldWidget != null) { + this._top.add(this._spacer); + } + + this._topRightWidget = widget; +} + + +/** + * Returns the header. + * + * @return {TablePaneHeader} the header. + */ +qx.Proto.getHeader = function() { + return this._header; +} + + +/** + * Returns the table pane. + * + * @return {TablePane} the table pane. + */ +qx.Proto.getTablePane = function() { + return this._tablePane; +} + + +/** + * Returns which scrollbars are needed. + * + * @param forceHorizontal {Boolean ? false} Whether to show the horizontal + * scrollbar always. + * @param preventVertical {Boolean ? false} Whether tp show the vertical scrollbar + * never. + * @return {Integer} which scrollbars are needed. This may be any combination of + * {@link #HORIZONTAL_SCROLLBAR} or {@link #VERTICAL_SCROLLBAR} + * (combined by OR). + */ +qx.Proto.getNeededScrollBars = function(forceHorizontal, preventVertical) { + var barWidth = this._verScrollBar.getPreferredBoxWidth(); + + // Get the width and height of the view (without scroll bars) + var viewWidth = this._paneClipper.getInnerWidth(); + if (this.getVerticalScrollBarVisible()) { + viewWidth += barWidth; + } + var viewHeight = this._paneClipper.getInnerHeight(); + if (this.getHorizontalScrollBarVisible()) { + viewHeight += barWidth; + } + + // Get the (virtual) width and height of the pane + var paneWidth = this.getTablePaneModel().getTotalWidth(); + var paneHeight = this.getTable().getRowHeight() * this.getTable().getTableModel().getRowCount(); + + // Check which scrollbars are needed + var horNeeded = false; + var verNeeded = false; + if (paneWidth > viewWidth) { + horNeeded = true; + if (paneHeight > viewHeight - barWidth) { + verNeeded = true; + } + } else if (paneHeight > viewHeight) { + verNeeded = true; + if (!preventVertical && (paneWidth > viewWidth - barWidth)) { + horNeeded = true; + } + } + + // Create the mask + var horBar = qx.ui.table.TablePaneScroller.HORIZONTAL_SCROLLBAR; + var verBar = qx.ui.table.TablePaneScroller.VERTICAL_SCROLLBAR; + return ((forceHorizontal || horNeeded) ? horBar : 0) + | ((preventVertical || !verNeeded) ? 0 : verBar); +} + + +/** + * Does a postponed update of the content. + * + * @see #_updateContent + */ +qx.Proto._postponedUpdateContent = function() { + if (! this._updateContentPlanned) { + var self = this; + window.setTimeout(function() { + self._updateContent(); + self._updateContentPlanned = false; + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + this._updateContentPlanned = true; + } +} + + +/** + * Updates the content. Sets the right section the table pane should show and + * does the scrolling. + */ +qx.Proto._updateContent = function() { + var paneHeight = this._paneClipper.getInnerHeight(); + var scrollX = this._horScrollBar.getValue(); + var scrollY = this._verScrollBar.getValue(); + var rowHeight = this.getTable().getRowHeight(); + + var firstRow = Math.floor(scrollY / rowHeight); + var oldFirstRow = this._tablePane.getFirstVisibleRow(); + this._tablePane.setFirstVisibleRow(firstRow); + + var rowCount = Math.ceil(paneHeight / rowHeight); + var paneOffset = 0; + if (! this.getTable().getKeepFirstVisibleRowComplete()) { + // NOTE: We don't consider paneOffset, because this may cause alternating + // adding and deleting of one row when scolling. Instead we add one row + // in every case. + rowCount++; + paneOffset = scrollY % rowHeight; + } + this._tablePane.setVisibleRowCount(rowCount); + + if (firstRow != oldFirstRow) { + this._updateFocusIndicator(); + } + + // Workaround: We can't use scrollLeft for the header because IE + // automatically scrolls the header back, when a column is + // resized. + this._header.setLeft(-scrollX); + this._paneClipper.setScrollLeft(scrollX); + this._paneClipper.setScrollTop(paneOffset); + + //this.debug("paneHeight:"+paneHeight+",rowHeight:"+rowHeight+",firstRow:"+firstRow+",rowCount:"+rowCount+",paneOffset:"+paneOffset); +} + + +/** + * Updates the location and the visibility of the focus indicator. + */ +qx.Proto._updateFocusIndicator = function() { + if (this._focusedCol == null) { + this._focusIndicator.hide(); + } else { + var xPos = this.getTablePaneModel().getX(this._focusedCol); + if (xPos == -1) { + this._focusIndicator.hide(); + } else { + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + + var firstRow = this._tablePane.getFirstVisibleRow(); + var rowHeight = this.getTable().getRowHeight(); + + this._focusIndicator.setHeight(rowHeight + 3); + this._focusIndicator.setWidth(columnModel.getColumnWidth(this._focusedCol) + 3); + this._focusIndicator.setTop((this._focusedRow - firstRow) * rowHeight - 2); + this._focusIndicator.setLeft(paneModel.getColumnLeft(this._focusedCol) - 2); + + this._focusIndicator.show(); + } + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this.getElement() != null) { + this.getElement().onselectstart = null; + } + + this._verScrollBar.dispose(); + this._horScrollBar.dispose(); + this._header.dispose(); + this._headerClipper.dispose(); + this._spacer.dispose(); + this._top.dispose(); + this._tablePane.dispose(); + this._paneClipper.dispose(); + + if (this._resizeLine != null) { + this._resizeLine.dispose(); + } + + this.removeEventListener("mousemove", this._onmousemove, this); + this.removeEventListener("mousedown", this._onmousedown, this); + this.removeEventListener("mouseup", this._onmouseup, this); + this.removeEventListener("click", this._onclick, this); + this.removeEventListener("dblclick", this._ondblclick, this); + this.removeEventListener("mouseout", this._onmouseout, this); + + var tablePaneModel = this.getTablePaneModel(); + if (tablePaneModel != null) { + tablePaneModel.removeEventListener("modelChanged", this._onPaneModelChanged, this); + } + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} + + +/** {int} The minimum width a colum could get in pixels. */ +qx.Class.MIN_COLUMN_WIDTH = 10; + +/** {int} The radius of the resize region in pixels. */ +qx.Class.RESIZE_REGION_RADIUS = 5; + +/** + * (int) The number of pixels the mouse may move between mouse down and mouse up + * in order to count as a click. + */ +qx.Class.CLICK_TOLERANCE = 5; + +/** + * (int) The mask for the horizontal scroll bar. + * May be combined with {@link #VERTICAL_SCROLLBAR}. + * + * @see #getNeededScrollBars + */ +qx.Class.HORIZONTAL_SCROLLBAR = 1; + +/** + * (int) The mask for the vertical scroll bar. + * May be combined with {@link #HORIZONTAL_SCROLLBAR}. + * + * @see #getNeededScrollBars + */ +qx.Class.VERTICAL_SCROLLBAR = 2; + +/** + * (string) The correct value for the CSS style attribute "cursor" for the + * horizontal resize cursor. + */ +qx.Class.CURSOR_RESIZE_HORIZONTAL = (qx.core.Client.getInstance().isGecko() && (qx.core.Client.getInstance().getMajor() > 1 || qx.core.Client.getInstance().getMinor() >= 8)) ? "ew-resize" : "e-resize"; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js new file mode 100644 index 0000000000..5496904aa2 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js @@ -0,0 +1,60 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell editor factory creating text fields. + */ +qx.OO.defineClass("qx.ui.table.TextFieldCellEditorFactory", qx.ui.table.CellEditorFactory, +function() { + qx.ui.table.CellEditorFactory.call(this); +}); + + +// overridden +qx.Proto.createCellEditor = function(cellInfo) { + var cellEditor = new qx.ui.form.TextField; + cellEditor.setAppearance("table-editor-textfield"); + cellEditor.originalValue = cellInfo.value; + cellEditor.setValue("" + cellInfo.value); + + cellEditor.addEventListener("appear", function() { + this.selectAll(); + }); + + return cellEditor; +} + + +// overridden +qx.Proto.getCellEditorValue = function(cellEditor) { + // Workaround: qx.ui.form.TextField.getValue() delivers the old value, so we use the + // value property of the DOM element directly + var value = cellEditor.getElement().value; + + if (typeof cellEditor.originalValue == "number") { + value = parseFloat(value); + } + return value; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js new file mode 100644 index 0000000000..4794537d40 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js @@ -0,0 +1,49 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.Button", qx.ui.form.Button, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.form.Button.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + // Omit focus + this.setTabIndex(-1); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-button" }); + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = qx.lang.Function.returnTrue; +qx.Proto._onkeyup = qx.lang.Function.returnTrue; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js new file mode 100644 index 0000000000..4466bd1be2 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js @@ -0,0 +1,88 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.CheckBox", qx.ui.toolbar.Button, +function(vText, vIcon, vChecked) +{ + qx.ui.toolbar.Button.call(this, vText, vIcon); + + if (vChecked != null) { + this.setChecked(vChecked); + } +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false, getAlias:"isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + propValue ? this.addState("checked") : this.removeState("checked"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + if (!this.hasState("abandoned")) + { + this.addState("over"); + this.setChecked(!this.getChecked()); + this.execute(); + } + + this.removeState("abandoned"); + this.removeState("pressed"); + + e.stopPropagation(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js new file mode 100644 index 0000000000..0a890ced88 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js @@ -0,0 +1,254 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.MenuButton", qx.ui.toolbar.Button, +function(vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.toolbar.Button.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + if (vMenu != null) { + this.setMenu(vMenu); + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "menu", type : "object", instance : "qx.ui.menu.Menu" }); +qx.OO.addProperty({ name : "direction", type : "string", allowNull : false, possibleValues : [ "up", "down" ], defaultValue : "down" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getParentToolBar = function() +{ + var vParent = this.getParent(); + + if (vParent instanceof qx.ui.toolbar.Part) { + vParent = vParent.getParent(); + } + + return vParent instanceof qx.ui.toolbar.ToolBar ? vParent : null; +} + +qx.Proto._showMenu = function(vFromKeyEvent) +{ + var vMenu = this.getMenu(); + + if (vMenu) + { + // Caching common stuff + var vMenuParent = vMenu.getParent(); + var vMenuParentElement = vMenuParent.getElement(); + var vButtonElement = this.getElement(); + var vButtonHeight = qx.html.Dimension.getBoxHeight(vButtonElement); + + // Apply X-Location + var vMenuParentLeft = qx.html.Location.getPageBoxLeft(vMenuParentElement); + var vButtonLeft = qx.html.Location.getPageBoxLeft(vButtonElement); + + vMenu.setLeft(vButtonLeft - vMenuParentLeft); + + // Apply Y-Location + switch(this.getDirection()) + { + case "up": + var vBodyHeight = qx.html.Dimension.getInnerHeight(document.body); + var vMenuParentBottom = qx.html.Location.getPageBoxBottom(vMenuParentElement); + var vButtonBottom = qx.html.Location.getPageBoxBottom(vButtonElement); + + vMenu.setBottom(vButtonHeight + (vBodyHeight - vButtonBottom) - (vBodyHeight - vMenuParentBottom)); + vMenu.setTop(null); + break; + + case "down": + var vButtonTop = qx.html.Location.getPageBoxTop(vButtonElement); + + vMenu.setTop(vButtonTop + vButtonHeight); + vMenu.setBottom(null); + break; + } + + this.addState("pressed"); + + // If this show is called from a key event occured, we want to highlight + // the first menubutton inside. + if (vFromKeyEvent) { + vMenu.setHoverItem(vMenu.getFirstActiveChild()); + } + + vMenu.show(); + } +} + +qx.Proto._hideMenu = function() +{ + var vMenu = this.getMenu(); + + if (vMenu) { + vMenu.hide(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyMenu = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + propOldValue.setOpener(null); + + propOldValue.removeEventListener("appear", this._onmenuappear, this); + propOldValue.removeEventListener("disappear", this._onmenudisappear, this); + } + + if (propValue) + { + propValue.setOpener(this); + + propValue.addEventListener("appear", this._onmenuappear, this); + propValue.addEventListener("disappear", this._onmenudisappear, this); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: MOUSE +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + if (e.getTarget() != this || !e.isLeftButtonPressed()) { + return; + } + + this.hasState("pressed") ? this._hideMenu() : this._showMenu(); +} + +qx.Proto._onmouseup = function(e) {} + +qx.Proto._onmouseout = function(e) +{ + if (e.getTarget() != this) { + return; + } + + this.removeState("over"); +} + +qx.Proto._onmouseover = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (vToolBar) + { + var vMenu = this.getMenu(); + + switch(vToolBar.getOpenMenu()) + { + case null: + case vMenu: + break; + + default: + // hide other menus + qx.manager.object.MenuManager.getInstance().update(); + + // show this menu + this._showMenu(); + } + } + + return qx.ui.toolbar.Button.prototype._onmouseover.call(this, e); +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: MENU +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmenuappear = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (!vToolBar) { + return; + } + + var vMenu = this.getMenu(); + + vToolBar.setOpenMenu(vMenu); +} + +qx.Proto._onmenudisappear = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (!vToolBar) { + return; + } + + var vMenu = this.getMenu(); + + if (vToolBar.getOpenMenu() == vMenu) { + vToolBar.setOpenMenu(null); + } +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js new file mode 100644 index 0000000000..7d7c1649a0 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.Part", qx.ui.layout.HorizontalBoxLayout, +function() +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + this._handle = new qx.ui.toolbar.PartHandle; + this.add(this._handle); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-part" }); + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +// Omit recursive cloning of qx.ui.toolbar.PartHandle +qx.Proto._cloneRecursive = function(cloneInstance) +{ + var vChildren = this.getChildren(); + var vLength = vChildren.length; + + for (var i=0; i<vLength; i++) { + if (!(vChildren[i] instanceof qx.ui.toolbar.PartHandle)) { + cloneInstance.add(vChildren[i].clone(true)); + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._handle) + { + this._handle.dispose(); + this._handle = null; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/PartHandle.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/PartHandle.js new file mode 100644 index 0000000000..280175dec3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/PartHandle.js @@ -0,0 +1,37 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.PartHandle", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + var l = new qx.ui.basic.Terminator; + l.setAppearance("toolbar-part-handle-line"); + this.add(l); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-part-handle" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/RadioButton.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/RadioButton.js new file mode 100644 index 0000000000..3ace9452fb --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/RadioButton.js @@ -0,0 +1,118 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.RadioButton", qx.ui.toolbar.CheckBox, +function(vText, vIcon, vChecked) { + qx.ui.toolbar.CheckBox.call(this, vText, vIcon, vChecked); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons +*/ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + +/*! + The name of the radio group. All the radio elements in a group (registered by the same manager) + have the same name (and could have a different value). +*/ +qx.OO.addProperty({ name : "name", type : "string" }); + +/*! + Prohibit the deselction of the checked radio button when clicked on it. +*/ +qx.OO.addProperty({ name : "disableUncheck", type : "boolean", defaultValue : false }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + qx.ui.toolbar.CheckBox.prototype._modifyChecked.call(this, propValue, propOldValue, propData); + + var vManager = this.getManager(); + if (vManager) { + vManager.handleItemChecked(this, propValue); + } + + return true; +} + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + if (!this.hasState("abandoned")) + { + this.addState("over"); + this.setChecked(this.getDisableUncheck() || !this.getChecked()); + this.execute(); + } + + this.removeState("abandoned"); + this.removeState("pressed"); + + e.stopPropagation(); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Separator.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Separator.js new file mode 100644 index 0000000000..7984021661 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/Separator.js @@ -0,0 +1,37 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.Separator", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + var l = new qx.ui.basic.Terminator; + l.setAppearance("toolbar-separator-line"); + this.add(l); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-separator" }); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/ToolBar.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/ToolBar.js new file mode 100644 index 0000000000..6b62985172 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/toolbar/ToolBar.js @@ -0,0 +1,244 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.ToolBar", qx.ui.layout.HorizontalBoxLayout, +function() +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + this.addEventListener("keypress", this._onkeypress); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "openMenu", type : "object", instance : "qx.ui.menu.Menu" }); + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar" }); + + + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getAllButtons = function() +{ + var vChildren = this.getChildren(); + var vLength = vChildren.length; + var vDeepChildren = []; + var vCurrent; + + for (var i=0; i<vLength; i++) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton) + { + vDeepChildren.push(vCurrent); + } + else if (vCurrent instanceof qx.ui.toolbar.Part) + { + vDeepChildren = vDeepChildren.concat(vCurrent.getChildren()); + } + } + + return vDeepChildren; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +/*! + Wraps key events to target functions +*/ +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Left": + return this._onkeypress_left(); + + case "Right": + return this._onkeypress_right(); + } +} + +qx.Proto._onkeypress_left = function() +{ + var vMenu = this.getOpenMenu(); + if (!vMenu) { + return; + } + + var vOpener = vMenu.getOpener(); + if (!vOpener) { + return; + } + + var vChildren = this.getAllButtons(); + var vChildrenLength = vChildren.length; + var vIndex = vChildren.indexOf(vOpener); + var vCurrent; + var vPrevButton = null; + + for (var i=vIndex-1; i>=0; i--) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vPrevButton = vCurrent; + break; + } + } + + // If none found, try again from the begin (looping) + if (!vPrevButton) + { + for (var i=vChildrenLength-1; i>vIndex; i--) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vPrevButton = vCurrent; + break; + } + } + } + + if (vPrevButton) + { + // hide other menus + qx.manager.object.MenuManager.getInstance().update(); + + // show previous menu + vPrevButton._showMenu(true); + } +} + +qx.Proto._onkeypress_right = function() +{ + var vMenu = this.getOpenMenu(); + if (!vMenu) { + return; + } + + var vOpener = vMenu.getOpener(); + if (!vOpener) { + return; + } + + var vChildren = this.getAllButtons(); + var vChildrenLength = vChildren.length; + var vIndex = vChildren.indexOf(vOpener); + var vCurrent; + var vNextButton = null; + + for (var i=vIndex+1; i<vChildrenLength; i++) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vNextButton = vCurrent; + break; + } + } + + // If none found, try again from the begin (looping) + if (!vNextButton) + { + for (var i=0; i<vIndex; i++) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vNextButton = vCurrent; + break; + } + } + } + + if (vNextButton) + { + // hide other menus + qx.manager.object.MenuManager.getInstance().update(); + + // show next menu + vNextButton._showMenu(true); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/AbstractTreeElement.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/AbstractTreeElement.js new file mode 100644 index 0000000000..cbaf27f35c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/AbstractTreeElement.js @@ -0,0 +1,505 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) +#embed(qx.widgettheme/tree/*) +#embed(qx.icontheme/16/actions/document-new.png) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.AbstractTreeElement", qx.ui.layout.BoxLayout, +function(vLabel, vIcon, vIconSelected) +{ + if (this.classname == qx.ui.tree.AbstractTreeElement.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.tree.AbstractTreeElement directly. Choose between qx.ui.tree.TreeFolder and qx.ui.tree.TreeFile instead!"); + } + + // Precreate subwidgets + this._indentObject = new qx.ui.embed.HtmlEmbed; + this._iconObject = new qx.ui.basic.Image; + this._labelObject = new qx.ui.basic.Label; + + // Make anonymous + this._indentObject.setAnonymous(true); + this._iconObject.setAnonymous(true); + this._labelObject.setAnonymous(true); + + // Behaviour and Hard Styling + this._labelObject.setSelectable(false); + this._labelObject.setStyleProperty("lineHeight", "100%"); + + qx.ui.layout.BoxLayout.call(this, "horizontal"); + + this.setLabel(vLabel); + + // Prohibit selection + this.setSelectable(false); + + // Base URL used for indent images + this.BASE_URI = qx.manager.object.AliasManager.getInstance().resolvePath("widget/tree/"); + + // Adding subwidgets + this.add(this._indentObject, this._iconObject, this._labelObject); + + // Set Icons + if (vIcon != null) { + this.setIcon(vIcon); + this.setIconSelected(vIcon); + } + + if (vIconSelected != null) { + this.setIconSelected(vIconSelected); + } + + // Setup initial icon + this._iconObject.setSource(this._evalCurrentIcon()); + + // Set Appearance + this._iconObject.setAppearance("tree-element-icon"); + this._labelObject.setAppearance("tree-element-label"); + + // Register event listeners + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); +}); + +qx.ui.tree.AbstractTreeElement.ABSTRACT_CLASS = "qx.ui.tree.AbstractTreeElement"; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tree-element" }); + +/*! + The icons +*/ +qx.OO.addProperty({ name : "icon", type : "string" }); +qx.OO.addProperty({ name : "iconSelected", type : "string" }); + +/*! + The label/caption/text of the qx.ui.basic.Atom instance +*/ +qx.OO.addProperty({ name : "label" }); + +/*! + Selected property +*/ +qx.OO.addProperty({ name : "selected", type : "boolean", defaultValue : false }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + if (this._labelObject) { + this._labelObject.setHtml(propValue); + } + + return true; +} + +qx.Proto._modifySelected = function(propValue, propOldValue, propData) +{ + propValue ? this.addState("selected") : this.removeState("selected"); + propValue ? this._labelObject.addState("selected") : this._labelObject.removeState("selected"); + + var vTree = this.getTree(); + if (!vTree._fastUpdate || (propOldValue && vTree._oldItem == this)) + { + this._iconObject.setSource(this._evalCurrentIcon()); + + if (propValue) { + this._iconObject.addState("selected"); + } else { + this._iconObject.removeState("selected"); + } + } + + var vManager = this.getTree().getManager(); + + if (propOldValue && vManager.getSelectedItem() == this) + { + vManager.deselectAll(); + } + else if (propValue && vManager.getSelectedItem() != this) + { + vManager.setSelectedItem(this); + } + + return true; +} + +qx.Proto._evalCurrentIcon = function() +{ + if (this.getSelected() && this.getIconSelected()) { + return this.getIconSelected(); + } else { + return this.getIcon() || "icon/16/actions/document-new.png"; + } +} + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getParentFolder = function() +{ + try { + return this.getParent().getParent(); + } catch(ex) {} + + return null; +} + +qx.Proto.getLevel = function() +{ + var vParentFolder = this.getParentFolder(); + return vParentFolder ? vParentFolder.getLevel() + 1 : null; +} + +qx.Proto.getTree = function() +{ + var vParentFolder = this.getParentFolder(); + return vParentFolder ? vParentFolder.getTree() : null; +} + +qx.Proto.getIndentObject = function() { + return this._indentObject; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +/** + * <p>deselects, disconnects, removes and disposes the + * current tree element and its content. + * </p> + * + * <p>destroys the current item (TreeFile or TreeFolder) + * and all its subitems. The destruction of the subitems + * is done by calling destroyContent. This is done if the + * subitem has the method destroyContent which is true if the + * subitem is a TreeFolder (or one of its subclasses). + * </p> + * + * <p>The method destroyContent is defined in the TreeFolder class. + * </p> + */ +qx.Proto.destroy = function() { + var manager = this.getTree() ? this.getTree().getManager() : null; + if(manager) { + + // if the current destroyed item is + // selectd deselect the item. If we are + // in single selection mode we have to + // call deselectAll because setItemSelected + // refuses to deselect in this case + if(manager.getItemSelected(this)) { + if(manager.getMultiSelection()) { + manager.setItemSelected(this,false); + } + else { + manager.deselectAll(); + } + } + + // set the leadItem to null if the current + // destroyed item is the leadItem + if(manager.getLeadItem() == this) { + manager.setLeadItem(null); + } + // set the anchorItem to null if the current + // destroyed item is the anchorItem + if(manager.getAnchorItem() == this) { + manager.setAnchorItem(null); + } + } + + // if the item has the method destroyContent defined + // then it is a TreeFolder (and it's subclasses) + // which potentially have content which also + // has to be destroyed + if(this.destroyContent) { + this.destroyContent(); + } + + // first disconnect the item so rendering + // of the tree lines can be done correctly + this.disconnect(); + + // remove the current item from + // the parent folder + var parentFolder = this.getParentFolder(); + if(parentFolder) { + parentFolder.remove(this); + } + + this.dispose(); +} + + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addToTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.addChildToTreeQueue(this); + } +} + +qx.Proto.removeFromTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.removeChildFromTreeQueue(this); + } +} + +qx.Proto.addToCustomQueues = function(vHint) +{ + this.addToTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.addToCustomQueues.call(this, vHint); +} + +qx.Proto.removeFromCustomQueues = function(vHint) +{ + this.removeFromTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.removeFromCustomQueues.call(this, vHint); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) +{ + qx.ui.layout.BoxLayout.prototype._modifyParent.call(this, propValue, propOldValue, propData); + + // Be sure to update previous folder also if it is closed currently (plus/minus symbol) + if (propOldValue && !propOldValue.isDisplayable() && propOldValue.getParent() && propOldValue.getParent().isDisplayable()) { + propOldValue.getParent().addToTreeQueue(); + } + + // Be sure to update new folder also if it is closed currently (plus/minus symbol) + if (propValue && !propValue.isDisplayable() && propValue.getParent() && propValue.getParent().isDisplayable()) { + propValue.getParent().addToTreeQueue(); + } + + return true; +} + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + qx.ui.layout.BoxLayout.prototype._handleDisplayableCustom.call(this, vDisplayable, vParent, vHint); + + if (vHint) + { + var vParentFolder = this.getParentFolder(); + var vPreviousParentFolder = this._previousParentFolder; + + if (vPreviousParentFolder) + { + if (this._wasLastVisibleChild) + { + vPreviousParentFolder._updateIndent(); + } + else if (!vPreviousParentFolder.hasContent()) + { + vPreviousParentFolder.addToTreeQueue(); + } + } + + if (vParentFolder && vParentFolder.isDisplayable() && vParentFolder._initialLayoutDone) { + vParentFolder.addToTreeQueue(); + } + + if (this.isLastVisibleChild()) + { + var vPrev = this.getPreviousVisibleSibling(); + + if (vPrev && vPrev instanceof qx.ui.tree.AbstractTreeElement) { + vPrev._updateIndent(); + } + } + + if (vDisplayable) { + this._updateIndent(); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + this.getTree().getManager().handleMouseDown(this, e); + e.stopPropagation(); +} + +qx.Proto._onmouseup = qx.lang.Function.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + TREE FLUSH +--------------------------------------------------------------------------- +*/ + +qx.Proto.flushTree = function() +{ + // store informations for update process + this._previousParentFolder = this.getParentFolder(); + this._wasLastVisibleChild = this.isLastVisibleChild(); + + // generate html for indent area + var vLevel = this.getLevel(); + var vTree = this.getTree(); + var vImage; + var vHtml = []; + var vCurrentObject = this; + + for (var i=0; i<vLevel; i++) + { + vImage = vCurrentObject.getIndentSymbol(vTree.getUseTreeLines(), i==0); + + if (vImage) + { + vHtml.push("<img style=\"position:absolute;top:0px;left:"); + vHtml.push((vLevel-i-1) * 19); + vHtml.push("px\" src=\""); + vHtml.push(this.BASE_URI); + vHtml.push(vImage); + vHtml.push("."); + vHtml.push("gif"); + vHtml.push("\" />"); + } + + vCurrentObject = vCurrentObject.getParentFolder(); + } + + this._indentObject.setHtml(vHtml.join("")); + this._indentObject.setWidth(vLevel * 19); +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._indentObject) + { + this._indentObject.dispose(); + this._indentObject = null; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + this._previousParentFolder = null; + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js new file mode 100644 index 0000000000..850891e058 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js @@ -0,0 +1,400 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.Tree", qx.ui.tree.TreeFolder, +function(vLabel, vIcon, vIconSelected) +{ + qx.ui.tree.TreeFolder.call(this, vLabel, vIcon, vIconSelected); + + // ************************************************************************ + // INITILISIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.TreeSelectionManager(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" }); + + + + + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getSelectedElement = function() { + return this.getManager().getSelectedItem(); +} + + + + + + +/* +--------------------------------------------------------------------------- + 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; +} + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getTree = function() { + return this; +} + +qx.Proto.getParentFolder = function() { + return null; +} + +qx.Proto.getLevel = function() { + return 0; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + COMMON CHECKERS +--------------------------------------------------------------------------- +*/ + +qx.ui.tree.Tree.isTreeFolder = function(vObject) { + return vObject && vObject instanceof qx.ui.tree.TreeFolder && !(vObject instanceof qx.ui.tree.Tree); +}; + +qx.ui.tree.Tree.isOpenTreeFolder = function(vObject) { + return vObject instanceof qx.ui.tree.TreeFolder && vObject.getOpen() && vObject.hasContent(); +}; + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var vSelectedItem = this.getManager().getSelectedItem(); + + if (e.getKeyIdentifier() == "Enter") { + e.preventDefault(); + + if (qx.ui.tree.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.tree.Tree.isTreeFolder(vSelectedItem)) + { + if (!vSelectedItem.getOpen()) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.tree.TreeFolder) { + if (!(vParent instanceof qx.ui.tree.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + else + { + return vSelectedItem.close(); + } + } + else if (vSelectedItem instanceof qx.ui.tree.TreeFile) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.tree.TreeFolder) { + if (!(vParent instanceof qx.ui.tree.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + + break; + + case "Right": + e.preventDefault(); + + if (qx.ui.tree.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 vOldItem = this._oldItem; + var vNewItem = this.getManager().getSelectedItem(); + + vNewItem.getIconObject().addState("selected"); + + delete this._fastUpdate; + delete this._oldItem; + } +}; + + +qx.Proto.getLastTreeChild = function() +{ + var vLast = this; + + while (vLast instanceof qx.ui.tree.AbstractTreeElement) + { + if (!(vLast instanceof qx.ui.tree.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); +}; + + + + + + + +/* +--------------------------------------------------------------------------- + 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.tree.TreeFolder.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js new file mode 100644 index 0000000000..8c74fa1bf5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js @@ -0,0 +1,64 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.TreeFile", qx.ui.tree.AbstractTreeElement, +function(vLabel, vIcon, vIconSelected) { + qx.ui.tree.AbstractTreeElement.call(this, vLabel, vIcon, vIconSelected); +}); + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, vIsLastColumn) +{ + if (vUseTreeLines) + { + if (vIsLastColumn) + { + return this.isLastChild() ? "end" : "cross"; + } + else + { + return "line"; + } + } + + return null; +} + +qx.Proto._updateIndent = function() { + this.addToTreeQueue(); +} + +qx.Proto.getItems = function() { + return [this]; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js new file mode 100644 index 0000000000..236a776de5 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js @@ -0,0 +1,624 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) +#embed(qx.icontheme/16/status/folder-open.png) +#embed(qx.icontheme/16/places/folder.png) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.TreeFolder", qx.ui.tree.AbstractTreeElement, +function(vLabel, vIcon, vIconSelected) +{ + qx.ui.tree.AbstractTreeElement.call(this, vLabel, vIcon, vIconSelected); + + this._iconObject.setAppearance("tree-folder-icon"); + this._labelObject.setAppearance("tree-folder-label"); + + this.addEventListener("dblclick", this._ondblclick); + + // Remapping of add/remove methods + this.add = this.addToFolder; + this.addBefore = this.addBeforeToFolder; + this.addAfter = this.addAfterToFolder; + this.addAt = this.addAtToFolder; + this.addAtBegin = this.addAtBeginToFolder; + this.addAtEnd = this.addAtEndToFolder; + this.remove = this.removeFromFolder; +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tree-folder" }); +qx.OO.changeProperty({ name : "icon", type : "string" }); +qx.OO.changeProperty({ name : "iconSelected", type : "string" }); + +qx.OO.addProperty({ name : "open", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "alwaysShowPlusMinusSymbol", type : "boolean", defaultValue : false }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.hasContent = function() { + return this._containerObject && this._containerObject.getChildrenLength() > 0; +} + +qx.Proto.open = function() +{ + if (this.getOpen()) { + return; + } + + if (this.hasContent() && this.isSeeable()) + { + this.getTopLevelWidget().setGlobalCursor("progress"); + qx.client.Timer.once(this._openCallback, this, 0); + } + else + { + this.setOpen(true); + } +} + +qx.Proto.close = function() { + this.setOpen(false); +} + +qx.Proto.toggle = function() { + this.getOpen() ? this.close() : this.open(); +} + +qx.Proto._openCallback = function() +{ + this.setOpen(true); + qx.ui.core.Widget.flushGlobalQueues(); + this.getTopLevelWidget().setGlobalCursor(null); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._createChildrenStructure = function() +{ + this.setAppearance(this instanceof qx.ui.tree.Tree ? "tree-container" : "tree-folder-container"); + + if (!this._horizontalLayout) + { + this.setOrientation("vertical"); + + this._horizontalLayout = new qx.ui.layout.HorizontalBoxLayout; + this._horizontalLayout.setWidth(null); + this._horizontalLayout.setParent(this); + this._horizontalLayout.setAnonymous(true); + this._horizontalLayout.setAppearance(this instanceof qx.ui.tree.Tree ? "tree" : "tree-folder"); + + this._indentObject.setParent(this._horizontalLayout); + this._iconObject.setParent(this._horizontalLayout); + this._labelObject.setParent(this._horizontalLayout); + } + + if (!this._containerObject) + { + this._containerObject = new qx.ui.layout.VerticalBoxLayout; + this._containerObject.setWidth(null); + this._containerObject.setAnonymous(true); + + // it should be faster to first handle display, + // because the default display value is true and if we first + // setup the parent the logic do all to make the + // widget first visible and then, if the folder is not + // opened again invisible. + this._containerObject.setDisplay(this.getOpen()); + this._containerObject.setParent(this); + + // remap remove* functions + this.remapChildrenHandlingTo(this._containerObject); + } +} + +qx.Proto._handleChildMove = function(vChild, vRelationIndex, vRelationChild) +{ + if (vChild.isDisplayable()) + { + var vChildren = this._containerObject.getChildren(); + var vOldChildIndex = vChildren.indexOf(vChild); + + if (vOldChildIndex != -1) + { + if (vRelationChild) { + vRelationIndex = vChildren.indexOf(vRelationChild); + } + + if (vRelationIndex == vChildren.length-1) + { + vChild._updateIndent(); + + // Update indent of previous last child + this._containerObject.getLastVisibleChild()._updateIndent(); + } + else if (vChild._wasLastVisibleChild) + { + vChild._updateIndent(); + + // Update indent for new last child + var vPreviousSibling = vChild.getPreviousVisibleSibling(); + if (vPreviousSibling) { + vPreviousSibling._updateIndent(); + } + } + } + } +} + +qx.Proto.addToFolder = function() +{ + this._createChildrenStructure(); + + if (this._containerObject) { + return this._containerObject.add.apply(this._containerObject, arguments); + } +} + +qx.Proto.addBeforeToFolder = function(vChild, vBefore) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vBefore); + return this._containerObject.addBefore.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAfterToFolder = function(vChild, vAfter) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vAfter); + return this._containerObject.addAfter.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtToFolder = function(vChild, vIndex) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, vIndex); + return this._containerObject.addAt.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtBeginToFolder = function(vChild) { + return this.addAtToFolder(vChild, 0); +} + +qx.Proto.addAtEndToFolder = function(vChild) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + var vLast = this._containerObject.getLastChild(); + + if (vLast) + { + this._handleChildMove(vChild, null, vLast); + return this._containerObject.addAfter.call(this._containerObject, vChild, vLast); + } + else + { + return this.addAtBeginToFolder(vChild); + } + } +} + +qx.Proto._remappingChildTable = [ "remove", "removeAt", "removeAll" ]; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getContainerObject = function() { + return this._containerObject; +} + +qx.Proto.getHorizontalLayout = function() { + return this._horizontalLayout; +} + +qx.Proto.getFirstVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getFirstChild(); + } +} + +qx.Proto.getLastVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getLastChild(); + } +} + +qx.Proto.getItems = function(recursive, invisible) +{ + var a = [this]; + + if (this._containerObject) + { + var ch = invisible == true ? this._containerObject.getChildren() : this._containerObject.getVisibleChildren(); + + if (recursive == false) + { + a = a.concat(ch); + } + else + { + for (var i=0, chl=ch.length; i<chl; i++) { + a = a.concat(ch[i].getItems(recursive, invisible)); + } + } + } + + return a; +} + +/** + * <p>deselects, disconnects, removes and disposes the + * content of the folder and its subfolders. + * </p> + * + * <p>the current items subitems (and the subitems of each + * subitem) are destroyed going top down the TreeFolder + * hierarchy. The current item is left as is. + * </p> + */ +qx.Proto.destroyContent = function() +{ + if(!this.hasContent()) { + return; + } + + var manager = this.getTree() ? this.getTree().getManager() : null; + + var leadItem; + var anchorItem; + if(manager) { + leadItem = manager.getLeadItem(); + anchorItem = manager.getAnchorItem(); + } + + // set the container objects display property + // to true so getChildren will retreive all + // children objects + this._containerObject.setDisplay(true); + var items = this._containerObject.getChildren(); + var item; + + for(var i=items.length-1;i>=0;--i) { + item = items[i]; + + // this.getItems seems to also contain "this". + // In order to avoid endless loops by calling + // recursively destroyContent we have to avoid + // destroying ourselves + if(item != this) { + if(manager) { + // set the leadItem to null if the current + // destroyed item is the leadItem + if(leadItem == item) { + manager.setLeadItem(null); + } + // set the anchorItem to null if the current + // destroyed item is the anchorItem + if(anchorItem == item) { + manager.setAnchorItem(null); + } + + // if the current destroyed item is + // selected, deselect the item. If we are + // in single selection mode we have to + // call deselectAll because setItemSelected + // refuses to deselect in this case + if(manager.getItemSelected(item)) { + if(manager.getMultiSelection()) { + manager.setItemSelected(item,false); + } + else { + manager.deselectAll(); + } + } + + // if the item has the method destroyContent defined + // then it is a TreeFolder (and it's subclasses) + // which potentially have content which also + // has to be destroyed + if (item.destroyContent) { + item.destroyContent(); + } + } + + // first disconnect the item so rendering + // of the tree lines can be done correctly + item.removeFromTreeQueue(); + item.disconnect(); + + // remove the item from the containerObject + this._containerObject.remove(item); + item.dispose(); + delete items[i]; + } + } +} + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._evalCurrentIcon = function() +{ + if (this.getSelected()) { + return this.getIconSelected() || "icon/16/status/folder-open.png"; + } else { + return this.getIcon() || "icon/16/places/folder.png"; + } +} + +qx.Proto._modifyOpen = function(propValue, propOldValue, propData) +{ + this._updateLastColumn(); + + if (this._containerObject) { + this._containerObject.setDisplay(propValue); + } + + return true; +} + +qx.Proto._modifyAlwaysShowPlusMinusSymbol = function(propValue, propOldValue, propData) +{ + this._updateLastColumn(); + + return true; +} + +qx.Proto._updateLastColumn = function() +{ + if (this._indentObject) + { + var vElement = this._indentObject.getElement(); + + if (vElement && vElement.firstChild) { + vElement.firstChild.src = this.BASE_URI + this.getIndentSymbol(this.getTree().getUseTreeLines(), true) + ".gif"; + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + if (this._indentObject.getElement().firstChild == e.getDomTarget()) + { + this.toggle(); + + // Only if we just get closed and the current selection is inside of this node. + if (!this.getOpen()) + { + if(qx.lang.Array.contains(this.getItems(true, true), this.getTree().getSelectedElement())) { + this.getTree().getManager().handleMouseDown(this, e); + } + } + } + + break; + + case this._containerObject: + break; + + case this: + if (this._containerObject) { + break; + } + + // no break here + + default: + this.getTree().getManager().handleMouseDown(this, e); + } + + e.stopPropagation(); +} + +qx.Proto._onmouseup = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + case this._containerObject: + case this: + break; + + default: + if (!this.getTree().getUseDoubleClick()) { + this.open(); + } + } +} + +qx.Proto._ondblclick = function(e) +{ + if (!this.getTree().getUseDoubleClick()) { + return; + } + + this.toggle(); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, vIsLastColumn) +{ + if (vIsLastColumn) + { + if (this.hasContent() || this.getAlwaysShowPlusMinusSymbol()) + { + if (!vUseTreeLines) + { + return this.getOpen() ? "minus" : "plus"; + } + else if (this.isLastChild()) + { + return this.getOpen() ? "end_minus" : "end_plus"; + } + else + { + return this.getOpen() ? "cross_minus" : "cross_plus"; + } + } + else if (vUseTreeLines) + { + return this.isLastChild() ? "end" : "cross"; + } + } + else + { + return vUseTreeLines && !this.isLastChild() ? "line" : null; + } +} + +qx.Proto._updateIndent = function() +{ + // Intentionally bypass superclass; the _updateIndent we want is in TreeFile + qx.ui.tree.TreeFile.prototype._updateIndent.call(this); + + if (!this._containerObject) { + return; + } + + var ch = this._containerObject.getVisibleChildren(); + for (var i=0, l=ch.length; i<l; i++) { + ch[i]._updateIndent(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("dblclick", this._ondblclick); + + if (this._horizontalLayout) + { + this._horizontalLayout.dispose(); + this._horizontalLayout = null; + } + + if (this._containerObject) + { + this._containerObject.dispose(); + this._containerObject = null; + } + + return qx.ui.tree.AbstractTreeElement.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/AbstractTreeElement.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/AbstractTreeElement.js new file mode 100644 index 0000000000..17a9ba8ce7 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/AbstractTreeElement.js @@ -0,0 +1,532 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) +#embed(qx.widgettheme/tree/*) +#embed(qx.icontheme/16/actions/document-new.png) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.treefullcontrol.AbstractTreeElement", qx.ui.layout.BoxLayout, +function(treeRowStructure) +{ + if (this.classname == qx.ui.treefullcontrol.AbstractTreeElement.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.treefullcontrol.AbstractTreeElement directly. Choose between qx.ui.treefullcontrol.TreeFolder, qx.ui.treefullcontrol.TreeFolderSimple, qx.ui.treefullcontrol.TreeFile and qx.ui.treefullcontrol.TreeFileSimple instead!"); + } + + if (treeRowStructure !== qx.ui.treefullcontrol.TreeRowStructure.getInstance()) + { + throw new Error("A qx.ui.treefullcontrol.TreeRowStructure parameter is required."); + } + + // Precreate subwidgets + this._indentObject = treeRowStructure._indentObject; + this._iconObject = treeRowStructure._iconObject; + this._labelObject = treeRowStructure._labelObject; + + // Make anonymous + this._indentObject.setAnonymous(true); + this._iconObject.setAnonymous(true); + this._labelObject.setAnonymous(true); + + // Behaviour and Hard Styling + this._labelObject.setSelectable(false); + this._labelObject.setStyleProperty("lineHeight", + "100%"); + + qx.ui.layout.BoxLayout.call(this, "horizontal"); + + if (qx.util.Validation.isValid(treeRowStructure._label)) { + this.setLabel(treeRowStructure._label); + } + + // Prohibit selection + this.setSelectable(false); + + // Base URL used for indent images + this.BASE_URI = qx.manager.object.AliasManager.getInstance().resolvePath("widget/tree/"); + + /* + * Add all of the objects which are to be in the horizontal layout. + */ + for (var i = 0; i < treeRowStructure._fields.length; i++) + { + this.add(treeRowStructure._fields[i]); + } + + // Set Icons + if ((treeRowStructure._icons.unselected != null) && + (qx.util.Validation.isValidString(treeRowStructure._icons.unselected))) { + this.setIcon(treeRowStructure._icons.unselected); + this.setIconSelected(treeRowStructure._icons.unselected); + } + if ((treeRowStructure._icons.selected != null) && + (qx.util.Validation.isValidString(treeRowStructure._icons.selected))) { + this.setIconSelected(treeRowStructure._icons.selected); + } + + // Setup initial icon + this._iconObject.setSource(this._evalCurrentIcon()); + + // Set Appearance + this._iconObject.setAppearance("tree-element-icon"); + this._labelObject.setAppearance("tree-element-label"); + + // Register event listeners + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); +}); + +qx.ui.treefullcontrol.AbstractTreeElement.ABSTRACT_CLASS = "qx.ui.treefullcontrol.AbstractTreeElement"; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", + type : "string", + defaultValue : "tree-element" + }); + +/*! + The icons +*/ +qx.OO.addProperty({ name : "icon", + type : "string" + }); + +qx.OO.addProperty({ name : "iconSelected", + type : "string" + }); + +/*! + The label/caption/text of the qx.ui.basic.Atom instance +*/ +qx.OO.addProperty({ name : "label" + }); + +/*! + Selected property +*/ +qx.OO.addProperty({ name : "selected", + type : "boolean", + defaultValue : false + }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + if (this._labelObject) { + this._labelObject.setHtml(propValue); + } + + return true; +} + +qx.Proto._modifySelected = function(propValue, propOldValue, propData) +{ + if (propValue) { + this.addState("selected"); + this._labelObject.addState("selected"); + } else { + this.removeState("selected"); + this._labelObject.removeState("selected"); + } + + var vTree = this.getTree(); + if (!vTree._fastUpdate || + (propOldValue && vTree._oldItem == this)) { + this._iconObject.setSource(this._evalCurrentIcon()); + + if (propValue) { + this._iconObject.addState("selected"); + } else { + this._iconObject.removeState("selected"); + } + } + + var vManager = this.getTree().getManager(); + + if (propOldValue && vManager.getSelectedItem() == this) + { + vManager.deselectAll(); + } + else if (propValue && vManager.getSelectedItem() != this) + { + vManager.setSelectedItem(this); + } + + return true; +} + +qx.Proto._evalCurrentIcon = function() +{ + if (this.getSelected() && this.getIconSelected()) { + return this.getIconSelected(); + } else { + return this.getIcon() || "icon/16/actions/document-new.png"; + } +} + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getParentFolder = function() +{ + try { + return this.getParent().getParent(); + } catch(ex) {} + + return null; +} + +qx.Proto.getLevel = function() +{ + var vParentFolder = this.getParentFolder(); + return vParentFolder ? vParentFolder.getLevel() + 1 : null; +} + +qx.Proto.getTree = function() +{ + var vParentFolder = this.getParentFolder(); + return vParentFolder ? vParentFolder.getTree() : null; +} + +qx.Proto.getIndentObject = function() { + return this._indentObject; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +/** + * Obtain the entire hierarchy of labels from the root down to the current + * node. + * + * @param + * vArr - + * When called by the user, arr should typically be an empty array. Each + * level from the current node upwards will push its label onto the array. + */ +qx.Proto.getHierarchy = function(vArr) { + // Add our label to the array + if (this._labelObject) { + vArr.unshift(this._labelObject.getHtml()); + } + + // Get the parent folder + var parent = this.getParentFolder(); + + // If it exists... + if (parent) { + // ... then add it and its ancestors' labels to the array. + parent.getHierarchy(vArr); + } + + // Give 'em what they came for + return vArr; +} + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addToTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.addChildToTreeQueue(this); + } +} + +qx.Proto.removeFromTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.removeChildFromTreeQueue(this); + } +} + +qx.Proto.addToCustomQueues = function(vHint) +{ + this.addToTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.addToCustomQueues.call(this, vHint); +} + +qx.Proto.removeFromCustomQueues = function(vHint) +{ + this.removeFromTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.removeFromCustomQueues.call(this, vHint); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) +{ + qx.ui.layout.BoxLayout.prototype._modifyParent.call(this, propValue, propOldValue, propData); + + // Be sure to update previous folder also if it is closed currently + // (plus/minus symbol) + if (propOldValue && + !propOldValue.isDisplayable() && + propOldValue.getParent() && + propOldValue.getParent().isDisplayable()) { + propOldValue.getParent().addToTreeQueue(); + } + + // Be sure to update new folder also if it is closed currently + // (plus/minus symbol) + if (propValue && + !propValue.isDisplayable() && + propValue.getParent() && + propValue.getParent().isDisplayable()) { + propValue.getParent().addToTreeQueue(); + } + + return true; +} + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + qx.ui.layout.BoxLayout.prototype._handleDisplayableCustom.call(this, + vDisplayable, + vParent, + vHint); + + if (vHint) + { + var vParentFolder = this.getParentFolder(); + var vPreviousParentFolder = this._previousParentFolder; + + if (vPreviousParentFolder) + { + if (this._wasLastVisibleChild) + { + vPreviousParentFolder._updateIndent(); + } + else if (!vPreviousParentFolder.hasContent()) + { + vPreviousParentFolder.addToTreeQueue(); + } + } + + if (vParentFolder && + vParentFolder.isDisplayable() && + vParentFolder._initialLayoutDone) { + vParentFolder.addToTreeQueue(); + } + + if (this.isLastVisibleChild()) + { + var vPrev = this.getPreviousVisibleSibling(); + + if (vPrev && + vPrev instanceof qx.ui.treefullcontrol.AbstractTreeElement) { + vPrev._updateIndent(); + } + } + + if (vDisplayable) { + this._updateIndent(); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + this.getTree().getManager().handleMouseDown(this, e); + e.stopPropagation(); +} + +qx.Proto._onmouseup = qx.lang.Function.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + TREE FLUSH +--------------------------------------------------------------------------- +*/ + +qx.Proto.flushTree = function() +{ + // store information for update process + this._previousParentFolder = this.getParentFolder(); + this._wasLastVisibleChild = this.isLastVisibleChild(); + + // generate html for indent area + var vLevel = this.getLevel(); + var vTree = this.getTree(); + var vImage; + var vHtml = []; + var vCurrentObject = this; + var vMinLevel = 0; + var vMaxLevel = vLevel; + + // If we're displaying the open/close button for the root node (normal)... + if (vTree.getRootOpenClose()) { + // ... then we need one more level + vMaxLevel = vLevel + 1; + } + + // If we're not displaying the root node (creating virtual roots)... + if (vTree.hideNode()) { + // ... then start one level higher + vMinLevel = 1; + } + + for (var i=vMinLevel; i<vMaxLevel; i++) + { + vImage = vCurrentObject.getIndentSymbol(vTree.getUseTreeLines(), + i, + vMinLevel, + vMaxLevel); + + if (vImage) + { + vHtml.push("<img style=\"position:absolute;top:0px;left:"); + + // location of image; Root's image could be left of margin (invisible) + vHtml.push((vMaxLevel-i-1) * 19); + + vHtml.push("px\" src=\""); + vHtml.push(this.BASE_URI); + vHtml.push(vImage); + vHtml.push("."); + vHtml.push("gif"); + vHtml.push("\" />"); + } + + vCurrentObject = vCurrentObject.getParentFolder(); + } + + this._indentObject.setHtml(vHtml.join("")); + this._indentObject.setWidth((vMaxLevel - vMinLevel) * 19); +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._indentObject) + { + this._indentObject.dispose(); + this._indentObject = null; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + this._previousParentFolder = null; + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js new file mode 100644 index 0000000000..e29e06777a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js @@ -0,0 +1,541 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + 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 <i>true</i>, indicates that tree lines at that indentation + level are to be omitted. Any value of that element other than <i>true</i>, + 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 <i>true</i> and desiring to reset the default + behavior, you should 'delete' the element rather than setting it to some + value other than <i>true</i>.) + + If useTreeLines is <i>false</i>, 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); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js new file mode 100644 index 0000000000..cb1f6ef892 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js @@ -0,0 +1,83 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +/** + * qx.ui.treefullcontrol.TreeFile objects are terminal tree rows (i.e. no + * sub-trees) + * + * @param + * treeRowStructure - + * An instance of qx.ui.treefullcontrol.TreeRowStructure, defining the + * structure of this tree row. + */ +qx.OO.defineClass("qx.ui.treefullcontrol.TreeFile", qx.ui.treefullcontrol.AbstractTreeElement, +function(treeRowStructure) +{ + qx.ui.treefullcontrol.AbstractTreeElement.call(this, treeRowStructure); +}); + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, + vColumn, + vFirstColumn, + vLastColumn) +{ + var vLevel = this.getLevel(); + var vExcludeList = this.getTree().getExcludeSpecificTreeLines(); + var vExclude = vExcludeList[vLastColumn - vColumn - 1]; + + if (vUseTreeLines && ! (vExclude === true)) + { + if (vColumn == vFirstColumn) + { + return this.isLastChild() ? "end" : "cross"; + } + else + { + return "line"; + } + } + + return null; +} + +qx.Proto._updateIndent = function() { + this.addToTreeQueue(); +} + +qx.Proto.getItems = function() { + return [this]; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js new file mode 100644 index 0000000000..0ca957e35f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js @@ -0,0 +1,655 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) +#embed(qx.icontheme/16/status/folder-open.png) +#embed(qx.icontheme/16/places/folder.png) + +************************************************************************ */ + +/** + * qx.ui.treefullcontrol.TreeFolder objects are tree rows which may contain + * sub-trees + * + * @param + * treeRowStructure - + * An instance of qx.ui.treefullcontrol.TreeRowStructure, defining the + * structure of this tree row. + * + * @event treeOpenWithContent {qx.event.type.DataEvent} + * @event treeOpenWhileEmpty {qx.event.type.DataEvent} + * @event treeClose {qx.event.type.DataEvent} + */ +qx.OO.defineClass("qx.ui.treefullcontrol.TreeFolder", qx.ui.treefullcontrol.AbstractTreeElement, +function(treeRowStructure) +{ + qx.ui.treefullcontrol.AbstractTreeElement.call(this, treeRowStructure); + + // Save the tree row field order. We'll need it to create children structure. + this._treeRowStructureFields = treeRowStructure._fields; + + this._iconObject.setAppearance("tree-folder-icon"); + this._labelObject.setAppearance("tree-folder-label"); + + this.addEventListener("dblclick", this._ondblclick); + + // Remapping of add/remove methods + this.add = this.addToFolder; + this.addBefore = this.addBeforeToFolder; + this.addAfter = this.addAfterToFolder; + this.addAt = this.addAtToFolder; + this.addAtBegin = this.addAtBeginToFolder; + this.addAtEnd = this.addAtEndToFolder; +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", + type : "string", + defaultValue : "tree-folder" + }); + +qx.OO.changeProperty({ name : "icon", + type : "string" + }); + +qx.OO.changeProperty({ name : "iconSelected", + type : "string" + }); + +qx.OO.addProperty({ name : "open", + type : "boolean", + defaultValue : false + }); + +qx.OO.addProperty({ name : "alwaysShowPlusMinusSymbol", + type : "boolean", + defaultValue : false + }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.hasContent = function() { + return (this._containerObject && + this._containerObject.getChildrenLength() > 0); +} + +qx.Proto.open = function() +{ + if (this.getOpen()) { + return; + } + + if (this.hasContent()) + { + // If there are listeners waiting for a treeOpenWithContent event... + if (this.getTree().hasEventListeners("treeOpenWithContent")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeOpenWithContent", this), true); + } + + this.getTopLevelWidget().setGlobalCursor("progress"); + qx.client.Timer.once(this._openCallback, this, 0); + } + else + { + // If there are listeners waiting for a treeOpenWithContent event... + if (this.getTree().hasEventListeners("treeOpenWhileEmpty")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeOpenWhileEmpty", this), true); + } + + this.setOpen(true); + } +} + +qx.Proto.close = function() +{ + // If there are listeners waiting for a treeClose event... + if (this.getTree().hasEventListeners("treeClose")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeClose", this), true); + } + + this.setOpen(false); +} + +qx.Proto.toggle = function() +{ + this.getOpen() ? this.close() : this.open(); +} + +qx.Proto._openCallback = function() +{ + this.setOpen(true); + qx.ui.core.Widget.flushGlobalQueues(); + this.getTopLevelWidget().setGlobalCursor(null); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._createChildrenStructure = function() +{ + this.setAppearance(this instanceof qx.ui.treefullcontrol.Tree + ? "tree-container" + : "tree-folder-container"); + + if (!this._horizontalLayout) + { + this.setOrientation("vertical"); + + // Create a horizontal layout for this tree row + this._horizontalLayout = new qx.ui.layout.HorizontalBoxLayout; + this._horizontalLayout.setWidth(null); + this._horizontalLayout.setParent(this); + this._horizontalLayout.setAnonymous(true); + this._horizontalLayout.setAppearance(this instanceof qx.ui.treefullcontrol.Tree + ? "tree" + : "tree-folder"); + + // Move the row fields into the horizontal layout + for (var i = 0; i < this._treeRowStructureFields.length; i++) + { + this._treeRowStructureFields[i].setParent(this._horizontalLayout); + } + + // We don't need the tree row structure any more. + this._treeRowStructureFields = null; + } + + if (!this._containerObject) + { + // Create a veritcal box layout for all of this folder's children + this._containerObject = new qx.ui.layout.VerticalBoxLayout; + this._containerObject.setWidth(null); + this._containerObject.setAnonymous(true); + + // it should be faster to first handle display, + // because the default display value is true and if we first + // setup the parent the logic do all to make the + // widget first visible and then, if the folder is not + // opened again invisible. + this._containerObject.setDisplay(this.getOpen()); + this._containerObject.setParent(this); + + // remap remove* functions + this.remapChildrenHandlingTo(this._containerObject); + } +} + +qx.Proto._handleChildMove = function(vChild, vRelationIndex, vRelationChild) +{ + if (vChild.isDisplayable()) + { + var vChildren = this._containerObject.getChildren(); + var vOldChildIndex = vChildren.indexOf(vChild); + + if (vOldChildIndex != -1) + { + if (vRelationChild) { + vRelationIndex = vChildren.indexOf(vRelationChild); + } + + if (vRelationIndex == vChildren.length-1) + { + vChild._updateIndent(); + + // Update indent of previous last child + this._containerObject.getLastVisibleChild()._updateIndent(); + } + else if (vChild._wasLastVisibleChild) + { + vChild._updateIndent(); + + // Update indent for new last child + var vPreviousSibling = vChild.getPreviousVisibleSibling(); + if (vPreviousSibling) { + vPreviousSibling._updateIndent(); + } + } + } + } +} + +qx.Proto.addToFolder = function() +{ + this._createChildrenStructure(); + + if (this._containerObject) { + return this._containerObject.add.apply(this._containerObject, arguments); + } +} + +qx.Proto.addBeforeToFolder = function(vChild, vBefore) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vBefore); + return this._containerObject.addBefore.apply(this._containerObject, + arguments); + } +} + +qx.Proto.addAfterToFolder = function(vChild, vAfter) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vAfter); + return this._containerObject.addAfter.apply(this._containerObject, + arguments); + } +} + +qx.Proto.addAtToFolder = function(vChild, vIndex) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, vIndex); + return this._containerObject.addAt.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtBeginToFolder = function(vChild) { + return this.addAtToFolder(vChild, 0); +} + +qx.Proto.addAtEndToFolder = function(vChild) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + var vLast = this._containerObject.getLastChild(); + + if (vLast) + { + this._handleChildMove(vChild, null, vLast); + return this._containerObject.addAfter.call(this._containerObject, + vChild, + vLast); + } + else + { + return this.addAtBeginToFolder(vChild); + } + } +} + +qx.Proto._remappingChildTable = [ "remove", "removeAt", "removeAll" ]; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getContainerObject = function() +{ + return this._containerObject; +} + +qx.Proto.getHorizontalLayout = function() +{ + return this._horizontalLayout; +} + +qx.Proto.getFirstVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getFirstChild(); + } +} + +qx.Proto.getLastVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getLastChild(); + } +} + +qx.Proto.getItems = function() +{ + var a = [this]; + + if (this._containerObject) + { + var ch = this._containerObject.getVisibleChildren(); + + for (var i=0, chl=ch.length; i<chl; i++) { + a = a.concat(ch[i].getItems()); + } + } + + return a; +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._evalCurrentIcon = function() +{ + if (this.getSelected()) { + return this.getIconSelected() || "icon/16/status/folder-open.png"; + } else { + return this.getIcon() || "icon/16/places/folder.png"; + } +} + +qx.Proto._modifyOpen = function(propValue, propOldValue, propData) +{ + // we need the whole indent process if certain tree lines are to be excluded + if (this.getTree().getExcludeSpecificTreeLines().length > 0) { + this._updateIndent(); + } else { + this._updateLastColumn(); + } + + if (this._containerObject) { + this._containerObject.setDisplay(propValue); + } + + return true; +} + +qx.Proto._modifyAlwaysShowPlusMinusSymbol = function(propValue, propOldValue, propData) +{ + var t = this.getTree(); + if (t) { + // we need the whole indent process if only certain tree lines are to be + // excluded + if (t.getExcludeSpecificTreeLines().length > 0) { + this._updateIndent(); + } else { + this._updateLastColumn(); + } + } + + return true; +} + +qx.Proto._updateLastColumn = function() +{ + if (this._indentObject) + { + var vElement = this._indentObject.getElement(); + + if (vElement && vElement.firstChild) { + vElement.firstChild.src = + (this.BASE_URI + + this.getIndentSymbol(this.getTree().getUseTreeLines(), 0, 0, 0) + + ".gif"); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + if (this._indentObject.getElement().firstChild == e.getDomTarget()) + { + this.getTree().getManager().handleMouseDown(this, e); + this.toggle(); + } + + break; + + case this._containerObject: + break; + + case this: + if (this._containerObject) { + break; + } + + // no break here + + default: + this.getTree().getManager().handleMouseDown(this, e); + } + + e.stopPropagation(); +} + +qx.Proto._onmouseup = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + case this._containerObject: + case this: + break; + + default: + if (!this.getTree().getUseDoubleClick()) { + this.open(); + } + } +} + +qx.Proto._ondblclick = function(e) +{ + if (!this.getTree().getUseDoubleClick()) { + return; + } + + this.toggle(); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, + vColumn, + vFirstColumn, + vLastColumn) +{ + var vLevel = this.getLevel(); + var vExcludeList = this.getTree().getExcludeSpecificTreeLines(); + var vExclude = vExcludeList[vLastColumn - vColumn - 1]; + + if (vColumn == vFirstColumn) + { + if (this.hasContent() || this.getAlwaysShowPlusMinusSymbol()) + { + // If tree lines were not requested, don't display them + if (!vUseTreeLines) + { + return this.getOpen() ? "minus" : "plus"; + } + + + // If this is the first level under the root... + if (vLevel == 1) { + // ... and the root is not being displayed and this is the first + // child... + var vParentFolder = this.getParentFolder(); + if (vParentFolder && + !vParentFolder._horizontalLayout.getVisibility() && + this.isFirstChild()) + { + //... then if this is also the last (i.e. only) child, use no tree + // lines; otherwise, use descender lines but no ascender. + if (this.isLastChild() || vExclude === true) + { + return this.getOpen() ? "only_minus" : "only_plus"; + } + else + { + return this.getOpen() ? "start_minus" : "start_plus"; + } + } + } + + if (vExclude === true) + { + return this.getOpen() ? "only_minus" : "only_plus"; + } + else if (this.isLastChild()) + { + return this.getOpen() ? "end_minus" : "end_plus"; + } + else + { + return this.getOpen() ? "cross_minus" : "cross_plus"; + } + } + else if (vUseTreeLines && ! (vExclude === true)) + { + return this.isLastChild() ? "end" : "cross"; + } + } + else + { + if (vUseTreeLines && ! this.isLastChild()) { + if (vExclude === true) { + return null; + } + return "line"; + } + return null; + } +} + +qx.Proto._updateIndent = function() +{ + // Intentionally bypass superclass; the _updateIndent we want is in TreeFile + qx.ui.treefullcontrol.TreeFile.prototype._updateIndent.call(this); + + if (!this._containerObject) { + return; + } + + var ch = this._containerObject.getVisibleChildren(); + for (var i=0, l=ch.length; i<l; i++) { + ch[i]._updateIndent(); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("dblclick", this._ondblclick); + + if (this._horizontalLayout) + { + this._horizontalLayout.dispose(); + this._horizontalLayout = null; + } + + if (this._containerObject) + { + this._containerObject.dispose(); + this._containerObject = null; + } + + return qx.ui.treefullcontrol.AbstractTreeElement.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeRowStructure.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeRowStructure.js new file mode 100644 index 0000000000..9eedf64718 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeRowStructure.js @@ -0,0 +1,268 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +/** + * The structure of a tree row. + * + * This is a singleton class. The constructor is not accessed by users; + * instead, to obtain the one and only TreeRowStructure object, call either + * + * <pre>qx.ui.treefullcontrol.TreeRowStructure.newRow()</pre> + * + * or + * + * <pre>qx.ui.treefullcontrol.TreeRowStructure.standard().</pre> + * + * The structure of a tree row is provided by a + * qx.ui.treefullcontrol.TreeRowStructure. The order of elements added to + * this object is the order in which they will be presented in a tree row. + * + * The three standard parts of a tree: the indentation (and its associated + * tree-lines, if enabled), the icon (selected or unselected), and the label + * are added to the structure in the desired order by calling, respectively, + * the methods addIndent(), addIcon() and addLabel(). + * + * By default, indentation will appear at the beginning of the tree row. This + * can be changed by calling the addIndent() method after having calling other + * add*() methods on this object. If indentation is to be at the beginning of + * the tree row, simply do not call addIndent(). + * + * Any other object which is valid within a qx.ui.layout.HorizontalBoxLayout + * may be added to the structure using addObject(). If the object has no + * special treatment, it may be made anonymous with obj.SetAnonymous(true). + * Otherwise, all handling for the object should be done by the application. + * + * A "standard" (traditional) tree row would be generated like this: + * + * <pre> + * treeRowStructure = qx.ui.treefullcontrol.TreeRowStructure.standard("Trash"); + * </pre> + * + * which equates to issuing these commands: + * + * <pre> + * treeRowStructure = qx.ui.treefullcontrol.TreeRowStructure.newRow(); + * + * //treeRowStructure.addIndent() // defaults to here; no need to call + * treeRowStructure.addIcon(); + * treeRowStructure.addLabel("Trash"); + * </pre> + * + * The former method is typically preferred. + * + * An example of a more sophisticated structure: + * + * <pre> + * treeRowStructure = qx.ui.treefullcontrol.TreeRowStructure.newRow(); + * + * // A left-justified icon + * obj = new qx.ui.basic.Image("icon/16/apps/accessories-alarm.png"); + * treeRowStructure.addObject(obj, true); + * + * // Here's our indentation and tree-lines + * treeRowStructure.addIndent(); + * + * // The standard tree icon follows + * treeRowStructure.addIcon("icon/16/places/user-desktop.png","icon/16/apps/accessories-dictionary.png"); + * + * // Right after the tree icon is a checkbox + * obj = new qx.ui.form.CheckBox(null, 23, null, false); + * obj.setPadding(0, 0); + * treeRowStructure.addObject(obj, true); + * + * // The label + * treeRowStructure.addLabel("Trash"); + * + * // All else should be right justified + * obj = new qx.ui.basic.HorizontalSpacer; + * treeRowStructure.addObject(obj, true); + * + * // Add a file size, date and mode + * obj = new qx.ui.basic.Label("23kb"); + * obj.setWidth(50); + * treeRowStructure.addObject(obj, true); + * obj = new qx.ui.basic.Label("11 Sept 1959"); + * obj.setWidth(150); + * treeRowStructure.addObject(obj, true); + * obj = new qx.ui.basic.Label("-rw-r--r--"); + * obj.setWidth(80); + * treeRowStructure.addObject(obj, true); + * </pre> + */ + +qx.OO.defineClass("qx.ui.treefullcontrol.TreeRowStructure", qx.core.Object, +function() +{ + qx.core.Object.call(this); +}); + + +/** + * Prepare to define a new row. + * + * This reinitializes the singleton TreeRowStructure so that it is ready to + * define a new tree row. + * + * @return The singleton itself, purely for convenience. + */ +qx.Proto.newRow = function() +{ + /* Create the indent, icon, and label objects */ + this._indentObject = new qx.ui.embed.HtmlEmbed; + this._iconObject = new qx.ui.basic.Image; + this._labelObject = new qx.ui.basic.Label; + + /* Create an object to hold the ordering of row objects */ + this._fields = new Array; + + /* Create an object to hold the icon names */ + this._icons = new Object; + + /* Initially assume that indentation goes at the beginning of the row */ + this._fields.push(this._indentObject); + + /* Set initial flags */ + this._indentAdded = false; + this._iconAdded = false; + this._labelAdded = false; + + /* Return the singleton (from which we were called) */ + return this; +} + +/** + * Define a new row with the 'standard' structure. + * + * This reinitializes the singleton TreeRowStructure to the state of a + * standard'or traditional tree row: + * - indentation + * - icon + * - label + * + * The icon parameters may be omitted in which case the defaults will be + * used. If the label parameter is omitted, no label will appear. + * + * @param vLabel {String} The label text + * @param vIcon {String} Relative path to the 'non-selected' icon + * @param vIconSelected {String} Relative path to the 'selected' icon + * + * @return The singleton itself, purely for convenience. + */ +qx.Proto.standard = function(vLabel, vIcon, vIconSelected) +{ + this.newRow(); + this.addIcon(vIcon, vIconSelected); + this.addLabel(vLabel); + + return this; +} + +qx.Proto.addIndent = function() +{ + /* If the assumed indent object is in use... */ + if (! this._indentAdded) + { + /* ... then remove it. */ + this._fields.shift(); + this._indentAdded = true; + } + else + { + throw new Error("Indent object added more than once."); + } + + /* Add the indentation to the structure */ + this._fields.push(this._indentObject); +} + +qx.Proto.addIcon = function(vIcon, vIconSelected) +{ + /* Ensure only one standard icon is added */ + if (! this._iconAdded) + { + this._iconAdded = true; + } + else + { + throw new Error("Icon object added more than once."); + } + + /* Track the two icon names */ + this._icons.unselected = vIcon; + this._icons.selected = vIconSelected; + + /* Add the icon to the structure */ + this._fields.push(this._iconObject); +} + +qx.Proto.addLabel = function(vLabel) +{ + /* Ensure only one standard label is added */ + if (! this._labelAdded) + { + this._labelAdded = true; + } + else + { + throw new Error("Label added more than once."); + } + + /* Track the label text */ + this._label = vLabel; + + /* Add the label to the structure */ + this._fields.push(this._labelObject); +} + +/* + * Add an object to the tree row structure. For convenience, vAnonymous can + * be provided, and if a boolean value is provided, vObj.setAnonymous() is + * called with the provided value. If the object has already been + * setAnonymous or if there is no need to do so, then provide no value for + * vAnonymous or pass 'null'. + */ +qx.Proto.addObject = function(vObj, vAnonymous) +{ + /* Is requested, set this object's anonymous state */ + if (typeof vAnonymous == "boolean") + { + vObj.setAnonymous(vAnonymous); + } + + /* Add this user-specified object to the structure */ + this._fields.push(vObj); +} + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.lang.Function.returnInstance; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/DefaultDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/DefaultDataCellRenderer.js new file mode 100644 index 0000000000..adedd829a9 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/DefaultDataCellRenderer.js @@ -0,0 +1,45 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(treevirtual) + +************************************************************************ */ + +/** + * The default data cell renderer for a virtual tree (columns other than the + * tree column) + */ +qx.OO.defineClass("qx.ui.treevirtual.DefaultDataCellRenderer", + qx.ui.table.DefaultDataCellRenderer, +function() +{ + qx.ui.table.DefaultDataCellRenderer.call(this); +}); + + +// overridden +qx.Proto._getCellStyle = function(cellInfo) +{ + // Return the style for the div for the cell. If there's cell-specific + // style information provided, append it. + var html = qx.ui.treevirtual.SimpleTreeDataCellRenderer.MAIN_DIV_STYLE; + return html; +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataCellRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataCellRenderer.js new file mode 100644 index 0000000000..71abc0eb3f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataCellRenderer.js @@ -0,0 +1,314 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(treevirtual) + +************************************************************************ */ + +/** + * A data cell renderer for the tree column of a simple tree + */ +qx.OO.defineClass("qx.ui.treevirtual.SimpleTreeDataCellRenderer", + qx.ui.table.AbstractDataCellRenderer, +function() +{ + qx.ui.table.AbstractDataCellRenderer.call(this); + + // Base URL used for indent images + var Am = qx.manager.object.AliasManager; + this.WIDGET_TREE_URI = Am.getInstance().resolvePath("widget/tree/"); + this.STATIC_IMAGE_URI = Am.getInstance().resolvePath("static/image/") +}); + + +/** + * Set whether lines linking tree children shall be drawn on the tree. + */ +qx.OO.addProperty({ + name : "useTreeLines", + type : "boolean", + defaultValue : true, + getAlias : "useTreeLines" + }); + +/** + * Set whether the open/close button should be displayed on a branch, even if + * the branch has no children. + */ +qx.OO.addProperty({ + name : "alwaysShowOpenCloseSymbol", + type : "boolean", + defaultValue : false + }); + +/** + * When true, exclude only the first-level tree lines, creating, effectively, + * multiple unrelated root nodes. + */ +qx.OO.addProperty({ + name : "jensLautenbacherMode", + type : "boolean", + defaultValue : false + }); + + + + +// overridden +qx.Proto._getCellStyle = function(cellInfo) +{ + var node = cellInfo.value; + + // Return the style for the div for the cell. If there's cell-specific + // style information provided, append it. + var html = + qx.ui.treevirtual.SimpleTreeDataCellRenderer.MAIN_DIV_STYLE + + (node.cellStyle ? node.cellStyle + ";" : ""); + return html; +}; + + +// overridden +qx.Proto._getContentHtml = function(cellInfo) +{ + var html = ""; + var node = cellInfo.value; + var imageUrl; + var _this = this; + var Stdcr = qx.ui.treevirtual.SimpleTreeDataCellRenderer; + + function addImage(urlAndToolTip) + { + var html = Stdcr.IMG_START; + var Am = qx.manager.object.AliasManager; + + if (qx.core.Client.getInstance().isMshtml() && + /\.png$/i.test(urlAndToolTip.url)) + { + html += + this.STATIC_IMAGE_URI + "blank.gif" + + '" style="filter:' + + "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + + " src='" + urlAndToolTip.url + "',sizingMethod='scale')"; + } + else + { + var imageUrl = Am.getInstance().resolvePath(urlAndToolTip.url); + html += imageUrl + '" style="'; + } + + if (urlAndToolTip.imageWidth && urlAndToolTip.imageHeight) + { + html += + ';width:' + urlAndToolTip.imageWidth + 'px' + + ';height:' + urlAndToolTip.imageHeight + 'px'; + } + + var tooltip = urlAndToolTip.tooltip; + if (tooltip != null) + { + html += Stdcr.IMG_TITLE_START + tooltip; + } + html += Stdcr.IMG_END; + + return html; + } + + // Generate the indentation. Obtain icon determination values once rather + // than each time through the loop. + var bUseTreeLines = this.getUseTreeLines(); + var bJensLautenbacherMode = this.getJensLautenbacherMode(); + var bAlwaysShowOpenCloseSymbol = this.getAlwaysShowOpenCloseSymbol(); + + for (var i = 0; i < node.level; i++) + { + imageUrl = this._getIndentSymbol(i, + node, + bUseTreeLines, + bAlwaysShowOpenCloseSymbol, + bJensLautenbacherMode); + html += addImage({ + url : imageUrl, + imageWidth : 19, + imageHeight : 16 + }); + } + + // Add the node's icon + imageUrl = (node.bSelected ? node.iconSelected : node.icon); + if (! imageUrl) + { + if (node.type == qx.ui.treevirtual.SimpleTreeDataModel.Type.LEAF) + { + imageUrl = (node.bSelected + ? "icon/16/actions/document-open.png" + : "icon/16/actions/document-new.png"); + } + else + { + imageUrl = (node.bSelected + ? "icon/16/status/folder-open.png" + : "icon/16/places/folder.png"); + } + } + html += addImage({ url:imageUrl }); + + // Add the node's label. We calculate the "left" property with: each tree + // line (indentation) icon is 19 pixels wide; the folder icon is 16 pixels + // wide, there are two pixels of padding at the left, and we want 2 pixels + // between the folder icon and the label + html += + '<div style="position:absolute;' + + 'left:' + ((node.level * 19) + 16 + 2 + 2) + ';' + + 'top:0' + + (node.labelStyle ? ";" + node.labelStyle : "") + + ';">' + + node.label + + '</div>'; + + return html; +}; + + +qx.Proto._getIndentSymbol = function(column, + node, + bUseTreeLines, + bAlwaysShowOpenCloseSymbol, + bJensLautenbacherMode) +{ + // If we're in column 0 and jensLautenbacherMode is enabled, then we treat + // this as if no tree lines were requested. + if (column == 0 && bJensLautenbacherMode) + { + bUseTreeLines = false; + } + + // If we're not on the final column... + if (column < node.level - 1) + { + // then return either a line or a blank icon, depending on bUseTreeLines + return (bUseTreeLines && ! node.lastChild[column] + ? this.WIDGET_TREE_URI + "line.gif" + : this.STATIC_IMAGE_URI + "blank.gif"); + } + + var bLastChild = node.lastChild[node.lastChild.length - 1]; + + // Is this a branch node? + if (node.type == qx.ui.treevirtual.SimpleTreeDataModel.Type.BRANCH && + (node.opened === true || node.opened === false)) + { + // Determine if this node has any children + var child = null; + for (child in node.children) + { + // If we find even one, we're done here. + break; + } + + // Does this node have any children, or do we always want the open/close + // symbol to be shown? + if (child !== null || bAlwaysShowOpenCloseSymbol) + { + // If we're not showing tree lines... + if (! bUseTreeLines) + { + // ... then just use a plus or minus + return (node.opened + ? this.WIDGET_TREE_URI + "minus.gif" + : this.WIDGET_TREE_URI + "plus.gif"); + } + + // Are we looking at a top-level, first child of its parent? + if (column == 0 && node.bFirstChild) + { + // Yup. If it's also a last child... + if (bLastChild) + { + // ... then use no tree lines. + return (node.opened + ? this.WIDGET_TREE_URI + "only_minus.gif" + : this.WIDGET_TREE_URI + "only_plus.gif"); + } + else + { + // otherwise, use descender lines but no ascender. + return (node.opened + ? this.WIDGET_TREE_URI + "start_minus.gif" + : this.WIDGET_TREE_URI + "start_plus.gif"); + } + } + + // It's not a top-level, first child. Is this the last child of its + // parent? + if (bLastChild) + { + // Yup. Return an ending plus or minus, or blank if node.opened so + // indicates. + return (node.opened + ? this.WIDGET_TREE_URI + "end_minus.gif" + : this.WIDGET_TREE_URI + "end_plus.gif"); + } + + // Otherwise, return a crossing plus or minus, or a blank if + // node.opened so indicates. + return (node.opened + ? this.WIDGET_TREE_URI + "cross_minus.gif" + : this.WIDGET_TREE_URI + "cross_plus.gif"); + } + } + + // This node does not have any children. Return an end or cross, if we're + // using tree lines. + if (bUseTreeLines) + { + // If this is a last child, return and ending line; otherwise cross. + return (bLastChild + ? this.WIDGET_TREE_URI + "end.gif" + : this.WIDGET_TREE_URI + "cross.gif"); + } + + return this.STATIC_IMAGE_URI + "blank.gif"; +} + + +// overridden +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) +{ + throw new Error("USE_ARRAY_JOIN not supported"); +}; + + + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) +{ + throw new Error("USE_ARRAY_JOIN not supported"); +}; + +qx.Class.MAIN_DIV_STYLE = + ';overflow:hidden;white-space:nowrap;border-right:1px solid #eeeeee;' + + 'padding-left:2px;padding-right:2px;cursor:default' + + (qx.core.Client.getInstance().isMshtml() ? '' : ';-moz-user-select:none;'); + +qx.Class.IMG_START = '<img src="'; +qx.Class.IMG_END = '"/>'; +qx.Class.IMG_TITLE_START = '" title="'; + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataModel.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataModel.js new file mode 100644 index 0000000000..215830c224 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataModel.js @@ -0,0 +1,576 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(treevirtual) + +************************************************************************ */ + + + +/* + * A simple tree data model used as the table model + * + * The object structure of a single node of the tree is: + * + * { + * type : qx.ui.treevirtual.Type.LEAF, + * parentNodeId : 23, // index in _nodeArr of the parent node + * label : "My Documents", + * bSelected : true, // true if node is selected; false otherwise + * opened : null, // true (-), false (+), or null (no +/-) + * icon : "images/folder.gif", + * iconSelected : "images/folder_selected.gif", + * children : [ ], // each value is an index into _nodeArr + * + * cellStyle : "background-color:cyan" + * labelStyle : "background-color:red;color:white" + * + * // The following properties need not (and should not) be set by the + * // caller, but are automatically calculated. Some are used internally, + * // while others may be of use to event listeners. + * + * nodeId : 42, // The index in _nodeArr, useful to event listeners + * + * level : 2, // The indentation level of this tree node + * + * bFirstChild : true, + * lastChild : [ false ], // Array where the index is the column of + * // indentation, and the value is a boolean. + * // These are used to locate the + * // appropriate "tree line" icon. + * } + */ +qx.OO.defineClass("qx.ui.treevirtual.SimpleTreeDataModel", + qx.ui.table.AbstractTableModel, +function() +{ + qx.ui.table.AbstractTableModel.call(this); + + this._rowArr = [ ]; // rows, resorted into tree order as necessary + this._nodeArr = [ ]; // tree nodes, organized with hierarchy + + this._nodeRowMap = [ ]; // map nodeArr index to rowArr index. The + // index of this array is the index of + // _nodeArr, and the values in this array are + // the indexes into _rowArr. + + + this._treeColumn = 0; // default column for tree nodes + + this._selections = { }; // list of indexes of selected nodes + + this._nodeArr.push( // the root node, needed to store its children + { + label : "<virtual root>", + opened : true, + children : [ ] + }); +}); + + +// overridden +qx.Proto.setEditable = function(editable) +{ + throw new Error("Tree columns can not be made editable"); +}; + + +// overridden +qx.Proto.setColumnEditable = function(columnIndex, editable) +{ + throw new Error("Tree columns can not be made editable"); +}; + + +// overridden +qx.Proto.isColumnEditable = function(columnIndex) +{ + return false; +}; + + +// overridden +qx.Proto.isColumnSortable = function(columnIndex) +{ + return false; +}; + + +// overridden +qx.Proto.sortByColumn = function(columnIndex, ascending) +{ + throw new Error("Trees can not be sorted by column"); +}; + + +qx.Proto.getSortColumnIndex = function() +{ + return -1; +}; + + +qx.Proto.isSortAscending = function() +{ + return true; +}; + + +qx.Proto.getRowCount = function() +{ + return this._rowArr.length; +}; + + +qx.Proto.setTreeColumn = function(columnIndex) +{ + this._treeColumn = columnIndex; +} + + +qx.Proto.getTreeColumn = function() +{ + return this._treeColumn; +} + + +qx.Proto.getRowData = function(rowIndex) +{ + return this._rowArr[rowIndex]; +} + + +qx.Proto.getValue = function(columnIndex, rowIndex) +{ + if (rowIndex < 0 || rowIndex >= this._rowArr.length) + { + throw new Error ("this._rowArr row " + + "(" + rowIndex + ") out of bounds: " + + this._rowArr + + " (0.." + + (this._rowArr.length - 1) + ")");b + } + + if (columnIndex < 0 || columnIndex >= this._rowArr[rowIndex].length) + { + throw new Error ("this._rowArr column " + + "(" + columnIndex + ") out of bounds: " + + this._rowArr[rowIndex] + + " (0.." + + (this._rowArr[rowIndex].length - 1) + ")"); + } + + return this._rowArr[rowIndex][columnIndex]; +}; + + +qx.Proto._addNode = function(parentNodeId, + label, + opened, + type, + icon, + iconSelected) +{ + var parentNode; + + // Ensure that if parent was specified, it exists + if (parentNodeId) + { + parentNode = this._nodeArr[parentNodeId]; + if (! parentNode) + { + throw new Error("Request to add a child to a non-existent parent"); + } + + // Ensure parent isn't a leaf + if (parentNode.type == qx.ui.treevirtual.SimpleTreeDataModel.Type.LEAF) + { + throw new Error("Sorry, a LEAF may not have children."); + } + } + else + { + // This is a child of the root + parentNode = this._nodeArr[0]; + parentNodeId = 0; + } + + // If this is a file, we don't present open/close icon + if (type == qx.ui.treevirtual.SimpleTreeDataModel.Type.LEAF && opened) + { + throw new Error("Attempt to display a LEAF opened [" + label + "]"); + } + + // Determine the node id of this new node + var nodeId = this._nodeArr.length; + + // Set the data for this node. + var node = + { + type : type, + parentNodeId : parentNodeId, + label : label, + bSelected : false, + opened : opened, + icon : icon, + iconSelected : iconSelected, + children : [ ], + columnData : [ ] + }; + + // Add this node to the array + this._nodeArr.push(node); + + // Add this node to its parent's child array. + parentNode.children.push(nodeId); + + // Return the node id we just added + return nodeId; +}; + + + +qx.Proto.addBranch = function(parentNodeId, + label, + opened, + icon, + iconSelected) +{ + return this._addNode(parentNodeId, + label, + opened, + qx.ui.treevirtual.SimpleTreeDataModel.Type.BRANCH, + icon, + iconSelected); +}; + + +qx.Proto.addLeaf = function(parentNodeId, + label, + icon, + iconSelected) +{ + return this._addNode(parentNodeId, + label, + false, + qx.ui.treevirtual.SimpleTreeDataModel.Type.LEAF, + icon, + iconSelected); +}; + + +qx.Proto.prune = function(nodeId) +{ + // First, recursively remove all children + for (var i = 0; i < this._nodeArr[nodeId].children.length; i++) + { + this.prune(this._nodeArr[nodeId].children[i]); + } + + // Delete ourself from our parent's children list + var node = this._nodeArr[nodeId]; + qx.lang.Array.remove(this._nodeArr[node.parentNodeId].children, nodeId); + + // Delete ourself from the selections list, if we're in it. + if (this._selections[nodeId]) + { + delete this._selections[nodeId]; + } + + // We can't splice the node itself out, because that would muck up the + // nodeId == index correspondence. Instead, just replace the node with + // null so its index just becomes unused. + this._nodeArr[nodeId] = null; +}; + + + +/** + * Sets the whole data en bulk, or notifies the data model that node + * modifications are complete. + * + * @param nodeArr {Array | null} + * Pass either an Array of node objects, or null. + * + * If non-null, nodeArr is an array of node objects containing the entire + * tree to be displayed. If loading the whole data en bulk in this way, it + * is assumed that the data is correct! No error checking or validation is + * done. You'd better know what you're doing! Caveat emptor. + * + * If nodeArr is null, then this call is a notification that the user has + * completed building or modifying a tree by issuing a series of calls to + * addNode(). + */ +qx.Proto.setData = function(nodeArr) +{ + if (nodeArr instanceof Array) + { + // Determine the set of selected nodes + for (i = 0; i < nodeArr.length; i++) + { + if (nodeArr[i].selected) + { + this._selections[i] = true; + } + } + + // Save the user-supplied data. + this._nodeArr = nodeArr; + } + else if (nodeArr !== null && nodeArr !== undefined) + { + throw new Error("Expected array of node objects or null/undefined; got " + + typeof(nodeArr)); + } + + // Re-render the row array + this._render(); +}; + + +/** + * Return the array of node data. + * + * @return {Array} + * Array of node objects. See {@link qx.ui.treevirtual.SimpleTreeDataModel} + * for a description of each node. + */ +qx.Proto.getData = function() +{ + return this._nodeArr; +}; + + + +/** + * Add data to an additional column of the tree. + * + * @param nodeId + * A node identifier, as previously returned by addBranch() or addLeaf(). + * + * @param columnIndex + * The column number to which the provided data applies + * + * @param data + * The cell data for the specified column + */ +qx.Proto.setColumnData = function(nodeId, columnIndex, data) +{ + this._nodeArr[nodeId].columnData[columnIndex] = data; +} + + +qx.Proto.setState = function(nodeId, attributes) +{ + for (var attribute in attributes) + { + // If the selected state is changing... + if (attribute == "bSelected") + { + // ... then keep track of what is selected + if (attributes[attribute]) + { + this._selections[nodeId] = true; + } + else + { + delete this._selections[nodeId]; + } + } + + this._nodeArr[nodeId][attribute] = attributes[attribute]; + } +}; + + +qx.Proto.getNodeRowMap = function() +{ + return this._nodeRowMap; +}; + + +qx.Proto.clearSelections = function() +{ + // Clear selected state for any selected nodes. + for (var selection in this._selections) + { + this._nodeArr[selection].bSelected = false; + } + + // Reinitialize selections array. + this._selections = { }; +}; + + +qx.Proto.getSelections = function() +{ + return this._selections; +}; + + +/** + * Render (or re-render) the tree. Call this function after having added + * and/or deleted tree nodes (Files or Folders), or after having made changes + * to tree (or tree node) options that will cause the tree to be rendered + * differently. This function should typically be called after a set of + * concurrent changes, not after each change. + */ +qx.Proto._render = function() +{ + var _this = this; + + var inorder = function(nodeId, level) + { + var child = null; + var childNodeId; + + // For each child of the specified node... + var numChildren = _this._nodeArr[nodeId].children.length; + for (var i = 0; i < numChildren; i++) + { + // Determine the node id of this child + childNodeId = _this._nodeArr[nodeId].children[i]; + + // Get the child node + child = _this._nodeArr[childNodeId]; + + // Skip deleted nodes + if (child == null) + { + continue; + } + + // Listeners will need to know a node's id when they receive an event + child.nodeId = childNodeId; + + // (Re-)assign this node's level + child.level = level; + + // Determine if we're the first child of our parent + child.bFirstChild = (i == 0); + + // Determine if we're the last child of our parent + child.lastChild = [ i == numChildren - 1 ]; + + // Get our parent. + var parent = _this._nodeArr[child.parentNodeId]; + + // For each parent node, determine if it is a last child + while (parent.nodeId) + { + var bLast = parent.lastChild[parent.lastChild.length - 1]; + child.lastChild.unshift(bLast); + parent = _this._nodeArr[parent.parentNodeId]; + } + + // Ensure there's an entry in the columnData array for each column + if (! child.columnData) + { + child.columnData = [ ]; + } + + if (child.columnData.length < _this.getColumnCount()) + { + child.columnData[_this.getColumnCount() - 1] = null; + } + + // Add this node to the row array. Initialize a row data array. + var rowData = [ ]; + + // If additional column data is provided... + if (child.columnData) + { + // ... then add each column data. + for (var j = 0; j < child.columnData.length; j++) + { + // Is this the tree column? + if (j == _this._treeColumn) + { + // Yup. Add the tree node data + rowData.push(child); + } + else + { + // Otherwise, add the column data verbatim. + rowData.push(child.columnData[j]); + } + } + } + else + { + // No column data. Just add the tree node. + rowData.push(child); + } + + // If this node is selected, ... + if (child.bSelected) + { + // ... indicate so for the row. + rowData.selected = true; + } + + // Track the _rowArr index for each node so we can handle selections + _this._nodeRowMap[child.nodeId] = _this._rowArr.length; + + // Add the row data to the row array + _this._rowArr.push(rowData) + + // If this child is opened, ... + if (child.opened) + { + // ... then add its children too. + inorder(childNodeId, level + 1); + } + } + } + + // Reset the row array + this._rowArr = []; + + // Reset the _nodeArr -> _rowArr map + this._nodeRowMap = [ ]; + + // Begin in-order traversal of the tree from the root to regenerate _rowArr + inorder(0, 1); + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) + { + var data = + { + firstRow : 0, + lastRow : this._rowArr.length - 1, + firstColumn : 0, + lastColumn : this.getColumnCount() - 1 + }; + + this.dispatchEvent(new qx.event.type.DataEvent( + qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, + data), + true); + } +}; + + +// We currently support these types of tree nodes +qx.Class.Type = {}; +qx.Class.Type.LEAF = 1; +qx.Class.Type.BRANCH = 2; + diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataRowRenderer.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataRowRenderer.js new file mode 100644 index 0000000000..33ae27110a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/SimpleTreeDataRowRenderer.js @@ -0,0 +1,61 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(treevirtual) + +************************************************************************ */ + +/** + * A data row renderer for a simple tree row + */ +qx.OO.defineClass("qx.ui.treevirtual.SimpleTreeDataRowRenderer", + qx.ui.table.DefaultDataRowRenderer, +function() +{ + qx.ui.table.DefaultDataRowRenderer.call(this); +}); + + +// overridden +qx.Proto.updateDataRowElement = function(rowInfo, rowElem) +{ + // If the node is selected, select the row + var tree = rowInfo.table; + var rowData = rowInfo.rowData; + var tableModel = tree.getTableModel(); + var treeCol = tableModel.getTreeColumn(); + var node = rowData[treeCol]; + + // Set the row's selected state based on the data model + rowInfo.selected = node.bSelected; + + if (node.bSelected) + { + // Ensure that the selection model knows it's selected + var nodeRowMap = tableModel.getNodeRowMap(); + var row = nodeRowMap[node.nodeId]; + tree.getSelectionModel()._addSelectionInterval(row, row); + } + + // Now call our superclass + var ddrr = qx.ui.table.DefaultDataRowRenderer; + ddrr.prototype.updateDataRowElement.call(this, rowInfo, rowElem); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/TreeVirtual.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/TreeVirtual.js new file mode 100644 index 0000000000..0acf87f56f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/treevirtual/TreeVirtual.js @@ -0,0 +1,634 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(treevirtual) + +************************************************************************ */ + +/** + * A "virtual" tree + * + * @event treeOpenWithContent {qx.event.type.DataEvent} + * @event treeOpenWhileEmpty {qx.event.type.DataEvent} + * @event treeClose {qx.event.type.DataEvent} + * @event changeSelection {qx.event.type.Event} + * + * WARNING: This widget is in active development and the interface to it is + * very likely to change, possibly on a daily basis, for a while. Do + * not use this widget yet. + * + */ +qx.OO.defineClass("qx.ui.treevirtual.TreeVirtual", qx.ui.table.Table, +function(headings) +{ + // Create a table model + var tableModel = new qx.ui.treevirtual.SimpleTreeDataModel(); + + // Specify the column headings. We accept a single string (one single + // column) or an array of strings (one or more columns). + if (typeof(headings) == "string") + { + headings = [ headings ]; + } + tableModel.setColumns(headings); + + // Call our superclass constructor + qx.ui.table.Table.call(this, tableModel); + + // Set sizes + this.setRowHeight(16); + this.setMetaColumnCounts([1, -1]); + + // Set the data cell render. We use the SimpleTreeDataCellRenderer for the + // tree column, and our DefaultDataCellRenderer for all other columns. + var stdcr = new qx.ui.treevirtual.SimpleTreeDataCellRenderer(); + var ddcr = new qx.ui.treevirtual.DefaultDataCellRenderer(); + var tcm = this.getTableColumnModel(); + var treeCol = this.getTableModel().getTreeColumn(); + for (var i = 0; i < headings.length; i++) + { + tcm.setDataCellRenderer(i, i == treeCol ? stdcr : ddcr); + } + + // Set the data row renderer. + this.setDataRowRenderer(new qx.ui.treevirtual.SimpleTreeDataRowRenderer()); + + // We need our cell renderer called on selection change, to update the icon + this.setAlwaysUpdateCells(true); + + // Move the focus with the mouse + this.setFocusCellOnMouseMove(true); + + // Change focus colors. Make them less obtrusive. + this.setRowColors( + { + bgcolFocused : "#f0f0f0", + bgcolFocusedBlur : "#f0f0f0" + }); + +/* + // Use this instead, to help determine which does what + this.setRowColors( + { + bgcolFocusedSelected : "cyan", + bgcolFocusedSelectedBlur : "green", + bgcolFocused : "yellow", + bgcolFocusedBlur : "blue", + bgcolSelected : "red", + bgcolSelectedBlur : "pink", + }); +*/ + + // Remove the outline on focus. + // + // KLUDGE ALERT: I really want to remove the old appearance, but I don't + // know how to do that. Instead, for the moment, I'll just use an existing + // appearance that won't affect the focus indicator, making the appearance + // effectively a no-op. + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) + { + scrollerArr[i]._focusIndicator.setAppearance("image"); + + // Set the pane scrollers to handle the selection before displaying the + // focus, so we can manipulate the selected icon. + scrollerArr[i].setSelectBeforeFocus(true); + } + + // Arrange to select events locally. Replace the selection manager's method + // with one that calls our _handleSelectEvent method first, and it it + // indicates we should actually select the row, then call the selection + // manager's method. Our method handles deciding if the click was on the + // open/close button, and toggling the opened/closed state as necessary. + // The selection manager's method handles marking the selected row. + var _this = this; + this._getSelectionManager()._handleSelectEvent = function(index, evt) + { + var Sm = qx.ui.table.SelectionManager; + var Tv = qx.ui.treevirtual.TreeVirtual; + + // Call our local method to toggle the open/close state, if necessary + var bNoSelect = Tv.prototype._handleSelectEvent.call(_this, index, evt); + + // If we haven't been told not to do the selection... + if (! bNoSelect) + { + // then call the Selection Manager's method to do it. + Sm.prototype._handleSelectEvent.call(_this, index, evt); + } + }; +}); + + +/** + * Whether a click on the open/close button should also cause selection of the + * row. + */ +qx.OO.addProperty( + { + name : "openCloseClickSelectsRow", + type : "boolean", + defaultValue : false, + getAlias : "openCloseClickSelectsRow" + }); + + +/** + * Return the data model for this tree. + */ +qx.Proto.getDataModel = function() +{ + return this.getTableModel(); +}; + + +/** + * Set whether lines linking tree children shall be drawn on the tree. + * + * @param b {Boolean} + * <i>true</i> if tree lines should be shown; <i>false</i> otherwise. + */ +qx.Proto.setUseTreeLines = function(b) +{ + var stdcm = this.getTableModel(); + var treeCol = stdcm.getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + dcr.setUseTreeLines(b); + + // Inform the listeners + if (stdcm.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) + { + var data = + { + firstRow : 0, + lastRow : stdcm._rowArr.length - 1, + firstColumn : 0, + lastColumn : stdcm.getColumnCount() - 1 + }; + + stdcm.dispatchEvent(new qx.event.type.DataEvent( + qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, + data), + true); + } +}; + + +/** + * Get whether lines linking tree children shall be drawn on the tree. + * + * @return {Boolean} + * <i>true</i> if tree lines are in use; <i>false</i> otherwise. + */ +qx.Proto.getUseTreeLines = function() +{ + var treeCol = this.getTableModel().getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + return dcr.getUseTreeLines(); +} + + +/** + * Set whether the open/close button should be displayed on a branch, even if + * the branch has no children. + * + * @param b {Boolean} + * <i>true</i> if the open/close button should be shown; <i>false</i> + * otherwise. + */ +qx.Proto.setAlwaysShowOpenCloseSymbol = function(b) +{ + var stdcm = this.getTableModel(); + var treeCol = stdcm.getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + dcr.setAlwaysShowOpenCloseSymbol(b); + + // Inform the listeners + if (stdcm.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) + { + var data = + { + firstRow : 0, + lastRow : stdcm._rowArr.length - 1, + firstColumn : 0, + lastColumn : stdcm.getColumnCount() - 1 + }; + + stdcm.dispatchEvent(new qx.event.type.DataEvent( + qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, + data), + true); + } +}; + + +/** + * Set whether drawing of first-level tree-node lines are disabled. + * + * @param b {Boolean} + * <i>true</i> if first-level tree lines should be disabled; + * <i>false</i> for normal operation. + */ +qx.Proto.setJensLautenbacherMode = function(b) +{ + var stdcm = this.getTableModel(); + var treeCol = stdcm.getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + dcr.setJensLautenbacherMode(b); + + // Inform the listeners + if (stdcm.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) + { + var data = + { + firstRow : 0, + lastRow : stdcm._rowArr.length - 1, + firstColumn : 0, + lastColumn : stdcm.getColumnCount() - 1 + }; + + stdcm.dispatchEvent(new qx.event.type.DataEvent( + qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, + data), + true); + } +}; + + +/** + * Get whether drawing of first-level tree lines should be disabled + * + * @return {Boolean} + * <i>true</i> if tree lines are in use; <i>false</i> otherwise. + */ +qx.Proto.getJensLautenbacherMode = function() +{ + var treeCol = this.getTableModel().getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + return dcr.getJensLautenbacherMode(); +} + + +/** + * Set whether the open/close button should be displayed on a branch, even if + * the branch has no children. + * + * @return {Boolean} + * <i>true</i> if tree lines are in use; <i>false</i> otherwise. + */ +qx.Proto.getAlwaysShowOpenCloseSymbol = function() +{ + var treeCol = this.getTableModel().getTreeColumn(); + var dcr = this.getTableColumnModel().getDataCellRenderer(treeCol); + return dcr.getAlwaysShowOpenCloseSymbol(); +}; + + +qx.Proto.setSelectionMode = function(mode) +{ + this.getSelectionModel().setSelectionMode(mode); +} + + +qx.Proto.getSelectionMode = function(mode) +{ + return this.getSelectionModel().getSelectionMode(); +} + + +/** + * Toggle the opened state of the node: if the node is opened, close + * it; if it is closed, open it. + * + * @param node {Object} + * The object representing the node to have its opened/closed state + * toggled. + */ +qx.Proto.toggleOpened = function(node) +{ + // Ignore toggle request if 'opened' is not a boolean (i.e. we've been + // told explicitely not to display the open/close button). + if (node.opened !== true && node.opened !== false) + { + return; + } + + // Are we opening or closing? + if (node.opened) + { + // We're closing. If there are listeners, generate a treeClose event. + this.createDispatchDataEvent("treeClose", node); + } + else + { + // We're opening. Are there any children? + if (node.children.length > 0) + { + // Yup. If there any listeners, generate a "treeOpenWithContent" event. + this.createDispatchDataEvent("treeOpenWithContent", node); + } + else + { + // No children. If there are listeners, generate a "treeOpenWhileEmpty" + // event. + this.createDispatchDataEvent("treeOpenWhileEmpty", node); + } + } + + // Event handler may have modified the opened state. Check before toggling. + if (node.opened === true || node.opened === false) + { + // It's still boolean. Toggle the state + node.opened = ! node.opened; + + // Get the selection model + var sm = this.getSelectionModel(); + + // Clear the old selections in the tree + this.getSelectionModel()._clearSelection(); + + // Clear the old selections in the data model + this.getTableModel().clearSelections(); + } + + // Re-render the row data since formerly visible rows may now be invisible, + // or vice versa. + this.getTableModel()._render(); +}; + + +/** + * Set state attributes of a tree node. + * + * @param nodeId {Integer} + * The node identifier (returned by addBranch() or addLeaf()) representing + * the node for which attributes are being set. + * + * @param attributes {Map} + * Map with the node properties to be set. The map may contain any of the + * properties described in {@link qx.ui.treevirtual.SimpleTreeDataModel} + */ +qx.Proto.setState = function(nodeId, attributes) +{ + this.getTableModel().setState(nodeId, attributes); +}; + + +/** + * Allow setting the tree row colors. + * + * @param colors {Map} + * The value of each property in the map is a string containing either a + * number (e.g. "#518ad3") or color name ("white") representing the color + * for that type of display. The map may contain any or all of the + * following properties: + * <ul> + * <li>bgcolFocusedSelected</li> + * <li>bgcolFocusedSelectedBlur</li> + * <li>bgcolFocused</li> + * <li>bgcolFocusedBlur</li> + * <li>bgcolSelected</li> + * <li>bgcolSelectedBlur</li> + * <li>bgcolEven</li> + * <li>bgcolOdd</li> + * <li>colSelected</li> + * <li>colNormal</li> + * </ul> + */ +qx.Proto.setRowColors = function(colors) +{ + this.getDataRowRenderer().setRowColors(colors); +}; + + +/** + * Event handler. Called when a key was pressed. + * + * We handle the Enter key to toggle opened/closed tree state. All + * other keydown events are passed to our superclass. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeydown = function(evt) +{ + var identifier = evt.getKeyIdentifier(); + + var consumed = false; + if (evt.getModifiers() == 0) + { + switch (identifier) + { + case "Enter": + var node = this.getTableModel().getValue(this.getFocusedColumn(), + this.getFocusedRow()); + + this.toggleOpened(node); + consumed = true; + break; + } + } + + // Was this one of our events that we handled? + if (consumed) + { + // Yup. Don't propagate it. + evt.preventDefault(); + evt.stopPropagation(); + } + else + { + // It's not one of ours. Let our superclass handle this event + qx.ui.table.Table.prototype._onkeydown.call(this, evt); + } +}; + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) +{ + // Clear the old list of selected nodes + this.getTableModel().clearSelections(); + + // If selections are allowed, pass an event to our listeners + if (this.getSelectionMode() != + qx.ui.treevirtual.TreeVirtual.SelectionMode.NONE) + { + var selectedNodes = this._calculateSelectedNodes(); + + // Get the now-focused + this.createDispatchDataEvent("changeSelection", selectedNodes); + } + + // Call the superclass method + qx.ui.table.Table.prototype._onSelectionChanged.call(this, evt); +}; + + +/** + * Handles the a selection event + * + * @param index {Integer} + * The row index the mouse is pointing at. + * + * @param evt {Map} + * The mouse event. + * + * @return {Boolean} + * Returns <i>true</i> if the event was a click on the open/close button, + * <i>false</i> otherwise. + */ +qx.Proto._handleSelectEvent = function(index, evt) +{ + // Get the node to which this event applies + var node = this.getTableModel().getValue(this.getFocusedColumn(), + this.getFocusedRow()); + if (! node) + { + return false; + } + + // Was this a mouse event? + if (evt instanceof qx.event.type.MouseEvent) + { + // Yup. Get the order of the columns + var tcm = this.getTableColumnModel(); + var columnPositions = tcm._getColToXPosMap(); + + // Calculate the position of the beginning of the tree column + var treeCol = this.getTableModel().getTreeColumn(); + var left = 0; + for (i = 0; i < columnPositions[treeCol].visX; i++) + { + left += tcm.getColumnWidth(columnPositions[i].visX); + } + + // Was the click on the open/close button? That button begins at + // (node.level - 1) * 19 + 2 (the latter for padding), and has width 19. + // We add a bit of latitude to that. + var x = evt.getClientX(); + var latitude = 2; + + var buttonPos = left + (node.level - 1) * 19 + 2; + + if (x >= buttonPos - latitude && x <= buttonPos + 19 + latitude) + { + // Yup. Toggle the opened state for this node. + this.toggleOpened(node); + return true; + } + } + else + { + // Key event. Toggle the open state + this.toggleOpened(node); + return true; + } + + return this.openCloseClickSelectsRow() ? true : false; +}; + + +qx.Proto.getHierarchy = function(nodeId) +{ + var _this = this; + var components = [ ]; + + function addHierarchy(nodeId) + { + // If we're at the root... + if (! nodeId) + { + // ... then we're done + return; + } + + // Get the requested node + var node = _this.getTableModel().getData()[nodeId]; + + // Add its label to the hierarchy components + components.unshift(node.label); + + // Call recursively to our parent node. + addHierarchy(node.parentNodeId); + } + + addHierarchy(nodeId); + return components; +} + + +qx.Proto._calculateSelectedNodes = function() +{ + // Create an array of nodes that are now selected + var stdcm = this.getTableModel(); + var selectedRanges = this.getSelectionModel().getSelectedRanges(); + var selectedNodes = [ ]; + var node; + + for (var i = 0; i < selectedRanges.length; i++) + { + for (var j = selectedRanges[i].minIndex; + j <= selectedRanges[i].maxIndex; + j++) + { + node = stdcm.getValue(stdcm.getTreeColumn(), j); + stdcm.setState(node.nodeId, { bSelected : true }); + selectedNodes.push(node); + } + } + + return selectedNodes; +}; + + +/* + * Selection Modes {int} + * + * NONE + * Nothing can ever be selected. + * + * SINGLE + * Allow only one selected item. + * + * SINGLE_INTERVAL + * Allow one contiguous interval of selected items. + * + * MULTIPLE_INTERVAL + * Allow any set of selected items, whether contiguous or not. + */ +qx.Class.SelectionMode = +{ + NONE : + qx.ui.table.SelectionModel.NO_SELECTION, + + SINGLE : + qx.ui.table.SelectionModel.SINGLE_SELECTION, + + SINGLE_INTERVAL : + qx.ui.table.SelectionModel.SINGLE_INTERVAL_SELECTION, + + MULTIPLE_INTERVAL : + qx.ui.table.SelectionModel.MULTIPLE_INTERVAL_SELECTION +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/window/Window.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/window/Window.js new file mode 100644 index 0000000000..fa79b5173a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/ui/window/Window.js @@ -0,0 +1,1441 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_window) +#embed(qx.widgettheme/window/*) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.window.Window", qx.ui.popup.Popup, +function(vCaption, vIcon, vWindowManager) +{ + qx.ui.popup.Popup.call(this); + + // ************************************************************************ + // FUNCTIONAL STYLE + // ************************************************************************ + + this.setMinWidth("auto"); + this.setMinHeight("auto"); + this.setAutoHide(false); + + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + + // Init Window Manager + this.setWindowManager(vWindowManager || qx.ui.window.Window.getDefaultWindowManager()); + + + + // ************************************************************************ + // RESIZE AND MOVE FRAME + // ************************************************************************ + + var f = this._frame = new qx.ui.basic.Terminator; + f.setAppearance("window-resize-frame"); + + + // ************************************************************************ + // LAYOUT + // ************************************************************************ + + var l = this._layout = new qx.ui.layout.VerticalBoxLayout; + l.setEdge(0); + this.add(l); + + + // ************************************************************************ + // CAPTIONBAR + // ************************************************************************ + + var cb = this._captionBar = new qx.ui.layout.HorizontalBoxLayout; + cb.setAppearance("window-captionbar"); + l.add(cb); + + + // ************************************************************************ + // CAPTIONICON + // ************************************************************************ + + if (vIcon != null) + { + var ci = this._captionIcon = new qx.ui.basic.Image(vIcon); + ci.setAppearance("window-captionbar-icon"); + cb.add(ci); + } + + + // ************************************************************************ + // CAPTIONTITLE + // ************************************************************************ + + var ct = this._captionTitle = new qx.ui.basic.Label(vCaption); + ct.setAppearance("window-captionbar-title"); + ct.setSelectable(false); + cb.add(ct); + + + // ************************************************************************ + // CAPTIONFLEX + // ************************************************************************ + + var cf = this._captionFlex = new qx.ui.basic.HorizontalSpacer; + cb.add(cf); + + + // ************************************************************************ + // CAPTIONBUTTONS: MINIMIZE + // ************************************************************************ + + var bm = this._minimizeButton = new qx.ui.form.Button(null, "widget/window/minimize.gif"); + + bm.setAppearance("window-captionbar-minimize-button"); + bm.setTabIndex(-1); + + bm.addEventListener("execute", this._onminimizebuttonclick, this); + bm.addEventListener("mousedown", this._onbuttonmousedown, this); + + cb.add(bm); + + + // ************************************************************************ + // CAPTIONBUTTONS: RESTORE + // ************************************************************************ + + var br = this._restoreButton = new qx.ui.form.Button(null, "widget/window/restore.gif"); + + br.setAppearance("window-captionbar-restore-button"); + br.setTabIndex(-1); + + br.addEventListener("execute", this._onrestorebuttonclick, this); + br.addEventListener("mousedown", this._onbuttonmousedown, this); + + // don't add initially + // cb.add(br); + + + // ************************************************************************ + // CAPTIONBUTTONS: MAXIMIZE + // ************************************************************************ + + var bx = this._maximizeButton = new qx.ui.form.Button(null, "widget/window/maximize.gif"); + + bx.setAppearance("window-captionbar-maximize-button"); + bx.setTabIndex(-1); + + bx.addEventListener("execute", this._onmaximizebuttonclick, this); + bx.addEventListener("mousedown", this._onbuttonmousedown, this); + + cb.add(bx); + + + // ************************************************************************ + // CAPTIONBUTTONS: CLOSE + // ************************************************************************ + + var bc = this._closeButton = new qx.ui.form.Button(null, "widget/window/close.gif"); + + bc.setAppearance("window-captionbar-close-button"); + bc.setTabIndex(-1); + + bc.addEventListener("execute", this._onclosebuttonclick, this); + bc.addEventListener("mousedown", this._onbuttonmousedown, this); + + cb.add(bc); + + + // ************************************************************************ + // PANE + // ************************************************************************ + + var p = this._pane = new qx.ui.layout.CanvasLayout; + p.setHeight("1*"); + p.setOverflow("hidden"); + l.add(p); + + + // ************************************************************************ + // STATUSBAR + // ************************************************************************ + + var sb = this._statusBar = new qx.ui.layout.HorizontalBoxLayout; + sb.setAppearance("window-statusbar"); + + + // ************************************************************************ + // STATUSTEXT + // ************************************************************************ + + var st = this._statusText = new qx.ui.basic.Label("Ready"); + st.setAppearance("window-statusbar-text"); + st.setSelectable(false); + sb.add(st); + + + // ************************************************************************ + // INIT + // ************************************************************************ + + this.setCaption(vCaption); + this.setIcon(vIcon); + + + // ************************************************************************ + // EVENTS: WINDOW + // ************************************************************************ + + this.addEventListener("mousedown", this._onwindowmousedown, this); + this.addEventListener("mouseup", this._onwindowmouseup, this); + this.addEventListener("mousemove", this._onwindowmousemove, this); + this.addEventListener("click", this._onwindowclick, this); + + + // ************************************************************************ + // EVENTS: CAPTIONBAR + // ************************************************************************ + + cb.addEventListener("mousedown", this._oncaptionmousedown, this); + cb.addEventListener("mouseup", this._oncaptionmouseup, this); + cb.addEventListener("mousemove", this._oncaptionmousemove, this); + cb.addEventListener("dblclick", this._oncaptiondblblick, this); + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + this.remapChildrenHandlingTo(this._pane); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "window" }); + +/*! + The windowManager to use for. +*/ +qx.OO.addProperty({ name : "windowManager", type : "object" }); + +/*! + If the window is active, only one window in a single qx.manager.object.WindowManager could + have set this to true at the same time. +*/ +qx.OO.addProperty({ name : "active", type : "boolean", defaultValue : false }); + +/*! + Should be window be modal (this disable minimize and maximize buttons) +*/ +qx.OO.addProperty({ name : "modal", type : "boolean", defaultValue : false }); + +/*! + Should be window be modal (this disable minimize and maximize buttons) +*/ +qx.OO.addProperty({ name : "mode", type : "string", defaultValue : null, possibleValues : [ "minimized", "maximized" ], allowNull : true }); + +/*! + The opener (button) of the window +*/ +qx.OO.addProperty({ name : "opener", type : "object" }); + +/*! + The text of the caption +*/ +qx.OO.addProperty({ name : "caption" }); + +/*! + The icon of the caption +*/ +qx.OO.addProperty({ name : "icon", type : "string" }); + +/*! + The text of the statusbar +*/ +qx.OO.addProperty({ name : "status", type : "string", defaultValue : "Ready" }); + +/*! + Should the close button be shown +*/ +qx.OO.addProperty({ name : "showClose", type : "boolean", defaultValue : true }); + +/*! + Should the maximize button be shown +*/ +qx.OO.addProperty({ name : "showMaximize", type : "boolean", defaultValue : true }); + +/*! + Should the minimize button be shown +*/ +qx.OO.addProperty({ name : "showMinimize", type : "boolean", defaultValue : true }); + +/*! + Should the statusbar be shown +*/ +qx.OO.addProperty({ name : "showStatusbar", type : "boolean", defaultValue : false }); + +/*! + Should the user have the ability to close the window +*/ +qx.OO.addProperty({ name : "allowClose", type : "boolean", defaultValue : true }); + +/*! + Should the user have the ability to maximize the window +*/ +qx.OO.addProperty({ name : "allowMaximize", type : "boolean", defaultValue : true }); + +/*! + Should the user have the ability to minimize the window +*/ +qx.OO.addProperty({ name : "allowMinimize", type : "boolean", defaultValue : true }); + +/*! + If the text (in the captionbar) should be visible +*/ +qx.OO.addProperty({ name : "showCaption", type : "boolean", defaultValue : true }); + +/*! + If the icon (in the captionbar) should be visible +*/ +qx.OO.addProperty({ name : "showIcon", type : "boolean", defaultValue : true }); + +/*! + If the window is resizeable +*/ +qx.OO.addProperty({ name : "resizeable", type : "boolean", defaultValue : true }); + +/*! + If the window is moveable +*/ +qx.OO.addProperty({ name : "moveable", type : "boolean", defaultValue : true }); + +/*! + The resize method to use +*/ +qx.OO.addProperty({ name : "resizeMethod", type : "string", defaultValue : "frame", possibleValues : [ "opaque", "lazyopaque", "frame", "translucent" ] }); + +/*! + The move method to use +*/ +qx.OO.addProperty({ name : "moveMethod", type : "string", defaultValue : "opaque", possibleValues : [ "opaque", "frame", "translucent" ] }); + + + + +/* +--------------------------------------------------------------------------- + MANAGER HANDLING +--------------------------------------------------------------------------- +*/ + +qx.ui.window.Window.getDefaultWindowManager = function() +{ + if (!qx.ui.window.Window._defaultWindowManager) { + qx.ui.window.Window._defaultWindowManager = new qx.manager.object.WindowManager; + } + + return qx.ui.window.Window._defaultWindowManager; +} + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPane = function() { + return this._pane; +} + +qx.Proto.getCaptionBar = function() { + return this._captionBar; +} + +qx.Proto.getStatusBar = function() { + return this._statusBar; +} + +qx.Proto.close = function() { + this.hide(); +} + +qx.Proto.open = function(vOpener) +{ + if (vOpener != null) { + this.setOpener(vOpener); + } + + if (this.getCentered()) { + this.centerToBrowser(); + } + + this.show(); +} + +qx.Proto.focus = function() { + this.setActive(true); +} + +qx.Proto.blur = function() { + this.setActive(false); +} + +qx.Proto.maximize = function() { + this.setMode("maximized"); +} + +qx.Proto.minimize = function() { + this.setMode("minimized"); +} + +qx.Proto.restore = function() { + this.setMode(null); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + // Intentionally bypass superclass and call super.super._beforeAppear + qx.ui.layout.CanvasLayout.prototype._beforeAppear.call(this); + + // Hide popups + qx.manager.object.PopupManager.getInstance().update(); + + // Configure the focus root to be the current opened window + qx.event.handler.EventHandler.getInstance().setFocusRoot(this); + + this.getWindowManager().add(this); + this._makeActive(); +} + +qx.Proto._beforeDisappear = function() +{ + // Intentionally bypass superclass and call super.super._beforeDisappear + qx.ui.layout.CanvasLayout.prototype._beforeDisappear.call(this); + + // Reset focus root + var vFocusRoot = qx.event.handler.EventHandler.getInstance().getFocusRoot(); + if (vFocusRoot == this || this.contains(vFocusRoot)) { + qx.event.handler.EventHandler.getInstance().setFocusRoot(null); + } + + // Be sure to disable any capturing inside invisible parts + // Is this to much overhead? + // Are there any other working solutions? + var vWidget = qx.event.handler.EventHandler.getInstance().getCaptureWidget(); + if (vWidget && this.contains(vWidget)) { + vWidget.setCapture(false); + } + + this.getWindowManager().remove(this); + this._makeInactive(); +} + + + + + +/* +--------------------------------------------------------------------------- + ZIndex Positioning +--------------------------------------------------------------------------- +*/ + +qx.Proto._minZIndex = 1e5; + +qx.Proto._sendTo = function() +{ + var vAll = qx.lang.Object.getValues(this.getWindowManager().getAll()).sort(qx.util.Compare.byZIndex); + var vLength = vAll.length; + var vIndex = this._minZIndex; + + for (var i=0; i<vLength; i++) { + vAll[i].setZIndex(vIndex++); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyActive = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + if (this.getFocused()) { + this.setFocused(false); + } + + if (this.getWindowManager().getActiveWindow() == this) { + this.getWindowManager().setActiveWindow(null); + } + + this.removeState("active"); + this._captionBar.removeState("active"); + } + else + { + // Switch focus + // Also do this if gets inactive as this moved the focus outline + // away from any focused child. + if (!this.getFocusedChild()) { + this.setFocused(true); + } + + this.getWindowManager().setActiveWindow(this); + this.bringToFront(); + + this.addState("active"); + this._captionBar.addState("active"); + } + + return true; +} + +qx.Proto._modifyModal = function(propValue, propOldValue, propData) +{ + // Inform blocker + if (this._initialLayoutDone && this.getVisibility() && this.getDisplay()) + { + var vTop = this.getTopLevelWidget(); + propValue ? vTop.block(this) : vTop.release(this); + } + + return true; +} + +qx.Proto._modifyAllowClose = function(propValue, propOldValue, propData) { + return this._closeButtonManager(); +} + +qx.Proto._modifyAllowMaximize = function(propValue, propOldValue, propData) { + return this._maximizeButtonManager(); +} + +qx.Proto._modifyAllowMinimize = function(propValue, propOldValue, propData) { + return this._minimizeButtonManager(); +} + +qx.Proto._modifyMode = function(propValue, propOldValue, propData) +{ + switch(propValue) + { + case "minimized": + this._minimize(); + break; + + case "maximized": + this._maximize(); + break; + + default: + switch(propOldValue) + { + case "maximized": + this._restoreFromMaximized(); + break; + + case "minimized": + this._restoreFromMinimized(); + break; + } + } + + return true; +} + +qx.Proto._modifyShowCaption = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._captionBar.addAt(this._captionTitle, this.getShowIcon() ? 1 : 0); + } + else + { + this._captionBar.remove(this._captionTitle); + } + + return true; +} + +qx.Proto._modifyShowIcon = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._captionBar.addAtBegin(this._captionIcon); + } + else + { + this._captionBar.remove(this._captionIcon); + } + + return true; +} + +qx.Proto._modifyShowStatusbar = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._layout.addAtEnd(this._statusBar); + } + else + { + this._layout.remove(this._statusBar); + } + + return true; +} + +qx.Proto._modifyShowClose = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._captionBar.addAtEnd(this._closeButton); + } + else + { + this._captionBar.remove(this._closeButton); + } + + return true; +} + +qx.Proto._modifyShowMaximize = function(propValue, propOldValue, propData) +{ + if (propValue) + { + var t = this.getMode() == "maximized" ? this._restoreButton : this._maximizeButton; + + if (this.getShowMinimize()) + { + this._captionBar.addAfter(t, this._minimizeButton); + } + else + { + this._captionBar.addAfter(t, this._captionFlex); + } + } + else + { + this._captionBar.remove(this._maximizeButton); + this._captionBar.remove(this._restoreButton); + } + + return true; +} + +qx.Proto._modifyShowMinimize = function(propValue, propOldValue, propData) +{ + if (propValue) + { + this._captionBar.addAfter(this._minimizeButton, this._captionFlex); + } + else + { + this._captionBar.remove(this._minimizeButton); + } + + return true; +} + +qx.Proto._minimizeButtonManager = function() +{ + this._minimizeButton.setEnabled(this.getAllowMinimize()); + + return true; +} + +qx.Proto._closeButtonManager = function() +{ + this._closeButton.setEnabled(this.getAllowClose()); + + return true; +} + +qx.Proto._maximizeButtonManager = function() +{ + var b = this.getAllowMaximize() && this.getResizeable() && this._computedMaxWidthTypeNull && this._computedMaxHeightTypeNull; + + this._maximizeButton.setEnabled(b); + this._restoreButton.setEnabled(b); + + return true; +} + +qx.Proto._modifyStatus = function(propValue, propOldValue, propData) +{ + this._statusText.setHtml(propValue); + + return true; +} + +qx.Proto._modifyMaxWidth = function(propValue, propOldValue, propData) { + return this._maximizeButtonManager(); +} + +qx.Proto._modifyMaxHeight = function(propValue, propOldValue, propData) { + return this._maximizeButtonManager(); +} + +qx.Proto._modifyResizeable = function(propValue, propOldValue, propData) { + return this._maximizeButtonManager(); +} + +qx.Proto._modifyCaption = function(propValue, propOldValue, propData) +{ + this._captionTitle.setHtml(propValue); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + STATE LAYOUT IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._minimize = function() +{ + this.blur(); + this.hide(); +} + +qx.Proto._restoreFromMaximized = function() +{ + // restore previous dimension and location + this.setLeft(this._previousLeft ? this._previousLeft : null); + this.setWidth(this._previousWidth ? this._previousWidth : null); + this.setRight(this._previousRight ? this._previousRight : null); + + this.setTop(this._previousTop ? this._previousTop : null); + this.setHeight(this._previousHeight ? this._previousHeight : null); + this.setBottom(this._previousBottom ? this._previousBottom : null); + + // update state + this.removeState("maximized"); + + // toggle button + if (this.getShowMaximize()) + { + var cb = this._captionBar; + var v = cb.indexOf(this._restoreButton); + + cb.remove(this._restoreButton); + cb.addAt(this._maximizeButton, v); + } + + // finally focus the window + this.focus(); +} + +qx.Proto._restoreFromMinimized = function() +{ + if (this.hasState("maximized")) + { + this.setMode("maximized"); + } + + this.show(); + this.focus(); +} + +qx.Proto._maximize = function() +{ + if (this.hasState("maximized")) + { + return; + } + + // store current dimension and location + this._previousLeft = this.getLeft(); + this._previousWidth = this.getWidth(); + this._previousRight = this.getRight(); + this._previousTop = this.getTop(); + this._previousHeight = this.getHeight(); + this._previousBottom = this.getBottom(); + + // setup new dimension and location + this.setWidth(null); + this.setLeft(0); + this.setRight(0); + this.setHeight(null); + this.setTop(0); + this.setBottom(0); + + // update state + this.addState("maximized"); + + // toggle button + if (this.getShowMaximize()) + { + var cb = this._captionBar; + var v = cb.indexOf(this._maximizeButton); + + cb.remove(this._maximizeButton); + cb.addAt(this._restoreButton, v); + } + + // finally focus the window + this.focus(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: WINDOW +--------------------------------------------------------------------------- +*/ + +qx.Proto._onwindowmousedown = function(e) +{ + this.focus(); + + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + // enable capturing + this.setCapture(true); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor(this.getCursor()); + + // caching element + var el = this.getElement(); + + // measuring and caching of values for resize session + var pa = this.getParent(); + var pl = pa.getElement(); + + var l = qx.html.Location.getPageAreaLeft(pl); + var t = qx.html.Location.getPageAreaTop(pl); + var r = qx.html.Location.getPageAreaRight(pl); + var b = qx.html.Location.getPageAreaBottom(pl); + + // handle frame and translucently + switch(this.getResizeMethod()) + { + case "translucent": + this.setOpacity(0.5); + break; + + case "frame": + var f = this._frame; + + if (f.getParent() != this.getParent()) + { + f.setParent(this.getParent()); + qx.ui.core.Widget.flushGlobalQueues(); + } + + f._applyRuntimeLeft(qx.html.Location.getPageBoxLeft(el) - l); + f._applyRuntimeTop(qx.html.Location.getPageBoxTop(el) - t); + + f._applyRuntimeWidth(qx.html.Dimension.getBoxWidth(el)); + f._applyRuntimeHeight(qx.html.Dimension.getBoxHeight(el)); + + f.setZIndex(this.getZIndex() + 1); + + break; + } + + // create resize session + var s = this._resizeSession = {}; + + if (this._resizeWest) + { + s.boxWidth = qx.html.Dimension.getBoxWidth(el); + s.boxRight = qx.html.Location.getPageBoxRight(el); + } + + if (this._resizeWest || this._resizeEast) + { + s.boxLeft = qx.html.Location.getPageBoxLeft(el); + + s.parentAreaOffsetLeft = l; + s.parentAreaOffsetRight = r; + + s.minWidth = this.getMinWidthValue(); + s.maxWidth = this.getMaxWidthValue(); + } + + if (this._resizeNorth) + { + s.boxHeight = qx.html.Dimension.getBoxHeight(el); + s.boxBottom = qx.html.Location.getPageBoxBottom(el); + } + + if (this._resizeNorth || this._resizeSouth) + { + s.boxTop = qx.html.Location.getPageBoxTop(el); + + s.parentAreaOffsetTop = t; + s.parentAreaOffsetBottom = b; + + s.minHeight = this.getMinHeightValue(); + s.maxHeight = this.getMaxHeightValue(); + } + } + else + { + // cleanup resize session + delete this._resizeSession; + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._onwindowmouseup = function(e) +{ + var s = this._resizeSession; + + if (s) + { + // disable capturing + this.setCapture(false); + + // deactivate global cursor + this.getTopLevelWidget().setGlobalCursor(null); + + // sync sizes to frame + switch(this.getResizeMethod()) + { + case "frame": + var o = this._frame; + if (!(o && o.getParent())) { + break; + } + // no break here + + case "lazyopaque": + if (s.lastLeft != null) { + this.setLeft(s.lastLeft); + } + + if (s.lastTop != null) { + this.setTop(s.lastTop); + } + + if (s.lastWidth != null) { + this.setWidth(s.lastWidth); + } + + if (s.lastHeight != null) { + this.setHeight(s.lastHeight); + } + + if (this.getResizeMethod() == "frame") { + this._frame.setParent(null); + } + break; + + case "translucent": + this.setOpacity(null); + break; + } + + // cleanup session + delete this._resizeNorth; + delete this._resizeEast; + delete this._resizeSouth; + delete this._resizeWest; + + delete this._resizeSession; + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._near = function(p, e) { + return e > (p - 5) && e < (p + 5); +} + +qx.Proto._onwindowmousemove = function(e) +{ + if (!this.getResizeable() || this.getMode() != null) { + return; + } + + var s = this._resizeSession; + + if (s) + { + if (this._resizeWest) + { + s.lastWidth = qx.lang.Number.limit(s.boxWidth + s.boxLeft - Math.max(e.getPageX(), s.parentAreaOffsetLeft), s.minWidth, s.maxWidth); + s.lastLeft = s.boxRight - s.lastWidth - s.parentAreaOffsetLeft; + } + else if (this._resizeEast) + { + s.lastWidth = qx.lang.Number.limit(Math.min(e.getPageX(), s.parentAreaOffsetRight) - s.boxLeft, s.minWidth, s.maxWidth); + } + + if (this._resizeNorth) + { + s.lastHeight = qx.lang.Number.limit(s.boxHeight + s.boxTop - Math.max(e.getPageY(), s.parentAreaOffsetTop), s.minHeight, s.maxHeight); + s.lastTop = s.boxBottom - s.lastHeight - s.parentAreaOffsetTop; + } + else if (this._resizeSouth) + { + s.lastHeight = qx.lang.Number.limit(Math.min(e.getPageY(), s.parentAreaOffsetBottom) - s.boxTop, s.minHeight, s.maxHeight); + } + + switch(this.getResizeMethod()) + { + case "opaque": + case "translucent": + if (this._resizeWest || this._resizeEast) + { + this.setWidth(s.lastWidth); + + if (this._resizeWest) { + this.setLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + this.setHeight(s.lastHeight); + + if (this._resizeNorth) { + this.setTop(s.lastTop); + } + } + + break; + + default: + var o = this.getResizeMethod() == "frame" ? this._frame : this; + + if (this._resizeWest || this._resizeEast) + { + o._applyRuntimeWidth(s.lastWidth); + + if (this._resizeWest) { + o._applyRuntimeLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + o._applyRuntimeHeight(s.lastHeight); + + if (this._resizeNorth) { + o._applyRuntimeTop(s.lastTop); + } + } + } + } + else + { + var resizeMode = ""; + var el = this.getElement(); + + this._resizeNorth = this._resizeSouth = this._resizeWest = this._resizeEast = false; + + if (this._near(qx.html.Location.getPageBoxTop(el), e.getPageY())) + { + resizeMode = "n"; + this._resizeNorth = true; + } + else if (this._near(qx.html.Location.getPageBoxBottom(el), e.getPageY())) + { + resizeMode = "s"; + this._resizeSouth = true; + } + + if (this._near(qx.html.Location.getPageBoxLeft(el), e.getPageX())) + { + resizeMode += "w"; + this._resizeWest = true; + } + else if (this._near(qx.html.Location.getPageBoxRight(el), e.getPageX())) + { + resizeMode += "e"; + this._resizeEast = true; + } + + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + this.setCursor(resizeMode + "-resize"); + } + else + { + this.setCursor(null); + } + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._onwindowclick = function(e) +{ + // stop event + e.stopPropagation(); +}; + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: BUTTONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onbuttonmousedown = function(e) { + e.stopPropagation(); +} + +qx.Proto._onminimizebuttonclick = function(e) +{ + this.minimize(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._minimizeButton.removeState("pressed"); + this._minimizeButton.removeState("abandoned"); + this._minimizeButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onrestorebuttonclick = function(e) +{ + this.restore(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._restoreButton.removeState("pressed"); + this._restoreButton.removeState("abandoned"); + this._restoreButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onmaximizebuttonclick = function(e) +{ + this.maximize(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._maximizeButton.removeState("pressed"); + this._maximizeButton.removeState("abandoned"); + this._maximizeButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onclosebuttonclick = function(e) +{ + this.close(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._closeButton.removeState("pressed"); + this._closeButton.removeState("abandoned"); + this._closeButton.removeState("over"); + + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: CAPTIONBAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._oncaptionmousedown = function(e) +{ + if (!e.isLeftButtonPressed() || !this.getMoveable() || this.getMode() != null) { + return; + } + + // enable capturing + this._captionBar.setCapture(true); + + // element cache + var el = this.getElement(); + + // measuring and caching of values for drag session + var pa = this.getParent(); + var pl = pa.getElement(); + + var l = qx.html.Location.getPageAreaLeft(pl); + var t = qx.html.Location.getPageAreaTop(pl); + var r = qx.html.Location.getPageAreaRight(pl); + var b = qx.html.Location.getPageAreaBottom(pl); + + this._dragSession = + { + offsetX : e.getPageX() - qx.html.Location.getPageBoxLeft(el) + l, + offsetY : e.getPageY() - qx.html.Location.getPageBoxTop(el) + t, + + parentAvailableAreaLeft : l + 5, + parentAvailableAreaTop : t + 5, + parentAvailableAreaRight : r - 5, + parentAvailableAreaBottom : b - 5 + } + + // handle frame and translucently + switch(this.getMoveMethod()) + { + case "translucent": + this.setOpacity(0.5); + break; + + case "frame": + var f = this._frame; + + if (f.getParent() != this.getParent()) + { + f.setParent(this.getParent()); + qx.ui.core.Widget.flushGlobalQueues(); + } + + f._applyRuntimeLeft(qx.html.Location.getPageBoxLeft(el) - l); + f._applyRuntimeTop(qx.html.Location.getPageBoxTop(el) - t); + + f._applyRuntimeWidth(qx.html.Dimension.getBoxWidth(el)); + f._applyRuntimeHeight(qx.html.Dimension.getBoxHeight(el)); + + f.setZIndex(this.getZIndex() + 1); + + break; + } +} + +qx.Proto._oncaptionmouseup = function(e) +{ + var s = this._dragSession; + + if (!s) { + return; + } + + // disable capturing + this._captionBar.setCapture(false); + + // move window to last position + if (s.lastX != null) { + this.setLeft(s.lastX); + } + + if (s.lastY != null) { + this.setTop(s.lastY); + } + + // handle frame and translucently + switch(this.getMoveMethod()) + { + case "translucent": + this.setOpacity(null); + break; + + case "frame": + this._frame.setParent(null); + break; + } + + // cleanup session + delete this._dragSession; +} + +qx.Proto._oncaptionmousemove = function(e) +{ + var s = this._dragSession; + + // pre check for active session and capturing + if (!s || !this._captionBar.getCapture()) { + return; + } + + // pre check if we go out of the available area + if (!qx.lang.Number.isBetweenRange(e.getPageX(), s.parentAvailableAreaLeft, s.parentAvailableAreaRight) || !qx.lang.Number.isBetweenRange(e.getPageY(), s.parentAvailableAreaTop, s.parentAvailableAreaBottom)) { + return; + } + + // use the fast and direct dom methods + var o = this.getMoveMethod() == "frame" ? this._frame : this; + + o._applyRuntimeLeft(s.lastX = e.getPageX() - s.offsetX); + o._applyRuntimeTop(s.lastY = e.getPageY() - s.offsetY); +} + +qx.Proto._oncaptiondblblick = function() +{ + if (!this._maximizeButton.getEnabled()) { + return; + } + + return this.getMode() == "maximized" ? this.restore() : this.maximize(); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._layout) + { + this._layout.dispose(); + this._layout = null; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + if (this._captionBar) + { + this._captionBar.dispose(); + this._captionBar = null; + } + + if (this._captionIcon) + { + this._captionIcon.dispose(); + this._captionIcon = null; + } + + if (this._captionTitle) + { + this._captionTitle.dispose(); + this._captionTitle = null; + } + + if (this._captionFlex) + { + this._captionFlex.dispose(); + this._captionFlex = null; + } + + if (this._closeButton) + { + this._closeButton.dispose(); + this._closeButton = null; + } + + if (this._minimizeButton) + { + this._minimizeButton.dispose(); + this._minimizeButton = null; + } + + if (this._maximizeButton) + { + this._maximizeButton.dispose(); + this._maximizeButton = null; + } + + if (this._restoreButton) + { + this._restoreButton.dispose(); + this._restoreButton = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + if (this._statusBar) + { + this._statusBar.dispose(); + this._statusBar = null; + } + + if (this._statusText) + { + this._statusText.dispose(); + this._statusText = null; + } + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/ColorUtil.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/ColorUtil.js new file mode 100644 index 0000000000..f519fa4a41 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/ColorUtil.js @@ -0,0 +1,196 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Methods to convert colors between ddiffernt color spaces. + */ +qx.OO.defineClass("qx.util.ColorUtil"); + +/** + * Convert RGB colors to HSB + * + * @param vRed {Number} Red value. Range: 0..255 + * @param vGreen {Number} Green value. Range: 0..255 + * @param vBlue {Number} Blue value. Range: 0..255 + * + * @return {Map} Map with the keys following keys: + * <ul> + * <li>'hue': range 0..360</li> + * <li>'saturation': range 0..100</li> + * <li>'brightness': range 0..100</li> + * </ul> + */ +qx.Class.rgb2hsb = function(vRed, vGreen, vBlue) +{ + var vHue, vSaturation, vBrightness; + + vRed = parseFloat(vRed); + vGreen = parseFloat(vGreen); + vBlue = parseFloat(vBlue); + + var cmax = (vRed > vGreen) ? vRed : vGreen; + if (vBlue > cmax) { + cmax = vBlue; + } + + var cmin = (vRed < vGreen) ? vRed : vGreen; + if (vBlue < cmin) { + cmin = vBlue; + } + + vBrightness = cmax / 255.0; + + if (cmax != 0) + { + vSaturation = (cmax - cmin) / cmax; + } + else + { + vSaturation = 0; + } + + if (vSaturation == 0) + { + vHue = 0; + } + else + { + var redc = (cmax - vRed) / (cmax - cmin); + var greenc = (cmax - vGreen) / (cmax - cmin); + var bluec = (cmax - vBlue) / (cmax - cmin); + + if (vRed == cmax) + { + vHue = bluec - greenc; + } + else if (vGreen == cmax) + { + vHue = 2.0 + redc - bluec; + } + else + { + vHue = 4.0 + greenc - redc; + } + + vHue = vHue / 6.0; + if (vHue < 0) vHue = vHue + 1.0; + } + + return { + hue : Math.round(vHue * 360), + saturation : Math.round(vSaturation * 100), + brightness : Math.round(vBrightness * 100) + } +} + + +/** + * Convert HSB colors to RGB + * + * @param vHue {Number} Hue value. Range 0..360 + * @param vSaturation {Number} Saturation value. Range 0..100 + * @param vBrightness {Number} Brightness value. Range 0..100 + * + * @return {Map} Map the the following keys: + * <ul> + * <li>'red': range 0..255</li> + * <li>'green': range 0..255</li> + * <li>'blue': range 0..255</li> + * </ul> + */ +qx.Class.hsb2rgb = function(vHue, vSaturation, vBrightness) +{ + var i, f, p, q, t, vReturn; + + vHue = parseFloat(vHue/360); + vSaturation = parseFloat(vSaturation/100); + vBrightness = parseFloat(vBrightness/100); + + if(vHue >= 1.0) vHue %= 1.0; + if(vSaturation > 1.0) vSaturation = 1.0; + if(vBrightness > 1.0) vBrightness = 1.0; + + var tov = Math.floor(255 * vBrightness); + + var vReturn = {}; + + if(vSaturation == 0.0) + { + vReturn.red = vReturn.green = vReturn.blue = tov; + } + else + { + vHue *= 6.0; + + i = Math.floor(vHue); + + f = vHue - i; + + p = Math.floor(tov * (1.0 - vSaturation)); + q = Math.floor(tov * (1.0 - (vSaturation * f))); + t = Math.floor(tov * (1.0 - (vSaturation * (1.0 - f)))); + + switch(i) + { + case 0: + vReturn.red = tov; + vReturn.green = t; + vReturn.blue = p; + break; + + case 1: + vReturn.red = q; + vReturn.green = tov; + vReturn.blue = p; + break; + + case 2: + vReturn.red = p; + vReturn.green = tov; + vReturn.blue = t; + break; + + case 3: + vReturn.red = p; + vReturn.green = q; + vReturn.blue = tov; + break; + + case 4: + vReturn.red = t; + vReturn.green = p; + vReturn.blue = tov; + break; + + case 5: + vReturn.red = tov; + vReturn.green = p; + vReturn.blue = q; + break; + } + } + + return vReturn; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Compare.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Compare.js new file mode 100644 index 0000000000..00b8971411 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Compare.js @@ -0,0 +1,225 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Collection of methods to compare two values. + */ +qx.OO.defineClass("qx.util.Compare"); + + +/** + * Compare two Strings + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byString = function(a, b) { + return a==b ? 0 : a > b ? 1 : -1; +}; + + +/** + * Compare two Strings ignoring the letter case. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ + +qx.util.Compare.byStringCaseInsensitive = function(a, b) { + return qx.util.Compare.byString(a.toLowerCase(), b.toLowerCase()); +}; + + +/** + * Compare two Strings but first convert umlauts to an ascii character. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byStringUmlautsShort = function(a, b) { + return qx.util.Compare.byString(qx.util.Normalization.umlautsShort(a), qx.util.Normalization.umlautsShort(b)); +}; + + +/** + * Compare two Strings but first convert umlauts to an ascii character and ignore letter case. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byStringUmlautsShortCaseInsensitive = function(a, b) { + return qx.util.Compare.byString(qx.util.Normalization.umlautsShort(a).toLowerCase(), qx.util.Normalization.umlautsShort(b).toLowerCase()); +}; + + +/** + * Compare two Strings but first convert umlauts to ascii characters. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byStringUmlautsLong = function(a, b) { + return qx.util.Compare.byString(qx.util.Normalization.umlautsLong(a), qx.util.Normalization.umlautsLong(b)); +}; + + +/** + * Compare two Strings but first convert umlauts to ascii characters and ignore letter case. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byStringUmlautsLongCaseInsensitive = function(a, b) { + return qx.util.Compare.byString(qx.util.Normalization.umlautsLong(a).toLowerCase(), qx.util.Normalization.umlautsLong(b).toLowerCase()); +}; + + +/** + * Compare two Float numbers. + * + * @param a {Float} first value + * @param b {Float} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byFloat = function(a, b) { + return a - b; +}; + +qx.util.Compare.byInteger = qx.util.Compare.byNumber = qx.util.Compare.byFloat; + + +/** + * Compare two Strings representing integers. First convert the strings to an interger. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byIntegerString = function(a, b) { + return parseInt(a) - parseInt(b); +}; + + +/** + * Compare two Strings representing floats. First convert the strings to an float. + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byFloatString = function(a, b) { + return parseFloat(a) - parseFloat(b); +}; + +qx.util.Compare.byNumberString = qx.util.Compare.byFloatString; + + +/** + * Compare two Strings representing IPv4 adresses. + * Example: "192.168.1.2" + * + * @param a {String} first value + * @param b {String} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byIPv4 = function(a, b) +{ + var ipa = a.split(".", 4); + var ipb = b.split(".", 4); + + for (var i=0; i<3; i++) + { + a = parseInt(ipa[i]); + b = parseInt(ipb[i]); + + if (a != b) { + return a - b; + } + } + + return parseInt(ipa[3]) - parseInt(ipb[3]); +}; + + +/** + * Compare the zIndex property of two widgets. + * + * @param a {qx.ui.core.Widget} first value + * @param b {qx.ui.core.Widget} second value + * + * @return {Number} + * 0 if both values are equal + * a number > 0 if the first value if greater than the second one + * a value < 0 otherwise + */ +qx.util.Compare.byZIndex = function(a, b) { + return a.getZIndex() - b.getZIndex(); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/GuiBuilder.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/GuiBuilder.js new file mode 100644 index 0000000000..59225f981b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/GuiBuilder.js @@ -0,0 +1,492 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * A class to generate a widget hierarchy from XML. + * + * WARNING: This class may not be up-to-date or fully functional since it + * it is not actively maintained. However, there are other + * (server-side) solutions for handling XML GUI descriptions. + * Please see the qooxdoo homepage for related projects or ask on + * the mailing list. + * + * @param flags {Map} map of flags. "flags.strict" sets strict mode. + */ +qx.OO.defineClass("qx.util.GuiBuilder", qx.core.Target, +function(flags) +{ + qx.core.Target.call(this); + + // map<className, map<propertyName, function>> + this._propertyEditors = {}; + + this._registerDefaultPropertyEditors(); + + this._flags = flags || {}; + + // ensure the default flags are setup + if (this._flags.strict == null) { + // strick mode throws exceptions when + // * widget setters don't exist + this._flags.strict = true; + } + +}); + +/* +------------------------------------------------------------------------------------ + BUILD +------------------------------------------------------------------------------------ +*/ + +/** + * Asynchronous method - fetches XML data from the URL then delegates to build to process the xml + * Dispatches a qx.event.type.Event("done") after the hierarchy is built + * + * @param parent {qx.ui.core.Widget} can either be the application instance, or a widget to append the xml toplevel widgets to + * @param url {String} URL of the XML files + * + */ +qx.Proto.buildFromUrl = function(parent, url) { + var req = new qx.io.remote.Request(url, "GET", qx.util.Mime.XML); + var self = this; + req.addEventListener("completed", function(e) { + self.build(parent, e.getData().getContent()); + qx.ui.core.Widget.flushGlobalQueues(); + }); + req.send(); +} + +/** + * parse the children of the xml and appending all widgets to the parent widget + * + * @param parent {qx.ui.core.Widget} can either be the application instance, or a widget to append the xml toplevel widgets to + * @param node {String|Document|Element} can be either a xml string, or a xml dom document or fragment + */ +qx.Proto.build = function(parent, node) { + // support embedding of an XML string within a textarea + if (typeof node == "object" && node.nodeName == 'TEXTAREA') { + node = node.value; + } + + // parse strings in to XML DOM + if (typeof node == "string") { + node = qx.xml.Document.fromString(node); + // TODO handle parse errors + } + this._buildNodes(parent, node.childNodes); +} + +qx.Proto._buildNodes = function(parent, nodes) { + var x = 0; + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + // 1 = ELEMENT_NODE + if (n.nodeType == 1) { + this._buildWidgetFromNode(parent, n); + } + } +} + +qx.Proto._buildEventListener = function(widget, args, text) { + if (typeof args.type !== "string") { + throw this._newError('eventListener requires a string type attribute'); + } + + var self = this; + + // are we delegating ? + if (typeof args.delegate === "string") { + + if (args.delegate.indexOf('.') > -1) { + // delegation to a global method + var p = args.delegate.split('.'); + var o = p[0]; + var m = p[1]; + widget.addEventListener(args.type, function(e) { + + if (!window[o]) { + throw self._newError('delegate not found', {delegate:args.delegate}); + } + + if (!window[o][m]) { + throw self._newError('delegate not found', {delegate:args.delegate}); + } + + window[o][m].apply(window[o], [e]); + }); + } + else { + + // delegation to a global method + widget.addEventListener(args.type, function(e) { + + if (!window[args.delegate]) { + throw self._newError('delegate not found', {delegate:args.delegate}); + } + + window[args.delegate].apply(null, [e]); + }); + } + } + else { + + // build a function object using text as the function body + // + // the args attribute indicates the name of the event argument + // if not provided - use 'event' as the name + if (!args.args) { + args.args = "event"; + } + + var f = new Function(args.args, text); + widget.addEventListener(args.type, f); + } +} + + +/** + * A node builder that will be used if no node builder is declared for a nodeName + * + * @param parent {qx.ui.core.Widget} can either be the application instance, or a widget to append the xml toplevel widgets to + * @param node {String|Document|Element} can be either a xml string, or a xml dom document or fragment + */ + +qx.Proto._buildWidgetFromNode = function(parent, node) { + + var className = this._extractClassName(node); + + if (!className) { + throw this._newError("unrecognised node", {nodeName:node.nodeName}); + } + + if (className == "qx.client.builder.Container") { + // generic container node to allow xml to contain multiple toplevel nodes + this._buildNodes(parent, node.childNodes); + return; + } + + if (className == "qx.client.builder.Script") { + var e = document.createElement("script"); + var attribs = this._mapXmlAttribToObject(node); + if (attribs.type) { + e.type = attribs.type; + } + else { + e.type='text/javascript'; + } + + // e.innerHTML = node.firstChild.nodeValue; + + // fix for Internet Explorer by Cristian Bica + if (qx.core.Client.getInstance().isMshtml()) + { + e.innerHTML = eval(node.firstChild.nodeValue); + } + else + { + e.innerHTML = node.firstChild.nodeValue; + } + + document.body.appendChild(e); + return; + } + + if (className == "qx.client.builder.EventListener") { + var attribs = this._mapXmlAttribToObject(node); + var text; + if (node.firstChild) { + text = node.firstChild.nodeValue; + } + this._buildEventListener(parent, attribs, text); + return; + } + + + var classConstructor = qx.OO.classes[className]; + if (!classConstructor) { + throw this._newError("constructor not found", {className:className}); + } + + // construct the widget instance - using the default constructor + var widget = new classConstructor(); + var attribs = this._mapXmlAttribToObject(node, widget); + delete attribs['qxtype']; + + var dummyWidget = attribs.id && attribs.id.indexOf("_") == 0; + + if (attribs.id) { + // register a global refrence for this widget + window[attribs.id] = widget; + delete attribs.id; + } + + // convert any on?? attribs into event listeners + for (var a in attribs) { + + if (a.toLowerCase().indexOf('on') == 0 && a.length > 2) { + + // there may be issues here for XHTML based attributes - due to their case + var type = a.substring(2); + type = type.charAt(0) + type.substring(1); + + this._buildEventListener(widget, {type:type,args:'event'}, attribs[a]); + + delete attribs[a]; + } + } + + for (var n in attribs) { + this._setWidgetProperty(widget, n, attribs[n]); + } + + if(!dummyWidget) { + parent.add(widget); + } + + // recurse to all of the nodes children, using the newly created widget as the parent + this._buildNodes(widget, node.childNodes); +} + +/* +------------------------------------------------------------------------------------ + WIDGET PROPERTIES +------------------------------------------------------------------------------------ +*/ + + +/*! + Set a widget's property using a propertyEditor +*/ +qx.Proto._setWidgetProperty = function(widget, name, value) { + var editor = this._findPropertyEditor(widget.classname, name); + if (!editor) { + editor = this._coercePropertyEditor; + } + editor.set(widget, name, value); +} + +qx.Proto._findPropertyEditor = function(className, propertyName) { + // get all defined propertyEditors for this widget's prototype + var m = this._propertyEditors[className]; + // lookup the converter for this property name + if (m && m[propertyName]) { + return m[propertyName]; + } + + // try the widget's superclass + var w = qx.OO.classes[className]; + if (w && w.superclass && w.superclass.prototype.classname) { + return this._findPropertyEditor(w.superclass.prototype.classname, propertyName); + } + + return null; +} + +qx.Proto.registerPropertyEditor = function(className, propertyName, editor) { + if (!this._propertyEditors[className]) this._propertyEditors[className] = {}; + this._propertyEditors[className][propertyName] = editor; +} + +qx.Proto._registerDefaultPropertyEditors = function() { + var self = this; + + // a property editor that splits the values on a comma and coerces each one into a suitable type + var commaDelimitedPropertyEditor = {}; + commaDelimitedPropertyEditor.set = function(widget, name, value) { + if (value == null || value == "") { + self._setProperty(widget, name, null); + return; + } + + var s = value.split(","); + var v = []; + for (var i = 0; i < s.length; i++) { + v[i] = self._coerce(s[i]); + } + + self._setProperties(widget, name, v); + } + + var evalPropertyEditor = {}; + evalPropertyEditor.set = function(widget, name, value) { + if (value == null || value == "") { + self._setProperty(widget, name, null); + return; + } + + self._setProperty(widget, name, eval(value)); + } + + var referencePropertyEditor = {}; + referencePropertyEditor.set = function(widget, name, value) { + self._setProperty(widget, name, window[value]); + } + + this.registerPropertyEditor('qx.ui.core.Widget', 'location', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'dimension', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'space', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'edge', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'padding', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'margin', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'heights', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'widths', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'align', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'stretch', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'clipLocation', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'clipDimension', commaDelimitedPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'clip', commaDelimitedPropertyEditor); + + this.registerPropertyEditor('qx.ui.core.Widget', 'backgroundColor', evalPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'color', evalPropertyEditor); + this.registerPropertyEditor('qx.ui.core.Widget', 'border', evalPropertyEditor); + + + this.registerPropertyEditor('qx.ui.menu.Button', 'menu', referencePropertyEditor); + this.registerPropertyEditor('qx.ui.form.RadioButton', 'manager', referencePropertyEditor); + this.registerPropertyEditor('qx.ui.menu.RadioButton', 'group', referencePropertyEditor); + + + // a property editor that just tries to coerce the string value into a suitable type + this._coercePropertyEditor = {}; + this._coercePropertyEditor.set = function(widget, name, value) { + self._setProperty(widget, name, self._coerce(value)); + } + +} + + +qx.Proto._coerce = function(value) { + + // don't really care if its null + if (value == null) return value; + + // is it alreay a javascript type + if (typeof value == 'object') return value; + if (typeof value == 'function') return value; + if (typeof value == 'number') return value; + if (typeof value == 'boolean') return value; + if (typeof value == 'date') return value; + if (typeof value == 'array') return value; + + // is it a number ? + var n = new Number(value); + if (!isNaN(n)) return n.valueOf(); + + // is it a boolean ? + if (value == "true") return true; + if (value == "false") return false; + + // is it a date ? + var d = Date.parse(value); + if (d != null && !isNaN(d)) return d; + + // leave it as a string + if (typeof value == 'string') { + // convert empty string into null + if (value == "") return null; + } + + return value; +} + +qx.Proto._setProperty = function(widget, name, value) { + this._setProperties(widget, name, [value]); +} + +qx.Proto._setProperties = function(widget, name, value) { + + // TODO : find a cheaper way to find the setter + // NOTE : the name is LOWERCASE - hence we iterate all properties of the widget + // to try and find a matching one + var n = "set" + name; + for (var a in widget) { + if (n == a.toLowerCase()) { + var setter = widget[a]; + break; + } + } + if (!setter && this._flags.strict) throw this._newError('no setter defined on widget instance', {widget:widget, property:name}); + setter.apply(widget, value); +} + + +/* +------------------------------------------------------------------------------------ + UTILS +------------------------------------------------------------------------------------ +*/ + +/* +2 format +1. <qx.ui.basic.Atom/> +3. <div qxtype="qx.ui.basic.Atom"/> +*/ +qx.Proto._extractClassName = function(node) { + if (node.nodeName.toLowerCase() == "div") { + if (!node.attributes['qxtype']) + return null; + return node.attributes['qxtype'].value; + } else { + return node.nodeName; + } +} + +qx.Proto._mapXmlAttribToObject = function(node) { + var r = {}; + var c = node.attributes; + for (var i=0; i<c.length; i++) { + r[c[i].name.toLowerCase()] = c[i].value; + } + return r; +} + +/* +------------------------------------------------------------------------------------ + EXCEPTION HANDLING / DEBUGGING +------------------------------------------------------------------------------------ +*/ + +qx.Proto._newError = function(message, data, exception) { + var m = message; + var joiner = ""; + var d = ""; + if (data) { + for (var p in data) { + d += joiner + p + "=" + data[p] + ''; + joiner = " "; + } + m += " " + d + " "; + } + if (exception) { + m+= " error: " + exception + " "; + } + return new Error(m); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Mime.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Mime.js new file mode 100644 index 0000000000..abb6741d87 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Mime.js @@ -0,0 +1,40 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Mime type constants + */ +qx.OO.defineClass("qx.util.Mime", +{ + JAVASCRIPT: "text/javascript", + + /** this has been changed from text/json to application/json */ + JSON: "application/json", + + XML: "application/xml", + TEXT: "text/plain", + HTML: "text/html" +}); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Normalization.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Normalization.js new file mode 100644 index 0000000000..c246dfda65 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Normalization.js @@ -0,0 +1,89 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.util.Normalization"); + + + + + +/* +--------------------------------------------------------------------------- + HANDLING OF UMLAUTS +--------------------------------------------------------------------------- +*/ + +qx.util.Normalization._umlautsRegExp = /[\xE4\xF6\xFC\xDF\xC4\xD6\xDC]/g; + +qx.util.Normalization._umlautsShortData = { "\xC4": "A", "\xD6": "O", "\xDC": "U", "\xE4": "a", "\xF6": "o", "\xFC": "u", "\xDF": "s" }; + + +/** + * Private helper + * + * @param vChar {String} char to convert + * @return {String} + */ +qx.util.Normalization._umlautsShort = function(vChar) { + return qx.util.Normalization._umlautsShortData[vChar]; +}; + + +/** + * Converts (German) umlauts in the string to a one letter ASCI form. + * Example: Ä -> A, ü -> u, ß -> s, ... + * + * @param vString {String} string to normalize + * @return {String} normalized string + */ +qx.util.Normalization.umlautsShort = function(vString) { + return vString.replace(qx.util.Normalization._umlautsRegExp, qx.util.Normalization._umlautsShort); +}; + + +qx.util.Normalization._umlautsLongData = { "\xC4": "Ae", "\xD6": "Oe", "\xDC": "Ue", "\xE4": "ae", "\xF6": "oe", "\xFC": "ue", "\xDF": "ss" }; + + +/** + * Private helper + * + * @param vChar {String} char to convert + * @return {String} + */ +qx.util.Normalization._umlautsLong = function(vChar) { + return qx.util.Normalization._umlautsLongData[vChar]; +}; + + +/** + * Converts (German) umlauts in the string to a two letter ASCI form. + * Example: Ä -> Ae, ü -> ue, ß -> ss, ... + * + * @param vString {String} string to normalize + * @return {String} normalized string + */ +qx.util.Normalization.umlautsLong = function(vString) { + return vString.replace(qx.util.Normalization._umlautsRegExp, qx.util.Normalization._umlautsLong); +};
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/StringBuilder.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/StringBuilder.js new file mode 100644 index 0000000000..25e962a459 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/StringBuilder.js @@ -0,0 +1,148 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.core.Client) + +************************************************************************ */ + +/** + * A string builder class + * <p> + * += operator is faster in Firefox and Opera. + * Array push/join is faster in Internet Explorer + * </p><p> + * Even with this wrapper, which costs some time, this is + * faster in Firefox than the alternative Array concat in + * all browsers (which is in relation to IE's performance issues + * only marginal). The IE performance loss caused by this + * wrapper is not relevant. + * </p><p> + * So this class seems to be the best compromise to handle + * string concatenation.</p> + */ +qx.OO.defineClass("qx.util.StringBuilder", qx.core.Object, +function() +{ + qx.core.Object.call(this); + + this.init(); + this.add.apply(this, arguments); +}); + + +/** + * Resets the contents of the Stringbuilder + * equivalent to <pre>str = ""; </pre> + */ +qx.Proto.clear = function() {} + +/** + * Returns the contents of the concatenated string + * + * @return {String} string content + */ +qx.Proto.get = function() {} + +/** + * Append a variable number of string arguments + * + * @param varargs {String} variable number os strings to be added + */ +qx.Proto.add = function(varargs) {} + +/** + * Initializes the contents of the Stringbuilder + * equivalent to <pre>str = ""; </pre> + */ +qx.Proto.init = function() {} + +/** Destructor */ +qx.Proto.dispose = function() {} + +/** + * Returns the contents of the concatenated string + * + * @return {String} string content + */ +qx.Proto.toString = function() {} + + +if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Proto.clear = function() { + this._array = []; + } + + qx.Proto.get = function() { + return this._array.join(""); + } + + qx.Proto.add = function() { + this._array.push.apply(this._array, arguments); + } + + qx.Proto.init = function() { + this._array = []; + } + + qx.Proto.dispose = function() + { + if (this.getDisposed()) { + return; + } + + this._array = null; + + qx.core.Object.prototype.dispose.call(this); + } +} +else +{ + qx.Proto.clear = function() { + this._string = ""; + } + + qx.Proto.get = function() { + return this._string; + } + + qx.Proto.add = function() { + this._string += Array.prototype.join.call(arguments, ""); + } + + qx.Proto.init = function() { + this._string = ""; + } + + qx.Proto.dispose = function() + { + if (this.getDisposed()) { + return; + } + + this._string = null; + + qx.core.Object.prototype.dispose.call(this); + } +} + +qx.Proto.toString = qx.Proto.get; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Validation.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Validation.js new file mode 100644 index 0000000000..8dfb08ba33 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/Validation.js @@ -0,0 +1,363 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(core) + +************************************************************************ */ + +/** + * Collection of validation methods. + * + * All methods use the strict comparison operators as all modern + * browsers (needs support for JavaScript 1.3) support this. + * + * http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Comparison_Operators + */ +qx.OO.defineClass("qx.util.Validation"); + +/** + * Whether a value is valid. Invalid values are: + * <ul> + * <li>undefined</li> + * <li>null</li> + * <li>"" (empty string)</li> + * <li>Nan (not a number)</li> + * <li>false</li> + * </ul> + * All other values are considered valid. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValid = function(v) +{ + switch(typeof v) + { + case "undefined": + return false; + + case "object": + return v !== null; + + case "string": + return v !== ""; + + case "number": + return !isNaN(v); + + case "function": + case "boolean": + return true; + } + + return false; +}; + + +/** + * Whether a value is invalid. Invalid values are: + * <ul> + * <li>undefined</li> + * <li>null</li> + * <li>"" (empty string)</li> + * <li>Nan (not a number)</li> + * <li>false</li> + * </ul> + * All other values are considered valid. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is invalid + */ +qx.util.Validation.isInvalid = function(v) +{ + switch(typeof v) + { + case "undefined": + return true; + + case "object": + return v === null; + + case "string": + return v === ""; + + case "number": + return isNaN(v); + + case "function": + case "boolean": + return false; + } + + return true; +}; + + +/** + * Whether a value is a valid number. Valid numbers are: + * <ul> + * <li>type is number</li> + * <li>not NaN</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidNumber = function(v) { + return typeof v === "number" && !isNaN(v); +}; + + +/** + * Whether a value is an invalid number. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidNumber = function(v) { + return typeof v !== "number" || isNaN(v); +}; + + +/** + * Whether a value is valid string. Valid strings are: + * <ul> + * <li>type is string</li> + * <li>not an empty string</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidString = function(v) { + return typeof v === "string" && v !== ""; +}; + + +/** + * Whether a value is an invalid string. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidString = function(v) { + return typeof v !== "string" || v === ""; +}; + + +/** + * Whether a value is a valid array. Valid arrays are: + * <ul> + * <li>type is object</li> + * <li>instance is Array</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidArray = function(v) { + return typeof v === "object" && v !== null && v instanceof Array; +}; + + +/** + * Whether a value is an invalid array. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidArray = function(v) { + return typeof v !== "object" || v === null || !(v instanceof Array); +}; + + +/** + * Whether a value is a valid object. Valid object are: + * <ul> + * <li>type is object</li> + * <li>instance != Array</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidObject = function(v) { + return typeof v === "object" && v !== null && !(v instanceof Array); +} + + +/** + * Whether a value is an invalid object. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidObject = function(v) { + return typeof v !== "object" || v === null || v instanceof Array; +}; + + +/** + * Whether a value is a valid DOM node. Valid nodes are: + * <ul> + * <li>type is object</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidNode = function(v) { + return typeof v === "object" && v !== null; +}; + + +/** + * Whether a value is an invalid node. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidNode = function(v) { + return typeof v !== "object" || v === null; +}; + + +/** + * Whether a value is valid DOM element number. Valid elements are: + * <ul> + * <li>type is object</li> + * <li>v.nodeType === 1</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidElement = function(v) { + return typeof v === "object" && v !== null || v.nodeType !== 1; +}; + + +/** + * Whether a value is not a DOM element. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidElement = function(v) { + return typeof v !== "object" || v === null || v.nodeType !== 1; +}; + + +/** + * Whether a value is a function. + * <ul> + * <li>type is function</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidFunction = function(v) { + return typeof v === "function"; +}; + + +/** + * Whether a value is not a function. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidFunction = function(v) { + return typeof v !== "function"; +}; + + +/** + * Whether a value is a boolean. Valid booleans are: + * <ul> + * <li>type is boolean</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidBoolean = function(v) { + return typeof v === "boolean"; +}; + + +/** + * Whether a value is not boolean. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidBoolean = function(v) { + return typeof v !== "boolean"; +}; + + +/** + * Whether a value is valid a non empty string or a valid number. Valid values are: + * <ul> + * <li>type is string or number</li> + * <li>values is not "" or NaN</li> + * </ul> + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isValidStringOrNumber = function(v) +{ + switch(typeof v) + { + case "string": + return v !== ""; + + case "number": + return !isNaN(v); + } + + return false; +}; + + +/** + * Whether a value not a valid string or number. + * + * @param v {var} the value to validate. + * @return {Boolean} whether the variable is valid + */ +qx.util.Validation.isInvalidStringOrNumber = function(v) +{ + switch(typeof v) + { + case "string": + return v === ""; + + case "number": + return isNaN(v); + } + + return false; +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/DateFormat.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/DateFormat.js new file mode 100644 index 0000000000..dd31073f7a --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/DateFormat.js @@ -0,0 +1,604 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.locale.Date) + +************************************************************************ */ + +/** + * A formatter and parser for dates + * + * @param format {String} The format to use. If null, the + * {@link #DEFAULT_DATE_TIME_FORMAT} is used. + * @param locale {String} optional locale to be used + */ +qx.OO.defineClass("qx.util.format.DateFormat", qx.util.format.Format, +function(format, locale) { + qx.util.format.Format.call(this); + + if (format != null) { + this._format = format.toString() + } else { + this._format = qx.locale.Date.getDateFormat("long", locale) + " " + qx.locale.Date.getDateTimeFormat("HHmmss", "HH:mm:ss", locale); + } + this._locale = locale; +}); + + +/** + * Fills a number with leading zeros ("25" -> "0025"). + * + * @param number {Integer} the number to fill. + * @param minSize {Integer} the minimum size the returned string should have. + * @return {String} the filled number as string. + */ +qx.Proto._fillNumber = function(number, minSize) { + var str = "" + number; + while (str.length < minSize) { + str = "0" + str; + } + return str; +} + + +/** + * Returns the day in year of a date. + * + * @param date {Date} the date. + * @return {Integer} the day in year. + */ +qx.Proto._getDayInYear = function(date) { + var helpDate = new Date(date.getTime()); + var day = helpDate.getDate(); + while (helpDate.getMonth() != 0) { + // Set the date to the last day of the previous month + helpDate.setDate(-1); + day += helpDate.getDate() + 1; + } + return day; +} + + +/** + * Returns the thursday in the same week as the date. + * + * @param date {Date} the date to get the thursday of. + * @return {Date} the thursday in the same week as the date. + */ +qx.Proto._thursdayOfSameWeek = function(date) { + return new Date(date.getTime() + (3 - ((date.getDay() + 6) % 7)) * 86400000); +} + + +/** + * Returns the week in year of a date. + * + * @param date {Date} the date to get the week in year of. + * @return {Integer} the week in year. + */ +qx.Proto._getWeekInYear = function(date) { + // This algorithm gets the correct calendar week after ISO 8601. + // This standard is used in almost all european countries. + // TODO: In the US week in year is calculated different! + // See http://www.merlyn.demon.co.uk/weekinfo.htm + + // The following algorithm comes from http://www.salesianer.de/util/kalwoch.html + + // Get the thursday of the week the date belongs to + var thursdayDate = this._thursdayOfSameWeek(date); + // Get the year the thursday (and therefor the week) belongs to + var weekYear = thursdayDate.getFullYear(); + // Get the thursday of the week january 4th belongs to + // (which defines week 1 of a year) + var thursdayWeek1 = this._thursdayOfSameWeek(new Date(weekYear, 0, 4)); + // Calculate the calendar week + return Math.floor(1.5 + (thursdayDate.getTime() - thursdayWeek1.getTime()) / 86400000 / 7) +} + + +/** + * Formats a date. + * <p> + * Uses the same syntax as + * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html" target="_blank"> + * the SimpleDateFormat class in Java</a>. + * + * @param date {Date} The date to format. + * @return {String} the formatted date. + */ +qx.Proto.format = function(date) { + var DateFormat = qx.util.format.DateFormat; + var locale = this._locale; + + var fullYear = date.getFullYear(); + var month = date.getMonth(); + var dayOfMonth = date.getDate(); + var dayOfWeek = date.getDay(); + var hours = date.getHours(); + var minutes = date.getMinutes(); + var seconds = date.getSeconds(); + var ms = date.getMilliseconds(); + var timezone = date.getTimezoneOffset() / 60; + + // Create the output + this._initFormatTree(); + var output = ""; + for (var i = 0; i < this._formatTree.length; i++) { + var currAtom = this._formatTree[i]; + + if (currAtom.type == "literal") { + output += currAtom.text; + } else { + // This is a wildcard + var wildcardChar = currAtom.character; + var wildcardSize = currAtom.size; + + // Get its replacement + var replacement = "?"; + switch (wildcardChar) { + // TODO: G - Era designator (e.g. AD). Problem: Not covered by JScript Date class + // TODO: W - Week in month (e.g. 2) + // TODO: F - Day of week in month (e.g. 2). Problem: What is this? + + case 'y': // Year + if (wildcardSize == 2) { + replacement = this._fillNumber(fullYear % 100, 2); + } else if (wildcardSize == 4) { + replacement = fullYear; + } + break; + case 'D': // Day in year (e.g. 189) + replacement = this._fillNumber(this._getDayInYear(date), wildcardSize); break; + case 'd': // Day in month + replacement = this._fillNumber(dayOfMonth, wildcardSize); break; + case 'w': // Week in year (e.g. 27) + replacement = this._fillNumber(this._getWeekInYear(date), wildcardSize); break; + case 'E': // Day in week + if (wildcardSize == 2) { + replacement = qx.locale.Date.getDayName("narrow", dayOfWeek, locale); + } else if (wildcardSize == 3) { + replacement = qx.locale.Date.getDayName("abbreviated", dayOfWeek, locale); + } else if (wildcardSize == 4) { + replacement = qx.locale.Date.getDayName("wide", dayOfWeek, locale); + } + break; + case 'M': // Month + if (wildcardSize == 1 || wildcardSize == 2) { + replacement = this._fillNumber(month + 1, wildcardSize); + } else if (wildcardSize == 3) { + replacement = qx.locale.Date.getMonthName("abbreviated",month, locale); + } else if (wildcardSize == 4) { + replacement = qx.locale.Date.getMonthName("wide", month, locale); + } + break; + case 'a': // am/pm marker + // NOTE: 0:00 is am, 12:00 is pm + replacement = (hours < 12) ? qx.locale.Date.getAmMarker(locale) : qx.locale.Date.getPmMarker(locale); break; + case 'H': // Hour in day (0-23) + replacement = this._fillNumber(hours, wildcardSize); break; + case 'k': // Hour in day (1-24) + replacement = this._fillNumber((hours == 0) ? 24 : hours, wildcardSize); break; + case 'K': // Hour in am/pm (0-11) + replacement = this._fillNumber(hours % 12, wildcardSize); break; + case 'h': // Hour in am/pm (1-12) + replacement = this._fillNumber(((hours % 12) == 0) ? 12 : (hours % 12), wildcardSize); break; + case 'm': // Minute in hour + replacement = this._fillNumber(minutes, wildcardSize); break; + case 's': // Second in minute + replacement = this._fillNumber(seconds, wildcardSize); break; + case 'S': // Millisecond + replacement = this._fillNumber(ms, wildcardSize); break; + case 'z': // Time zone + if (wildcardSize == 1) { + replacement = "GMT" + ((timezone < 0) ? "-" : "+") + this._fillNumber(timezone) + ":00"; + } else if (wildcardSize == 2) { + replacement = DateFormat.MEDIUM_TIMEZONE_NAMES[timezone]; + } else if (wildcardSize == 3) { + replacement = DateFormat.FULL_TIMEZONE_NAMES[timezone]; + } + break; + case 'Z': // RFC 822 time zone + replacement = ((timezone < 0) ? "-" : "+") + this._fillNumber(timezone, 2) + "00"; + } + output += replacement; + } + } + + return output; +} + + +/** + * Parses a date. + * <p> + * Uses the same syntax as + * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html" target="_blank"> + * the SimpleDateFormat class in Java</a>. + * + * @param dateStr {String} the date to parse. + * @return {Date} the parsed date. + * @throws If the format is not well formed or if the date string does not + * match to the format. + */ +qx.Proto.parse = function(dateStr) { + this._initParseFeed(); + + // Apply the regex + var hit = this._parseFeed.regex.exec(dateStr); + if (hit == null) { + throw new Error("Date string '" + dateStr + "' does not match the date format: " + this._format); + } + + // Apply the rules + var dateValues = { year:1970, month:0, day:1, hour:0, ispm:false, min:0, sec:0, ms:0 } + var currGroup = 1; + for (var i = 0; i < this._parseFeed.usedRules.length; i++) { + var rule = this._parseFeed.usedRules[i]; + + var value = hit[currGroup]; + if (rule.field != null) { + dateValues[rule.field] = parseInt(value, 10); + } else { + rule.manipulator(dateValues, value); + } + + currGroup += (rule.groups == null) ? 1 : rule.groups; + } + + var date = new Date(dateValues.year, dateValues.month, dateValues.day, + (dateValues.ispm) ? (dateValues.hour + 12) : dateValues.hour, + dateValues.min, dateValues.sec, dateValues.ms); + if (dateValues.month != date.getMonth() || dateValues.year != date.getFullYear()) { + // TODO: check if this is also necessary for the time components + throw new Error("Error parsing date '" + dateStr + "': the value for day or month is too large"); + } + + return date; +} + + + +/** + * Helper method for {@link #format()} and {@link #parse()}. + * Parses the date format. + */ +qx.Proto._initFormatTree = function() { + if (this._formatTree != null) { + return; + } + + this._formatTree = []; + + var currWildcardChar; + var currWildcardSize = 0; + var currLiteral = ""; + var format = this._format; + + var state = "default" + + var i = 0; + while (i < format.length) { + var currChar = format.charAt(i); + + switch (state) { + case "quoted_literal": + // We are now inside a quoted literal + // Check whether the current character is an escaped "'" character + if (currChar == "'") { + if (i+1 >= format.length) { + // this is the last character + i++; + break; + } + var lookAhead = format.charAt(i+1); + if (lookAhead == "'") { + currLiteral += currChar; + i++; + } else { + // quoted literal ends + i++; + state = "unkown"; + } + } else { + currLiteral += currChar; + i++; + } + break; + case "wildcard": + // Check whether the currChar belongs to that wildcard + if (currChar == currWildcardChar) { + // It does -> Raise the size + currWildcardSize++; + i++; + } else { + // It does not -> The current wildcard is done + this._formatTree.push({ type:"wildcard", character:currWildcardChar, size:currWildcardSize }); + currWildcardChar = null; + currWildcardSize = 0; + state = "default"; + } + break; + default: + // We are not (any more) in a wildcard or quoted literal -> Check what's starting here + if ((currChar >= 'a' && currChar <= 'z') || (currChar >= 'A' && currChar <= 'Z')) { + // This is a letter -> All letters are wildcards + // Start a new wildcard + currWildcardChar = currChar; + state = "wildcard"; + } else if (currChar == "'") { + if (i+1 >= format.length) { + // this is the last character + currLiteral += currChar; + i++; + break; + } + var lookAhead = format.charAt(i+1); + if (lookAhead == "'") { + currLiteral += currChar; + i++; + } + i++; + state = "quoted_literal"; + } else { + state = "default" + } + if (state != "default") { + // Add the literal + if (currLiteral.length > 0) { + this._formatTree.push({ type:"literal", text:currLiteral }); + currLiteral = ""; + } + } else { + // This is an unquoted literal -> Add it to the current literal + currLiteral += currChar; + i++; + } + break; + } + } + + // Add the last wildcard or literal + if (currWildcardChar != null) { + this._formatTree.push({ type:"wildcard", character:currWildcardChar, size:currWildcardSize }); + } else if (currLiteral.length > 0) { + this._formatTree.push({ type:"literal", text:currLiteral }); + } +} + + +/** + * Initializes the parse feed. + * <p> + * The parse contains everything needed for parsing: The regular expression + * (in compiled and uncompiled form) and the used rules. + * + * @return {Map} the parse feed. + */ +qx.Proto._initParseFeed = function() { + if (this._parseFeed != null) { + // We already have the farse feed + return; + } + + var DateFormat = qx.util.format.DateFormat; + var format = this._format; + + // Initialize the rules + this._initParseRules(); + this._initFormatTree(); + + // Get the used rules and construct the regex pattern + var usedRules = []; + var pattern = "^"; + for (var atomIdx = 0; atomIdx < this._formatTree.length; atomIdx++) { + var currAtom = this._formatTree[atomIdx]; + + if (currAtom.type == "literal") { + pattern += qx.lang.String.escapeRegexpChars(currAtom.text); + } else { + // This is a wildcard + var wildcardChar = currAtom.character; + var wildcardSize = currAtom.size; + + // Get the rule for this wildcard + var wildcardRule; + for (var ruleIdx = 0; ruleIdx < DateFormat._parseRules.length; ruleIdx++) { + var rule = DateFormat._parseRules[ruleIdx]; + if (wildcardChar == rule.pattern.charAt(0) && wildcardSize == rule.pattern.length) { + // We found the right rule for the wildcard + wildcardRule = rule; + break; + } + } + + // Check the rule + if (wildcardRule == null) { + // We have no rule for that wildcard -> Malformed date format + var wildcardStr = ""; + for (var i = 0; i < wildcardSize; i++) { + wildcardStr += wildcardChar; + } + throw new Error("Malformed date format: " + format + ". Wildcard " + + wildcardStr + " is not supported"); + } else { + // Add the rule to the pattern + usedRules.push(wildcardRule); + pattern += wildcardRule.regex; + } + } + } + pattern += "$"; + + // Create the regex + var regex; + try { + regex = new RegExp(pattern); + } + catch (exc) { + throw new Error("Malformed date format: " + format); + } + + // Create the this._parseFeed + this._parseFeed = { regex:regex, "usedRules":usedRules, pattern:pattern } +} + + +/** + * Initializes the static parse rules. + */ +qx.Proto._initParseRules = function() { + var DateFormat = qx.util.format.DateFormat; + + if (DateFormat._parseRules != null) { + // The parse rules are already initialized + return; + } + + DateFormat._parseRules = []; + + var yearManipulator = function(dateValues, value) { + value = parseInt(value, 10); + if (value < DateFormat.ASSUME_YEAR_2000_THRESHOLD) { + value += 2000; + } else if (value < 100) { + value += 1900; + } + + dateValues.year = value; + } + + var monthManipulator = function(dateValues, value) { + dateValues.month = parseInt(value, 10) - 1; + } + + var ampmManipulator = function(dateValues, value) { + dateValues.ispm = (value == DateFormat.PM_MARKER); + } + + var noZeroHourManipulator = function(dateValues, value) { + dateValues.hour = parseInt(value, 10) % 24; + } + + var noZeroAmPmHourManipulator = function(dateValues, value) { + dateValues.hour = parseInt(value, 10) % 12; + } + + // Unsupported: w (Week in year), W (Week in month), D (Day in year), + // F (Day of week in month), z (time zone) reason: no setter in Date class, + // Z (RFC 822 time zone) reason: no setter in Date class + + DateFormat._parseRules.push({ pattern:"yyyy", regex:"(\\d\\d(\\d\\d)?)", + groups:2, manipulator:yearManipulator } ); + DateFormat._parseRules.push({ pattern:"yy", regex:"(\\d\\d)", manipulator:yearManipulator } ); + // TODO: "MMMM", "MMM" (Month names) + DateFormat._parseRules.push({ pattern:"M", regex:"(\\d\\d?)", manipulator:monthManipulator }); + DateFormat._parseRules.push({ pattern:"MM", regex:"(\\d\\d?)", manipulator:monthManipulator }); + DateFormat._parseRules.push({ pattern:"dd", regex:"(\\d\\d?)", field:"day" }); + DateFormat._parseRules.push({ pattern:"d", regex:"(\\d\\d?)", field:"day" }); + // TODO: "EEEE", "EEE", "EE" (Day in week names) + DateFormat._parseRules.push({ pattern:"a", + regex:"(" + DateFormat.AM_MARKER + "|" + DateFormat.PM_MARKER + ")", + manipulator:ampmManipulator }); + DateFormat._parseRules.push({ pattern:"HH", regex:"(\\d\\d?)", field:"hour" }); + DateFormat._parseRules.push({ pattern:"H", regex:"(\\d\\d?)", field:"hour" }); + DateFormat._parseRules.push({ pattern:"kk", regex:"(\\d\\d?)", manipulator:noZeroHourManipulator }); + DateFormat._parseRules.push({ pattern:"k", regex:"(\\d\\d?)", manipulator:noZeroHourManipulator }); + DateFormat._parseRules.push({ pattern:"KK", regex:"(\\d\\d?)", field:"hour" }); + DateFormat._parseRules.push({ pattern:"K", regex:"(\\d\\d?)", field:"hour" }); + DateFormat._parseRules.push({ pattern:"hh", regex:"(\\d\\d?)", manipulator:noZeroAmPmHourManipulator }); + DateFormat._parseRules.push({ pattern:"h", regex:"(\\d\\d?)", manipulator:noZeroAmPmHourManipulator }); + DateFormat._parseRules.push({ pattern:"mm", regex:"(\\d\\d?)", field:"min" }); + DateFormat._parseRules.push({ pattern:"m", regex:"(\\d\\d?)", field:"min" }); + DateFormat._parseRules.push({ pattern:"ss", regex:"(\\d\\d?)", field:"sec" }); + DateFormat._parseRules.push({ pattern:"s", regex:"(\\d\\d?)", field:"sec" }); + DateFormat._parseRules.push({ pattern:"SSS", regex:"(\\d\\d?\\d?)", field:"ms" }); + DateFormat._parseRules.push({ pattern:"SS", regex:"(\\d\\d?\\d?)", field:"ms" }); + DateFormat._parseRules.push({ pattern:"S", regex:"(\\d\\d?\\d?)", field:"ms" }); +} + + +/** + * Returns a <code>DateFomat</code> instance that uses the + * {@link #DEFAULT_DATE_TIME_FORMAT}. + * + * @return {String} the date/time instance. + */ +qx.Class.getDateTimeInstance = function() { + var DateFormat = qx.util.format.DateFormat; + + var format = qx.locale.Date.getDateFormat("long") + " " + qx.locale.Date.getDateTimeFormat("HHmmss", "HH:mm:ss"); + if ( + DateFormat._dateInstance == null || + DateFormat._format != format + ) { + DateFormat._dateTimeInstance = new DateFormat(); + } + return DateFormat._dateTimeInstance; +} + + +/** + * Returns a <code>DateFomat</code> instance that uses the + * {@link #DEFAULT_DATE_FORMAT}. + * + * @return {String} the date instance. + */ +qx.Class.getDateInstance = function() { + var DateFormat = qx.util.format.DateFormat; + + var format = qx.locale.Date.getDateFormat("short") + ""; + if ( + DateFormat._dateInstance == null || + DateFormat._format != format + ) { + DateFormat._dateInstance = new DateFormat(format); + } + return DateFormat._dateInstance; +} + + +/** + * (int) The threshold until when a year should be assumed to belong to the + * 21st century (e.g. 12 -> 2012). Years over this threshold but below 100 will be + * assumed to belong to the 20th century (e.g. 88 -> 1988). Years over 100 will be + * used unchanged (e.g. 1792 -> 1792). + */ +qx.Class.ASSUME_YEAR_2000_THRESHOLD = 30; + +/** {string} The date format used for logging. */ +qx.Class.LOGGING_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + +/** {string} The am marker. */ +qx.Class.AM_MARKER = "am" + +/** {string} The pm marker. */ +qx.Class.PM_MARKER = "pm"; + +/** {string[]} The medium (three letter) timezone names. */ +qx.Class.MEDIUM_TIMEZONE_NAMES = [ + "GMT" // TODO: fill up +]; + +/** {string[]} The full timezone names. */ +qx.Class.FULL_TIMEZONE_NAMES = [ + "Greenwich Mean Time" // TODO: fill up +];
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/Format.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/Format.js new file mode 100644 index 0000000000..5667491432 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/Format.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * Superclass for formatters and parsers. + */ +qx.OO.defineClass("qx.util.format.Format", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Formats an object. + * + * @param obj {var} The object to format. + * @return {String} the formatted object. + */ +qx.Proto.format = function(obj) { + throw new Error("format is abstract"); +} + + +/** + * Parses an object. + * + * @param str {String} the string to parse. + * @return {var} the parsed object. + */ +qx.Proto.parse = function(str) { + throw new Error("parse is abstract"); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/NumberFormat.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/NumberFormat.js new file mode 100644 index 0000000000..0417e8784f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/format/NumberFormat.js @@ -0,0 +1,215 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +* #require(qx.locale.Number) + +************************************************************************ */ + +/** + * A formatter and parser for numbers. + * + * @param locale {String} optional locale to be used + */ +qx.OO.defineClass("qx.util.format.NumberFormat", qx.util.format.Format, +function(locale) { + qx.util.format.Format.call(this); + this._locale = locale; +}); + + +/** + * The minimum number of integer digits (digits before the decimal separator). + * Missing digits will be filled up with 0 ("19" -> "0019"). + */ +qx.OO.addProperty({ name:"minimumIntegerDigits", type:"number", defaultValue:0, allowNull:false }); + +/** + * The maximum number of integer digits (superfluos digits will be cut off + * ("1923" -> "23"). + */ +qx.OO.addProperty({ name:"maximumIntegerDigits", type:"number", defaultValue:null }); + +/** + * The minimum number of fraction digits (digits after the decimal separator). + * Missing digits will be filled up with 0 ("1.5" -> "1.500") + */ +qx.OO.addProperty({ name:"minimumFractionDigits", type:"number", defaultValue:0, allowNull:false }); + +/** + * The maximum number of fraction digits (digits after the decimal separator). + * Superflous digits will cause rounding ("1.8277" -> "1.83") + */ +qx.OO.addProperty({ name:"maximumFractionDigits", type:"number", defaultValue:null }); + +/** Whether thousand groupings should be used {e.g. "1,432,234.65"}. */ +qx.OO.addProperty({ name:"groupingUsed", type:"boolean", defaultValue:true, allowNull:false }); + +/** The prefix to put before the number {"EUR " -> "EUR 12.31"}. */ +qx.OO.addProperty({ name:"prefix", type:"string", defaultValue:"", allowNull:false }); + +/** Sets the postfix to put after the number {" %" -> "56.13 %"}. */ +qx.OO.addProperty({ name:"postfix", type:"string", defaultValue:"", allowNull:false }); + + +/** + * Formats a number. + * + * @param num {number} the number to format. + * @return {String} the formatted number as a string. + */ +qx.Proto.format = function(num) { + var NumberFormat = qx.util.format.NumberFormat; + + var negative = (num < 0); + if (negative) { + num = -num; + } + if (this.getMaximumFractionDigits() != null) { + // Do the rounding + var mover = Math.pow(10, this.getMaximumFractionDigits()); + num = Math.round(num * mover) / mover; + } + + if (num != 0) { // Math.log(0) = -Infinity + var integerDigits = Math.max(parseInt(Math.log(num) / Math.LN10) + 1, 1); + } else { + integerDigits = 1; + } + + var numStr = "" + num; + + // Prepare the integer part + var integerStr = numStr.substring(0, integerDigits); + while (integerStr.length < this.getMinimumIntegerDigits()) { + integerStr = "0" + integerStr; + } + if (this.getMaximumIntegerDigits() != null && integerStr.length > this.getMaximumIntegerDigits()) { + // NOTE: We cut off even though we did rounding before, because there + // may be rounding errors ("12.24000000000001" -> "12.24") + integerStr = integerStr.substring(integerStr.length - this.getMaximumIntegerDigits()); + } + + // Prepare the fraction part + var fractionStr = numStr.substring(integerDigits + 1); + while (fractionStr.length < this.getMinimumFractionDigits()) { + fractionStr += "0"; + } + if (this.getMaximumFractionDigits() != null && fractionStr.length > this.getMaximumFractionDigits()) { + // We have already rounded -> Just cut off the rest + fractionStr = fractionStr.substring(0, this.getMaximumFractionDigits()); + } + + // Add the thousand groupings + if (this.getGroupingUsed()) { + var origIntegerStr = integerStr; + integerStr = ""; + var groupPos; + for (groupPos = origIntegerStr.length; groupPos > 3; groupPos -= 3) { + integerStr = "" + qx.locale.Number.getGroupSeparator(this._locale) + + origIntegerStr.substring(groupPos - 3, groupPos) + integerStr; + } + integerStr = origIntegerStr.substring(0, groupPos) + integerStr; + } + + // Workaround: prefix and postfix are null even their defaultValue is "" and + // allowNull is set to false?!? + var prefix = this.getPrefix() ? this.getPrefix() : ""; + var postfix = this.getPostfix() ? this.getPostfix() : ""; + + // Assemble the number + var str = prefix + (negative ? "-" : "") + integerStr; + if (fractionStr.length > 0) { + str += "" + qx.locale.Number.getDecimalSeparator(this._locale) + fractionStr; + } + str += postfix; + + return str; +}; + + +/** + * Parses a number. + * + * @param str {String} the string to parse. + * + * @return {Double} the number. + */ +qx.Proto.parse = function(str) { + var NumberFormat = qx.util.format.NumberFormat; + + // use the escaped separators for regexp + var groupSepEsc = qx.lang.String.escapeRegexpChars(qx.locale.Number.getGroupSeparator(this._locale)+""); + var decimalSepEsc = qx.lang.String.escapeRegexpChars(qx.locale.Number.getDecimalSeparator(this._locale)+""); + + var regex = new RegExp(qx.lang.String.escapeRegexpChars(this.getPrefix()) + + '(-)?([0-9' + groupSepEsc + ']+)' + + '(' + decimalSepEsc + '\\d+)?' + + qx.lang.String.escapeRegexpChars(this.getPostfix())); + + var hit = regex.exec(str); + if (hit == null) { + throw new Error("Number string '" + str + "' does not match the number format"); + } + + var negative = (hit[1] == "-"); + var integerStr = hit[2]; + var fractionStr = hit[3]; + + // Remove the thousand groupings + integerStr = integerStr.replace(new RegExp(groupSepEsc), ""); + + var asStr = (negative ? "-" : "") + integerStr; + if (fractionStr != null && fractionStr.length != 0) { + // Remove the leading decimal separator from the fractions string + fractionStr = fractionStr.replace(new RegExp(decimalSepEsc),""); + asStr += "." + fractionStr; + } + return parseFloat(asStr); +}; + + +/** + * Returns the default number format. + * + * @return {NumberFormat} the default number format. + */ +qx.Class.getInstance = function() { + var NumberFormat = qx.util.format.NumberFormat; + if (NumberFormat._instance == null) { + NumberFormat._instance = new NumberFormat(); + } + return NumberFormat._instance; +}; + + +/** + * Returns an integer number format. + * + * @return {NumberFormat} an integer number format. + */ +qx.Class.getIntegerInstance = function() { + var NumberFormat = qx.util.format.NumberFormat; + if (NumberFormat._integerInstance == null) { + NumberFormat._integerInstance = new NumberFormat(); + NumberFormat._integerInstance.setMaximumFractionDigits(0); + } + return NumberFormat._integerInstance; +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js new file mode 100644 index 0000000000..d91ab45858 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js @@ -0,0 +1,1402 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006, 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(util_fsm) + +************************************************************************ */ + +/** + * A finite state machine. + * + * See {@link qx.util.finitestatemacine.State} for details on creating States, + * and {@link qx.util.finitestatemacine.Transitions} for details on creating + * transitions between states. + * + * @param machineName {String} The name of this finite state machine + * + */ +qx.OO.defineClass("qx.util.fsm.FiniteStateMachine", qx.core.Target, +function(machineName) +{ + // Call our superclass' constructor + qx.core.Target.call(this); + + // Save the machine name + this.setName(machineName); + + // Initialize the states object + this._states = { }; + + // Initialize the saved-states stack + this._savedStates = [ ]; + + // Initialize the pending event queue + this._eventQueue = [ ]; + + // Initialize the blocked events queue + this._blockedEvents = [ ]; + + // Create the friendlyToObject" object. Each object has as its property + // name, the friendly name of the object; and as its property value, the + // object itself. + this._friendlyToObject = { }; + + // Create the "friendlyToHash" object. Each object has as its property + // name, the friendly name of the object; and as its property value, the + // hash code of the object. + this._friendlyToHash = { }; + + // Create the "hashToFriendly" object. Each object has as its property + // name, the hash code of the object; and as its property value, the + // friendly name of the object. + this._hashToFriendly = { }; + + // Friendly names can be added to groups, for easy manipulation of enabling + // and disabling groups of widgets. Track which friendly names are in which + // group. + this._groupToFriendly = { }; + + // We also need to be able to map back from friendly name to the groups it + // is in. + this._friendlyToGroups = { }; +}); + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * The name of this finite state machine (for debug messages) + */ +qx.OO.addProperty( + { + name : "name", + type : "string" + }); + +/** + * The current state of the finite state machine. + */ +qx.OO.addProperty( + { + name : "state", + type : "string" + }); + +/** + * The previous state of the finite state machine, i.e. the state from which + * we most recently transitioned. Note that this could be the same as the + * current state if a successful transition brought us back to the same + * state. + */ +qx.OO.addProperty( + { + name : "previousState", + type : "string" + }); + +/** + * The state to which we will be transitioning. This property is valid only + * during a Transition's ontransition function and a State's onexit function. + * At all other times, it is null. + */ +qx.OO.addProperty( + { + name : "nextState", + type : "string" + }); + + +/** + * The maximum number of states which may pushed onto the state-stack. It is + * generally a poor idea to have very many states saved on a stack. Following + * program logic becomes very difficult, and the code can be highly + * unmaintainable. The default should be more than adequate. You've been + * warned. + */ +qx.OO.addProperty( + { + name : "maxSavedStates", + type : "number", + defaultValue : 2 + }); + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + + +/** + * Add a state to the finite state machine. + * + * @param state {qx.util.fsm.State} + * An object of class qx.util.fsm.State representing a state + * which is to be a part of this finite state machine. + */ +qx.Proto.addState = function(state) +{ + // Ensure that we got valid state info + if (! state instanceof qx.util.fsm.State) + { + throw new Error("Invalid state: not an instance of " + + "qx.util.fsm.State"); + } + + // Retrieve the name of this state + var stateName = state.getName(); + + // Ensure that the state name doesn't already exist + if (stateName in this._states) + { + throw new Error("State " + state + " already exists"); + } + + // Add the new state object to the finite state machine + this._states[stateName] = state; +}; + + +/** + * Replace a state in the finite state machine. This is useful if initially + * "dummy" states are created which load the real state table for a series of + * operations (and possibly also load the gui associated with the new states + * at the same time). Having portions of the finite state machine and their + * associated gui pages loaded at run time can help prevent long delays at + * application start-up time. + * + * @param state {qx.util.fsm.State} + * An object of class qx.util.fsm.State representing a state + * which is to be a part of this finite state machine. + * + * @param bDispose {Boolean} + * If <i>true</i>, then dispose the old state object. If <i>false</i>, the + * old state object is returned for disposing by the caller. + * + * @return {Object} + * The old state object if it was not disposed; otherwise null. + */ +qx.Proto.replaceState = function(state, bDispose) +{ + // Ensure that we got valid state info + if (! state instanceof qx.util.fsm.State) + { + throw new Error("Invalid state: not an instance of " + + "qx.util.fsm.State"); + } + + // Retrieve the name of this state + var stateName = state.getName(); + + // Save the old state object, so we can return it to be disposed + var oldState = this._states[stateName]; + + // Replace the old state with the new state object. + this._states[stateName] = state; + + // Did they request that the old state be disposed? + if (bDispose) + { + // Yup. Mark it to be disposed. + oldState._needDispose; + } + + return oldState; +}; + + + +/** + * Add an object (typically a widget) that is to be accessed during state + * transitions, to the finite state machine. + * + * @param friendlyName {String} + * The friendly name to used for access to the object being added. + * + * @param obj {Object} + * The object to associate with the specified friendly name + * + * @param groupNames {Array} + * An optional list of group names of which this object is a member. + */ +qx.Proto.addObject = function(friendlyName, obj, groupNames) +{ + var hash = obj.toHashCode(); + this._friendlyToHash[friendlyName] = hash; + this._hashToFriendly[hash] = friendlyName; + this._friendlyToObject[friendlyName] = obj; + + // If no groupNames are specified, we're done. + if (! groupNames) + { + return; + } + + // Allow either a single group name or an array of group names. If the + // former, we convert it to the latter to make the subsequent code simpler. + if (typeof(groupNames) == "string") + { + groupNames = [ groupNames ]; + } + + // For each group that this friendly name is to be a member of... + for (var i = 0; i < groupNames.length; i++) + { + var groupName = groupNames[i]; + + // If the group name doesn't yet exist... + if (! this._groupToFriendly[groupName]) + { + // ... then create it. + this._groupToFriendly[groupName] = { }; + } + + // Add the friendly name to the list of names in this group + this._groupToFriendly[groupName][friendlyName] = true; + + // If the friendly name group mapping doesn't yet exist... + if (! this._friendlyToGroups[friendlyName]) + { + // ... then create it. + this._friendlyToGroups[friendlyName] = [ ]; + } + + // Append this group name to the list of groups this friendly name is in + this._friendlyToGroups[friendlyName] = + this._friendlyToGroups[friendlyName].concat(groupNames); + } +}; + + +/** + * Remove an object which had previously been added by {@link #addObject}. + * + * @param friendlyName {String} + * The friendly name associated with an object, specifying which object is + * to be removed. + */ +qx.Proto.removeObject = function(friendlyName) +{ + var hash = this._friendlyToHash[friendlyName]; + + // Delete references to any groupos this friendly name was in + if (this._friendlyToGroups[friendlyName]) + { + for (groupName in this._friendlyToGroups[friendlyName]) + { + delete this._groupToFriendly[groupName]; + } + + delete this._friendlyToGroups[friendlyName]; + } + + // Delete the friendly name + delete this._hashToFriendly[hash]; + delete this._friendlyToHash[friendlyName]; + delete this._friendlyToObject[friendlyName]; +}; + + +/** + * Retrieve an object previously saved via {@link #addObject}, using its + * Friendly Name. + * + * @param friendlyName {String} + * The friendly name of the object to be retrieved. + * + * @return {Object} + * The object which has the specified friendly name, or undefined if no + * object has been associated with that name. + */ +qx.Proto.getObject = function(friendlyName) +{ + return this._friendlyToObject[friendlyName]; +}; + + +/** + * Get the friendly name of an object. + * + * @param obj {Object} The object for which the friendly name is desired + * + * @return {String} + * If the object has been previously registered via {@link #addObject}, then + * the friendly name of the object is returned; otherwise, null. + */ +qx.Proto.getFriendlyName = function(obj) +{ + var hash = obj.toHashCode(); + return hash ? this._hashToFriendly[hash] : null; +}; + + +/** + * Retrieve the list of objects which have registered, via {@link addObject} as + * being members of the specified group. + * + * @param groupName {String} + * The name of the group for which the member list is desired. + * + * @return {Array} + * An array containing the friendly names of any objects which are members + * of the specified group. The resultant array may be empty. + */ +qx.Proto.getGroupObjects = function(groupName) +{ + var a = [ ]; + + for (var name in this._groupToFriendly[groupName]) + { + a.push(name); + } + + return a; +}; + + +/** + * Display all of the saved objects and their reverse mappings. + */ +qx.Proto.displayAllObjects = function() +{ + for (var friendlyName in this._friendlyToHash) + { + var hash = this._friendlyToHash[friendlyName]; + var obj = this.getObject(friendlyName); + this.debug(friendlyName + + " => " + + hash); + this.debug(" " + hash + + " => " + + this._hashToFriendly[hash]); + this.debug(" " + friendlyName + + " => " + + this.getObject(friendlyName)); + this.debug(" " + this.getObject(friendlyName) + + " => " + + this.getFriendlyName(obj)); + } +}; + + +/** + * Recursively display an object (as debug messages) + * + * @param obj {Object} + * The object to be recursively displayed + * @param initialMessage {String} + * The initial message to be displayed. + */ +qx.Proto.debugObject = function(obj, initialMessage) +{ + thisClass = this; + + var displayObj = function(obj, level) + { + var indentStr = ""; + for (var i = 0; i < level; i++) + { + indentStr += " "; + } + + if (typeof(obj) != "object") + { + thisClass.debug(indentStr, obj); + return; + } + + for (var prop in obj) + { + if (typeof(obj[prop]) == "object") + { + if (obj[prop] instanceof Array) + { + thisClass.debug(indentStr + prop + ": " + "Array"); + } + else + { + thisClass.debug(indentStr + prop + ": " + "Object"); + } + + displayObj(obj[prop], level + 1); + } + else + { + thisClass.debug(indentStr + prop + ": " + obj[prop]); + } + } + } + + if (initialMessage) + { + this.debug(initialMessage); + } + + displayObj(obj, 0); +}; + + + +/** + * Start (or restart, after it has terminated) the finite state machine from + * the starting state. The starting state is defined as the first state added + * to the finite state machine. + */ +qx.Proto.start = function() +{ + var stateName; + + // Set the start state to be the first state which was added to the machine + for (stateName in this._states) + { + this.setState(stateName); + this.setPreviousState(null); + this.setNextState(null); + break; + } + + if (! stateName) + { + throw new Error("Machine started with no available states"); + } + + var debugFunctions = + (qx.Settings.getValueOfClass("qx.util.fsm.FiniteStateMachine", + "debugFlags") & + qx.util.fsm.FiniteStateMachine.DebugFlags.FUNCTION_DETAIL); + + // Run the actionsBeforeOnentry actions for the initial state + if (debugFunctions) + { + this.debug(this.getName() + "#" + stateName + "#actionsBeforeOnentry"); + } + this._states[stateName].getAutoActionsBeforeOnentry()(this); + + // Run the entry function for the new state, if one is specified + if (debugFunctions) + { + this.debug(this.getName() + "#" + stateName + "#entry"); + } + this._states[stateName].getOnentry()(this, null); + + // Run the actionsAfterOnentry actions for the initial state + if (debugFunctions) + { + this.debug(this.getName() + "#" + stateName + "#actionsAfterOnentry"); + } + this._states[stateName].getAutoActionsAfterOnentry()(this); + +}; + + +/** + * Save the current or previous state on the saved-state stack. A future + * transition can then provide, as its nextState value, the class constant: + * + * qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK + * + * which will cause the next state to be whatever is at the top of the + * saved-state stack, and remove that top element from the saved-state stack. + * + * @param bCurrent {Boolean} + * When <i>true</i>, then push the current state onto the stack. This might + * be used in a transition, before the state has changed. When + * <i>false</i>, then push the previous state onto the stack. This might be + * used in an on entry function to save the previous state to return to. + */ +qx.Proto.pushState = function(bCurrent) +{ + // See if there's room on the state stack for a new state + if (this._savedStates.length >= this.getMaxSavedStates()) + { + // Nope. Programmer error. + throw new Error("Saved-state stack is full"); + } + + if (bCurrent) + { + // Push the current state onto the saved-state stack + this._savedStates.push(this.getState()); + } + else + { + // Push the previous state onto the saved-state stack + this._savedStates.push(this.getPreviousState()); + } +}; + + +/** + * Add the specified event to a list of events to be passed to the next state + * following state transition. + * + * @param event {qx.event.type.Event} + * The event to add to the event queue for processing after state change. + */ +qx.Proto.postponeEvent = function(event) +{ + // Add this event to the blocked event queue, so it will be passed to the + // next state upon transition. + this._blockedEvents.unshift(event); +}; + + +/** + * Copy an event + * + * @param event {qx.event.type.Event} + * The event to be copied + * + * @return {qx.event.type.Event} + * The new copy of the provided event + */ +qx.Proto.copyEvent = function(event) +{ + var e = { }; + for (var prop in event) + { + e[prop] = event[prop]; + } + + return e; +}; + + +/** + * Enqueue an event for processing + * + * @param event {qx.event.type.Event} + * The event to be enqueued + * + * @param bAddAtHead {Boolean} + * If <i>true</i>, put the event at the head of the queue for immediate + * processing. If <i>false</i>, place the event at the tail of the queue so + * that it receives in-order processing. + */ +qx.Proto.enqueueEvent = function(event, bAddAtHead) +{ + // Add the event to the event queue + if (bAddAtHead) + { + // Put event at the head of the queue + this._eventQueue.push(event); + } + else + { + // Put event at the tail of the queue + this._eventQueue.unshift(event); + } + + if (qx.Settings.getValueOfClass("qx.util.fsm.FiniteStateMachine", + "debugFlags") & + qx.util.fsm.FiniteStateMachine.DebugFlags.EVENTS) + { + if (bAddAtHead) + { + this.debug(this.getName() + ": Pushed event: " + event.getType()); + } + else + { + this.debug(this.getName() + ": Queued event: " + event.getType()); + } + } +}; + + +/** + * Event listener for all event types in the finite state machine + * + * @param event {qx.event.type.Event} + * The event that was dispatched. + */ +qx.Proto.eventListener = function(event) +{ + // Events are enqueued upon receipt. Some events are then processed + // immediately; other events get processed later. We need to allow the + // event dispatcher to free the source event upon our return, so we'll clone + // it and enqueue our clone. The source event can then be disposed upon our + // return. + var e = this.copyEvent(event); + + // Enqueue the new event on the tail of the queue + this.enqueueEvent(e, false); + + // Process events + this._processEvents(); +}; + + +/** + * Process all of the events on the event queue. + */ +qx.Proto._processEvents = function() +{ + // eventListener() can potentially be called while we're processing events + if (this._eventProcessingInProgress) + { + // We were processing already, so don't process concurrently. + return; + } + + // Track that we're processing events + this._eventProcessingInProgress = true; + + // Process each of the events on the event queue + while (this._eventQueue.length > 0) + { + // Pull the next event from the pending event queue + var event = this._eventQueue.pop(); + + // Run the finite state machine with this event + var bDispose = this._run(event); + + // If we didn't block (and re-queue) the event, dispose it. + if (bDispose) + { + event.dispose(); + } + } + + // We're no longer processing events + this._eventProcessingInProgress = false; +}; + +/** + * Run the finite state machine to process a single event. + * + * @param event {qx.event.type.Event} + * An event that has been dispatched. The event may be handled (if the + * current state handles this event type), queued (if the current state + * blocks this event type), or discarded (if the current state neither + * handles nor blocks this event type). + * + * @return {Boolean} + * Whether the event should be disposed. If it was blocked, we've pushed it + * back onto the event queue, and it should not be disposed. + */ +qx.Proto._run = function(event) +{ + // For use in generated functions... + var fsm = this; + + // State name variables + var thisState; + var nextState; + var prevState; + + // The current State object + var currentState; + + // The transitions available in the current State + var transitions; + + // Events handled by the current State + var e; + + // The action to take place upon receipt of a particular event + var action; + + // Get the debug flags + var debugFlags = + (qx.Settings.getValueOfClass("qx.util.fsm.FiniteStateMachine", + "debugFlags")); + + // Allow slightly faster access to determine if debug is enableda + var debugEvents = + debugFlags & qx.util.fsm.FiniteStateMachine.DebugFlags.EVENTS; + var debugTransitions = + debugFlags & qx.util.fsm.FiniteStateMachine.DebugFlags.TRANSITIONS; + var debugFunctions = + debugFlags & qx.util.fsm.FiniteStateMachine.DebugFlags.FUNCTION_DETAIL; + var debugObjectNotFound = + debugFlags & qx.util.fsm.FiniteStateMachine.DebugFlags.OBJECT_NOT_FOUND; + + if (debugEvents) + { + this.debug(this.getName() + ": Process event: " + event.getType()); + } + + // Get the current state name + thisState = this.getState(); + + // Get the current State object + currentState = this._states[thisState]; + + // Get a list of the transitions available from this state + transitions = currentState.transitions; + + // Determine how to handle this event + e = currentState.getEvents()[event.getType()]; + + // See if we actually found this event type + if (! e) + { + if (debugEvents) + { + this.debug(this.getName() + ": Event '" + event.getType() + "'" + + " not handled. Ignoring."); + } + return true; + } + + // We might have found a constant (PREDICATE or BLOCKED) or an object with + // each property name being the friendly name of a saved object, and the + // property value being one of the constants (PREDICATE or BLOCKED). + if (typeof(e) == "object") + { + // Individual objects are listed. Ensure target is a saved object + var friendly = this.getFriendlyName(event.getTarget()); + if (! friendly) + { + // Nope, it doesn't seem so. Just discard it. + if (debugObjectNotFound) + { + this.debug(this.getName() + ": Could not find friendly name for '" + + event.getType() + "' on '" + event.getTarget() + "'"); + } + return true; + } + + action = e[friendly]; + } + else + { + action = e; + } + + switch(action) + { + case qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE: + // Process this event. One of the transitions should handle it. + break; + + case qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED: + // This event is blocked. Enqueue it for later, and get outta here. + if (debugEvents) + { + this.debug(this.getName() + ": Event '" + event.getType() + "'" + + " blocked. Re-queuing."); + } + this._blockedEvents.unshift(event); + return false; + + default: + // See if we've been given an explicit transition name + if (typeof(action) == "string") + { + // Yup! Ensure that it exists + if (transitions[action]) + { + // Yup. Create a transitions object containing only this transition. + var trans = transitions[action]; + transitions = { }; + transitions[action] = trans; + } + else + { + throw new Error("Explicit transition " + action + " does not exist"); + } + + break; + } + } + + // We handle the event. Try each transition in turn until we find one that + // is acceptable. + for (var t in transitions) + { + var trans = transitions[t]; + + // Does the predicate allow use of this transition? + switch(trans.getPredicate()(this, event)) + { + case true: + // Transition is allowed. Proceed. + break; + + case false: + // Transition is not allowed. Try next transition. + continue; + + case null: + // Transition indicates not to try further transitions + return true; + + default: + throw new Error("Transition " + thisState + ":" + t + + " returned a value other than true, false, or null."); + } + + // We think we can transition to the next state. Set next state. + nextState = trans.getNextState(); + if (typeof(nextState) == "string") + { + // We found a literal state name. Ensure it exists. + if (! nextState in this._states) + { + throw new Error("Attempt to transition to nonexistent state " + + nextState); + } + + // It exists. Track it being the next state. + this.setNextState(nextState); + } + else + { + // If it's not a string, nextState must be a StateChange constant + switch(nextState) + { + case qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE: + // They want to remain in the same state. + nextState = thisState; + this.setNextState(nextState) + break; + + case qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: + // Switch to the state at the top of the state stack. + if (this._savedStates.length == 0) + { + throw new Error("Attempt to transition to POP_STATE_STACK " + + "while state stack is empty."); + } + + // Pop the state stack to retrieve the state to transition to + nextState = this._savedStates.pop(); + this.setNextState(nextState); + break; + + default: + throw new Error("Internal error: invalid nextState"); + break; + } + } + + // Run the actionsBeforeOntransition actions for this transition + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#" + t + + "#autoActionsBeforeOntransition"); + } + trans.getAutoActionsBeforeOntransition()(this); + + // Run the 'ontransition' function + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#" + t + "#ontransition"); + } + trans.getOntransition()(this, event); + + // Run the autoActionsAfterOntransition actions for this transition + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#" + t + + "#autoActionsAfterOntransition"); + } + trans.getAutoActionsAfterOntransition()(this); + + // Run the autoActionsBeforeOnexit actions for the old state + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + + "#autoActionsBeforeOnexit"); + } + currentState.getAutoActionsBeforeOnexit()(this); + + // Run the exit function for the old state + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#exit"); + } + currentState.getOnexit()(this, event); + + // Run the autoActionsAfterOnexit actions for the old state + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#autoActionsAfterOnexit"); + } + currentState.getAutoActionsAfterOnexit()(this); + + // If this state has been replaced and we're supposed to dispose it... + if (currentState._needDispose) + { + // ... then dispose it now that it's no longer in use + currentState.dispose(); + } + + // Reset currentState to the new state object + currentState = this._states[this.getNextState()]; + + // set previousState and state, and clear nextState, for transition + this.setPreviousState(thisState); + this.setState(this.getNextState()); + this.setNextState(null); + prevState = thisState; + thisState = nextState; + nextState = undefined; + + // Run the autoActionsBeforeOnentry actions for the new state + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + + "#autoActionsBeforeOnentry"); + } + currentState.getAutoActionsBeforeOnentry()(this); + + // Run the entry function for the new state, if one is specified + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + "#entry"); + } + currentState.getOnentry()(this, event); + + // Run the autoActionsAfterOnentry actions for the new state + if (debugFunctions) + { + this.debug(this.getName() + "#" + thisState + + "#autoActionsAfterOnentry"); + } + currentState.getAutoActionsAfterOnentry()(this); + + // Add any blocked events back onto the pending event queue + var e; + for (var i = 0; i < this._blockedEvents.length; i++) + { + e = this._blockedEvents.pop(); + this._eventQueue.unshift(e); + } + + // Ensure that all actions have been flushed + qx.ui.core.Widget.flushGlobalQueues(); + + if (debugTransitions) + { + this.debug(this.getName() + "#" + prevState + " => " + + this.getName() + "#" + thisState); + } + + // See ya! + return true; + } + + if (debugTransitions) + { + this.debug(this.getName() + "#" + thisState + + ": event '" + event.getType() + "'" + + ": no transition found. No state change."); + } + + return true; +}; + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + + + +/* +--------------------------------------------------------------------------- + CLASS CONSTANTS +--------------------------------------------------------------------------- +*/ + +/** + * Constants which may be values of the nextState member in the transitionInfo + * parameter of the Transition constructor. + */ +qx.Class.StateChange = +{ + /** When used as a nextState value, means remain in current state */ + CURRENT_STATE : 1, + + /** When used as a nextState value, means go to most-recently pushed state */ + POP_STATE_STACK : 2, + + /** When used as a nextState value, means terminate this state machine */ + TERMINATE : 3 +}; + + +/** + * Constants for use in the events member of the transitionInfo parameter of + * the Transition constructor. + */ +qx.Class.EventHandling = +{ + /** + * This event is handled by this state, but the predicate of a transition + * will determine whether to use that transition. + */ + PREDICATE : 1, + + /** Enqueue this event for possible use by the next state */ + BLOCKED : 2 +}; + +/** + * Debug bitmask values. Set the debug flags from the application by or-ing + * together bits, akin to this: + * + * qx.Settings.setCustomOfClass( + * "qx.util.fsm.FiniteStateMachine", + * "debugFlags", + * (qx.util.fsm.FiniteStateMachine.DebugFlags.EVENTS | + * qx.util.fsm.FiniteStateMachine.DebugFlags.TRANSITIONS | + * qx.util.fsm.FiniteStateMachine.DebugFlags.FUNCTION_DETAIL | + * qx.util.fsm.FiniteStateMachine.DebugFlags.OBJECT_NOT_FOUND)); + */ +qx.Class.DebugFlags = +{ + /** Show events */ + EVENTS : 1, + + /** Show transitions */ + TRANSITIONS : 2, + + /** Show individual function invocations during transitions */ + FUNCTION_DETAIL : 4, + + /** When object friendly names are referenced but not found, show message */ + OBJECT_NOT_FOUND : 8 +}; + + +/* +--------------------------------------------------------------------------- + CLASS DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +/** + * Debug flags: bitmap of DebugFlags (see Class Constants). + */ +qx.Settings.setDefault( + "debugFlags", + (qx.util.fsm.FiniteStateMachine.DebugFlags.EVENTS | + qx.util.fsm.FiniteStateMachine.DebugFlags.TRANSITIONS | + qx.util.fsm.FiniteStateMachine.DebugFlags.OBJECT_NOT_FOUND)); + + +/* +--------------------------------------------------------------------------- + CLASS FUNCTIONS +--------------------------------------------------------------------------- +*/ + +/** + * Common function used by {qx.util.fsm.State} and + * {qx.util.fsm.Transition} for checking the value provided for + * auto actions. + * + * Auto-action property values passed to us look akin to: + * + * <pre> + * { + * // The name of a function. + * "setEnabled" : + * [ + * { + * // The parameter value(s), thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ] + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ], + * } + * ]; + * + * "setColor" : + * [ + * { + * "parameters" : [ "blue" ] + * "groups" : [ "group3", "group4" ], + * "objects" : [ "obj3", "obj4" ] + * } + * ]; + * }; + * </pre> + * + * @param actionType {String} + * The name of the action being validated (for debug messages) + * + * @param propValue {Object} + * The property value which is being validated + * + * @param propData + * Not used + */ +qx.Class._commonCheckAutoActions = function(actionType, propValue, propData) +{ + // Validate that we received an object property value + if (typeof(propValue) != "object") + { + throw new Error("Invalid " + actionType + " value: " + typeof(propValue)); + } + + // We'll create a function to do the requested actions. Initialize the + // string into which we'll generate the common fragment added to the + // function for each object. + var funcFragment; + + // Here, we'll keep the function body. Initialize a try block. + var func = + "try" + + "{"; + + var param; + var objectAndGroupList; + + // Retrieve the function request, e.g. + // "enabled" : + for (var f in propValue) + { + // Get the function request value object, e.g. + // "setEnabled" : + // [ + // { + // "parameters" : [ true ], + // "objects" : [ "obj1", "obj2" ] + // "groups" : [ "group1", "group2" ], + // } + // ]; + var functionRequest = propValue[f]; + + // The function request value should be an object + if (! functionRequest instanceof Array) + { + throw new Error("Invalid function request type: " + + "expected array, found " + typeof(functionRequest)); + } + + // For each function request... + for (var i = 0; i < functionRequest.length; i++) + { + // Retreive the object and group list object + objectAndGroupList = functionRequest[i]; + + // The object and group list should be an object, e.g. + // { + // "parameters" : [ true ], + // "objects" : [ "obj1", "obj2" ] + // "groups" : [ "group1", "group2" ], + // } + if (typeof(objectAndGroupList) != "object") + { + throw new Error("Invalid function request parameter type: " + + "expected object, found " + + typeof(functionRequest[param])); + } + + // Retrieve the parameter list + params = objectAndGroupList["parameters"]; + + // If it didn't exist, ... + if (! params) + { + // ... use an empty array. + params = [ ]; + } + else + { + // otherwise, ensure we got an array + if (! params instanceof Array) + { + throw new Error("Invalid function parameters: " + + "expected array, found " + typeof(params)); + } + } + + // Create the function to call on each object. The object on which the + // function is called will be prepended later. + funcFragment = f + "("; + + // For each parameter... + for (var j = 0; j < params.length; j++) + { + // If this isn't the first parameter, add a separator + if (j != 0) + { + funcFragment += ","; + } + + if (typeof(params[j]) == "function") + { + // If the parameter is a function, arrange for it to be called + // at run time. + funcFragment += "(" + params[j] + ")(fsm)"; + } + else if (typeof(params[j]) == "string") + { + // If the parameter is a string, quote it. + funcFragment += '"' + params[j] + '"'; + } + else + { + // Otherwise, just add the parameter's literal value + funcFragment += params[j]; + } + } + + // Complete the function call + funcFragment += ")"; + + // Get the "objects" list, e.g. + // "objects" : [ "obj1", "obj2" ] + var a = objectAndGroupList["objects"]; + + // Was there an "objects" list? + if (! a) + { + // Nope. Simplify code by creating an empty array. + a = [ ]; + } + else if (! a instanceof Array) + { + throw new Error("Invalid 'objects' list: expected array, got " + + typeof(a)); + } + + for (var j = 0; j < a.length; j++) + { + // Ensure we got a string + if (typeof(a[j]) != "string") + { + throw new Error("Invalid friendly name in 'objects' list: " + a[j]); + } + + func += " fsm.getObject('" + a[j] + "')." + funcFragment + ";"; + } + + // Get the "groups" list, e.g. + // "groups" : [ "group1, "group2" ] + var g = objectAndGroupList["groups"]; + + // Was a "groups" list found? + if (g) + { + // Yup. Ensure it's an array. + if (! g instanceof Array) + { + throw new Error("Invalid 'groups' list: expected array, got " + + typeof(g)); + } + + for (var groupName in g) + { + // Arrange to call the function on each object in each group + func += + " var groupObjects = " + + " fsm.getGroupObjects('" + g[groupName] + "');" + + " for (var i = 0; i < groupObjects.length; i++)" + + " {" + + " var objName = groupObjects[i];" + + " fsm.getObject(objName)." + funcFragment + ";" + + " }"; + } + } + } + } + + // Terminate the try block for function invocations + func += + "}" + + "catch(e)" + + "{" + + " fsm.debug(e);" + + "}"; + +// o = new qx.core.Object(); +// o.debug("Dynamically created " + actionType + "(fsm) { " + func + " }"); + + // We've now built the entire body of a function that implements calls to + // each of the requested automatic actions. Create and return the function, + // which will become the property value. + return new Function("fsm", func); +}; + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + var e; + var s; + + if (this.getDisposed()) { + return true; + } + + while (this._savedStates.length > 0) + { + s = this._savedStates.pop(); + s = null; + } + this._savedStates = null; + + while (this._eventQueue.length > 0) + { + e = this._eventQueue.pop(); + e.dispose(); + e = null; + } + this._eventQueue = null; + + while (this._blockedEvents.length > 0) + { + e = this._blockedEvents.pop(); + e.dispose(); + e = null; + } + + for (var s in this._states) + { + this._states[s].dispose(); + this._states[s] = null; + delete this._states[s]; + } + this._states = null; + + return qx.core.Target.prototype.dispose.call(this); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/State.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/State.js new file mode 100644 index 0000000000..6a3743a2b3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/State.js @@ -0,0 +1,613 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006, 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(util_fsm) +#require(qx.util.fsm.FiniteStateMachine) + +************************************************************************ */ + +/** + * Create a new state which may be added to a finite state machine. + * + * @param + * stateName - + * The name of this state. This is the name which may be referenced in + * objects of class qx.util.fsm.Transition, when passing of + * the the transition's predicate means transition to this state. + * + * @param + * stateInfo - + * An object containing any of the following properties: + * + * onentry - + * A function which is called upon entry to the state. Its signature is + * function(fsm, event) and it is saved in the onentry property of the + * state object. (This function is called after the Transition's action + * function and after the previous state's onexit function.) + * + * In the onentry function: + * + * fsm - + * The finite state machine object to which this state is attached. + * + * event - + * The event that caused the finite state machine to run + * + * onexit - + * A function which is called upon exit from the state. Its signature + * is function(fsm, event) and it is saved in the onexit property of the + * state object. (This function is called after the Transition's action + * function and before the next state's onentry function.) + * + * In the onexit function: + * + * fsm - + * The finite state machine object to which this state is attached. + * + * event - + * The event that caused the finite state machine to run + * + * autoActionsBeforeOnentry - + * autoActionsAfterOnentry - + * autoActionsBeforeOnexit - + * autoActionsAfterOnexit - + * Automatic actions which take place at the time specified by the + * property name. In all cases, the action takes place immediately + * before or after the specified function. + * + * The property value for each of these properties is an object which + * describes some number of functions to invoke on a set of specified + * objects (typically widgets). + * + * An example, using autoActionsBeforeOnentry, might look like this: + * + * "autoActionsBeforeOnentry" : + * { + * // The name of a function. + * "enabled" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ], + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ] + * } + * ], + * + * // The name of another function. + * "visible" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ false ], + * + * // The function would be called on each object and group, as + * // described above. + * "objects" : [ "obj3", "obj4" ], + * "groups" : [ "group3", "group4" ] + * } + * ] + * }; + * + * + * events (required) - + * A description to the finite state machine of how to handle a + * particular event, optionally associated with a specific target object + * on which the event was dispatched. This should be an object + * containing one property for each event which is either handled or + * blocked. The property name should be the event name. The property + * value should be one of: + * + * (a) qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE + * + * (b) qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED + * + * (c) a string containing the name of an explicit Transition to use + * + * (d) an object where each property name is the Friendly Name of an + * object (meaning that this rule applies if both the event and + * the event's target object's Friendly Name match), and its + * property value is one of (a), (b) or (c), above. + * + * This object is saved in the events property of the state object. + * + * Additional properties may be provided in stateInfo. They will not be + * used by the finite state machine, but will be available via + * this.getUserData("<propertyName>") during the state's onentry and + * onexit functions. + */ +qx.OO.defineClass("qx.util.fsm.State", qx.core.Object, +function(stateName, stateInfo) +{ + // Call our superclass' constructor + qx.core.Object.call(this, true); + + // Save the state name + this.setName(stateName); + + // Ensure they passed in an object + if (typeof(stateInfo) != "object") + { + throw new Error("State info must be an object"); + } + + // Save data from the stateInfo object + for (var field in stateInfo) + { + // If we find one of our properties, call its setter. + switch(field) + { + case "onentry": + this.setOnentry(stateInfo[field]); + break; + + case "onexit": + this.setOnexit(stateInfo[field]); + break; + + case "autoActionsBeforeOnentry": + this.setAutoActionsBeforeOnentry(stateInfo[field]); + break; + + case "autoActionsAfterOnentry": + this.setAutoActionsAfterOnentry(stateInfo[field]); + break; + + case "autoActionsBeforeOnexit": + this.setAutoActionsBeforeOnexit(stateInfo[field]); + break; + + case "autoActionsAfterOnexit": + this.setAutoActionsAfterOnexit(stateInfo[field]); + break; + + case "events": + this.setEvents(stateInfo[field]); + break; + + default: + // Anything else is user-provided data for their own use. Save it. + this.setUserData(field, stateInfo[field]); + + // Log it in case it was a typo and they intended a built-in field + this.debug("State " + stateName + ": " + + "Adding user-provided field to state: " + field); + + break; + } + } + + + // Check for required but missing properties + if (! this.getEvents()) + { + throw new Error("The events object must be provided in new state info"); + } + + + // Initialize the transition list + this.transitions = { }; +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * The name of this state. This name may be used as a Transition's nextState + * value, or an explicit next state in the 'events' handling list in a State. + */ +qx.OO.addProperty( + { + name : "name", + type : "string" + }); + +/** + * The onentry function for this state. This is documented in the + * constructor, and is typically provided through the constructor's stateInfo + * object, but it is also possible (but highly NOT recommended) to change this + * dynamically. + */ +qx.OO.addProperty( + { + name : "onentry", + defaultValue : function(fsm, event) { } + }); + +/** + * The onexit function for this state. This is documented in the constructor, + * and is typically provided through the constructor's stateInfo object, but + * it is also possible (but highly NOT recommended) to change this + * dynamically. + */ +qx.OO.addProperty( + { + name : "onexit", + defaultValue : function(fsm, event) { } + }); + +/** + * Automatic actions to take prior to calling the state's onentry function. + * + * The value passed to setAutoActionsBeforeOnentry() should like something + * akin to: + * + * "autoActionsBeforeOnentry" : + * { + * // The name of a function. This would become "setEnabled(" + * "enabled" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ] + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ], + * } + * ]; + * }; + */ +qx.OO.addProperty( + { + name : "autoActionsBeforeOnentry", + defaultValue : function(fsm, event) { } + }); + +/** + * Automatic actions to take after return from the state's onentry function. + * + * The value passed to setAutoActionsAfterOnentry() should like something akin + * to: + * + * "autoActionsAfterOnentry" : + * { + * // The name of a function. This would become "setEnabled(" + * "enabled" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ] + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ], + * } + * ]; + * }; + */ +qx.OO.addProperty( + { + name : "autoActionsAfterOnentry", + defaultValue : function(fsm, event) { } + }); + +/** + * Automatic actions to take prior to calling the state's onexit function. + * + * The value passed to setAutoActionsBeforeOnexit() should like something akin + * to: + * + * "autoActionsBeforeOnexit" : + * { + * // The name of a function. This would become "setEnabled(" + * "enabled" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ] + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ], + * } + * ]; + * }; + */ +qx.OO.addProperty( + { + name : "autoActionsBeforeOnexit", + defaultValue : function(fsm, event) { } + }); + + +/** + * Automatic actions to take after returning from the state's onexit function. + * + * The value passed to setAutoActionsAfterOnexit() should like something akin + * to: + * + * "autoActionsBeforeOnexit" : + * { + * // The name of a function. This would become "setEnabled(" + * "enabled" : + * [ + * { + * // The parameter value, thus "setEnabled(true);" + * "parameters" : [ true ], + * + * // The function would be called on each object: + * // this.getObject("obj1").setEnabled(true); + * // this.getObject("obj2").setEnabled(true); + * "objects" : [ "obj1", "obj2" ] + * + * // And similarly for each object in each specified group. + * "groups" : [ "group1", "group2" ], + * } + * ]; + * }; + */ +qx.OO.addProperty( + { + name : "autoActionsAfterOnexit", + defaultValue : function(fsm, event) { } + }); + + +/** + * The object representing handled and blocked events for this state. This is + * documented in the constructor, and is typically provided through the + * constructor's stateInfo object, but it is also possible (but highly NOT + * recommended) to change this dynamically. + */ +qx.OO.addProperty( + { + name : "events" + }); + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._checkName = function(propValue, propData) +{ + // Ensure that we got a valid state name + if (typeof(propValue) != "string" || propValue.length < 1) + { + throw new Error("Invalid state name"); + } + + return propValue; +}; + +qx.Proto._checkOnentry = function(propValue, propData) +{ + // Validate the onentry function + switch(typeof(propValue)) + { + case "undefined": + // None provided. Convert it to a null function + return function(fsm, event) {}; + + case "function": + // We're cool. No changes required + return propValue; + + default: + throw new Error("Invalid onentry type: " + typeof(propValue)); + return null; + } +}; + +qx.Proto._checkOnexit = function(propValue, propData) +{ + // Validate the onexit function + switch(typeof(propValue)) + { + case "undefined": + // None provided. Convert it to a null function + return function(fsm, event) {}; + + case "function": + // We're cool. No changes required + return propValue; + + default: + throw new Error("Invalid onexit type: " + typeof(propValue)); + return null; + } +}; + +qx.Proto._checkEvents = function(propValue, propData) +{ + // Validate that events is an object + if (typeof(propValue) != "object") + { + throw new Error("events must be an object"); + } + + // Confirm that each property is a valid value + // The property value should be one of: + // + // (a) qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE + // + // (b) qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED + // + // (c) a string containing the name of an explicit Transition to use + // + // (d) an object where each property name is the Friendly Name of an + // object (meaning that this rule applies if both the event and + // the event's target object's Friendly Name match), and its + // property value is one of (a), (b) or (c), above. + for (var e in propValue) + { + var action = propValue[e]; + if (typeof(action) == "number" && + action != qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE && + action != qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED) + { + throw new Error("Invalid numeric value in events object: " + + e + ": " + action); + } + else if (typeof(action) == "object") + { + for (action_e in action) + { + if (typeof(action[action_e]) == "number" && + action[action_e] != + qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE && + action[action_e] != + qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED) + { + throw new Error("Invalid numeric value in events object " + + "(" + e + "): " + + action_e + ": " + action[action_e]); + } + else if (typeof(action[action_e]) != "string" && + typeof(action[action_e]) != "number") + { + throw new Error("Invalid value in events object " + + "(" + e + "): " + + action_e + ": " + action[action_e]); + } + } + } + else if (typeof(action) != "string" && typeof(action) != "number") + { + throw new Error("Invalid value in events object: " + + e + ": " + propValue[e]); + } + } + + // We're cool. No changes required. + return propValue; +}; + +qx.Proto._checkAutoActionsBeforeOnentry = function(propValue, propData) +{ + return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions( + "autoActionsBeforeOnentry", + propValue, + propData); +}; + +qx.Proto._checkAutoActionsAfterOnentry = function(propValue, propData) +{ + return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions( + "autoActionsAfterOnentry", + propValue, + propData); +}; + +qx.Proto._checkAutoActionsBeforeOnexit = function(propValue, propData) +{ + return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions( + "autoActionsBeforeOnexit", + propValue, + propData); +}; + +qx.Proto._checkAutoActionsAfterOnexit = function(propValue, propData) +{ + return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions( + "autoActionsAfterOnexit", + propValue, + propData); +}; + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +/** + * Add a transition to a state + * + * @param trans {qx.util.fsm.Transition} + * An object of class qx.util.fsm.Transition representing a + * transition which is to be a part of this state. + */ +qx.Proto.addTransition = function(trans) +{ + // Ensure that we got valid transition info + if (! trans instanceof qx.util.fsm.Transition) + { + throw new Error("Invalid transition: not an instance of " + + "qx.util.fsm.Transition"); + } + + // Add the new transition object to the state + this.transitions[trans.getName()] = trans; +}; + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + + + +/* +--------------------------------------------------------------------------- + CLASS CONSTANTS +--------------------------------------------------------------------------- +*/ + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js new file mode 100644 index 0000000000..6854a9c4e3 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js @@ -0,0 +1,381 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006, 2007 Derrell Lipman + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(util_fsm) +#require(qx.util.fsm.FiniteStateMachine) + +************************************************************************ */ + +/** + * Create a new possible transition from one state to another. + * + * @param transitionName {String} + * The name of this transition, used in debug messages. + * + * @param transitionInfo {Object} + * An object optionally containing any of the following properties: + * + * predicate - + * A function which is called to determine whether this transition is + * acceptable. An acceptable transition will cause the transition's + * "ontransition" function to be run, the current state's "onexit" + * function to be run, and the new state's "onentry" function to be run. + * + * The predicate function's signature is function(fsm, event) and it is + * saved in the predicate property of the transition object. In the + * predicate function: + * + * fsm - + * The finite state machine object to which this state is attached. + * + * event - + * The event that caused a run of the finite state machine + * + * The predicate function should return one of the following three + * values: + * + * - true means the transition is acceptable + * + * - false means the transition is not acceptable, and the next + * transition (if one exists) should be tried to determine if it is + * acceptable + * + * - null means that the transition determined that no further + * transitions should be tried. This might be used when the + * transition ascertained that the event is for a target that is not + * available in the current state, and the event has called + * fsm.queueEvent() to have the event delivered upon state + * transition. + * + * It is possible to create a default predicate -- one that will cause a + * transition to be acceptable always -- by either not providing a + * predicate property, or by explicitely either setting the predicate + * property to 'true' or setting it to a function that unconditionally + * returns 'true'. This default transition should, of course, always be + * the last transition added to a state, since no transition added after + * it will ever be tried. + * + * nextState - + * The state to which we transition, if the predicate returns true + * (meaning the transition is acceptable). The value of nextState may + * be: + * + * - a string, the state name of the state to transition to + * + * - One of the constants: + * - qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE: + * Remain in whatever is the current state + * - qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: + * Transition to the state at the top of the saved-state stack, + * and remove the top element from the saved-state stack. + * Elements are added to the saved-state stack using + * fsm.pushState(). It is an error if no state exists on the + * saved-state stack. + * - qx.util.fsm.FiniteStateMachine.StateChange.TERMINATE: + * TBD + * + * autoActionsBeforeOntransition - + * autoActionsAfterOntransition - + * Automatic actions which take place at the time specified by the + * property name. In all cases, the action takes place immediately + * before or after the specified function. + * + * The property value for each of these properties is an object which + * describes some number of functions to invoke on a set of specified + * objects (typically widgets). + * + * See {@link qx.util.fsm.State} for an example of autoActions. + * + * ontransition - + * A function which is called if the predicate function for this + * transition returns true. Its signature is function(fsm, event) and + * it is saved in the ontransition property of the transition object. + * In the ontransition function: + * + * fsm - + * The finite state machine object to which this state is attached. + * + * event - + * The event that caused a run of the finite state machine + * + * Additional properties may be provided in transInfo. They will not be + * used by the finite state machine, but will be available via + * this.getUserData("<propertyName>") during the transition's predicate + * and ontransition functions. + */ +qx.OO.defineClass("qx.util.fsm.Transition", qx.core.Object, +function(transitionName, transitionInfo) +{ + // Call our superclass' constructor + qx.core.Object.call(this, true); + + // Save the state name + this.setName(transitionName); + + // Save data from the transitionInfo object + for (var field in transitionInfo) + { + // If we find one of our properties, call its setter. + switch(field) + { + case "predicate": + this.setPredicate(transitionInfo[field]); + break; + + case "nextState": + this.setNextState(transitionInfo[field]); + break; + + case "autoActionsBeforeOntransition": + this.setAutoActionsBeforeOntransition(transitionInfo[field]); + break; + + case "autoActionsAfterOntransition": + this.setAutoActionsAfterOntransition(transitionInfo[field]); + break; + + case "ontransition": + this.setOntransition(transitionInfo[field]); + break; + + default: + // Anything else is user-provided data for their own use. Save it. + this.setUserData(field, transitionInfo[field]); + + // Log it in case it was a typo and they intended a built-in field + this.debug("Transition " + transitionName + ": " + + "Adding user-provided field to transition: " + field); + + break; + } + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/** + * The name of this transition + */ +qx.OO.addProperty( + { + name : "name", + type : "string" + }); + +/** + * The predicate function for this transition. This is documented in the + * constructor, and is typically provided through the constructor's + * transitionInfo object, but it is also possible (but highly NOT recommended) + * to change this dynamically. + */ +qx.OO.addProperty( + { + name : "predicate", + defaultValue : function(fsm, event) { return true; } + }); + +/** + * The state to transition to, if the predicate determines that this + * transition is acceptable. This is documented in the constructor, and is + * typically provided through the constructor's transitionInfo object, but it + * is also possible (but highly NOT recommended) to change this dynamically. + */ +qx.OO.addProperty( + { + name : "nextState", + defaultValue : qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE + }); + +/** + * Automatic actions to take prior to calling the transition's ontransition + * function. This is documented in the constructor, and is typically provided + * through the constructor's transitionInfo object, but it is also possible + * (but highly NOT recommended) to change this dynamically. + */ +qx.OO.addProperty( + { + name : "autoActionsBeforeOntransition", + defaultValue : function(fsm, event) { } + }); + +/** + * Automatic actions to take immediately after calling the transition's + * ontransition function. This is documented in the constructor, and is + * typically provided through the constructor's transitionInfo object, but it + * is also possible (but highly NOT recommended) to change this dynamically. + */ +qx.OO.addProperty( + { + name : "autoActionsAfterOntransition", + defaultValue : function(fsm, event) { } + }); + + +/** + * The function run when the transition is accepted. This is documented in + * the constructor, and is typically provided through the constructor's + * transitionInfo object, but it is also possible (but highly NOT recommended) + * to change this dynamically. + */ +qx.OO.addProperty( + { + name : "ontransition", + defaultValue : function(fsm, event) { } + }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._checkName = function(propValue, propData) +{ + // Ensure that we got a valid state name + if (typeof(propValue) != "string" || propValue.length < 1) + { + throw new Error("Invalid transition name"); + } + + return propValue; +}; + +qx.Proto._checkPredicate = function(propValue, propData) +{ + // Validate the predicate. Convert all valid types to function. + switch(typeof(propValue)) + { + case "undefined": + // No predicate means predicate passes + return function(fsm, event) { return true; }; + + case "boolean": + // Convert boolean predicate to a function which returns that value + return function(fsm, event) { return propValue; }; + + case "function": + // Use user-provided function. + return propValue; + + default: + throw new Error("Invalid transition predicate type: " + + typeof(propValue)); + break; + } +}; + +qx.Proto._checkNextState = function(propValue, propData) +{ + // Validate nextState. It must be a string or a number. + switch(typeof(propValue)) + { + case "string": + return propValue; + + case "number": + // Ensure that it's one of the possible state-change constants + switch(propValue) + { + case qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE: + case qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: + case qx.util.fsm.FiniteStateMachine.StateChange.TERMINATE: + return propValue; + + default: + throw new Error("Invalid transition nextState value: " + + propValue + + ": nextState must be an explicit state name, " + + "or one of the Fsm.StateChange constants"); + } + break; + + default: + throw new Error("Invalid transition nextState type: " + typeof(propValue)); + break; + } +}; + +qx.Proto._checkOntransition = function(propValue, propData) +{ + // Validate the ontransition function. Convert undefined to function. + switch(typeof(propValue) ) + { + case "undefined": + // No provided function just means do nothing. Use a null function. + return function(fsm, event) { }; + + case "function": + // Use user-provided function. + return propValue; + + default: + throw new Error("Invalid ontransition type: " + typeof(propValue)); + break; + } +}; + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + + + +/* +--------------------------------------------------------------------------- + CLASS CONSTANTS +--------------------------------------------------------------------------- +*/ + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + return qx.core.Object.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/example.txt b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/example.txt new file mode 100644 index 0000000000..35e8282afe --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/util/fsm/example.txt @@ -0,0 +1,210 @@ +var fsm; +var state; +var trans; + +// Create a new finite state machine called "Test Machine" +fsm = new qx.util.fsm.FiniteStateMachine("Test machine"); + +// State S1 +state = new qx.util.fsm.State( + // State name + "S1", + + // Object with state information + { + // Function called on entry to this state + "onentry" : + function(fsm, event) + { + alert("Previous state: " + fsm.getPreviousState()); + }; + + // Function called on exit from this state + "onexit" : + function(fsm, event) + { + alert("Next state: " + fsm.getNextState()); + }; + + // Automatic actions to take place before a (possibly) new state's onentry + // function is called. + "autoActionsBeforeOnentry" : + { + // The name of a function. + "setEnabled" : + [ + { + // The parameter value(s), thus "setEnabled(true);" + "parameters" : [ true ], + + // The function would be called on each object: + // this.getObject("obj1").setEnabled(true); + // this.getObject("obj2").setEnabled(true); + "objects" : [ "obj1", "obj2" ] + + // And similarly for each object in each specified group. + "groups" : [ "group1", "group2" ], + } + ]; + + "setColor" : + [ + { + "parameters" : [ "blue" ] + "groups" : [ "group3", "group4" ], + "objects" : [ "obj3", "obj4" ] + } + ]; + }; + + // also available, in same format as actionsBeforeOnentry: + // "autoActionsAfterOnentry", + // "autoActionsBeforeOnexit" + // "autoActionsAfterOnexit" + + // Events handled by this state, or queued for processing by a future state + "events" : + { + // The event type "compete" is handled by one of the transitions in this + // state. The transitions will be searched in order of their addition + // to the state, until the predicate for a transition returns true (or + // no predicate is specified for the transition, which is an implicit + // "true") That transition will be used. + "complete" : qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE, + + // The event type "interval" has two objects specified by their + // "friendly name". The action when an event of type "interval" occurs + // depends on which object was the target of the event. + "interval" : + { + // If the target of the event was the object to which we have given + // the friendly name "flash" then use a transition specified by name + "flash" : "S1_S3_interval_flash", + + // If the target of the event was the object to which we have given + // the friendly name "timeout", then enqueue this event for possible + // processing by a future state. + "timeout" : qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED + }, + + // The event type "execute", too, has two objects specified by their + // "friendly name". + "execute" : + { + // If the target of the event was the object to which we have given + // the friend name "ok", search the transitions in order looking for + // one where the predicate is true + "ok" : qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE + + // If the target of the event was the object to which we have given + // the friendly name "restart", then enqueue this event for possible + // processing by a future state. + "restart" : qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED + } + + // all events other than those which are handled or blocked are ignored. + }; + }); + +// Add State S1 to the finite state machine. +fsm.addState(state); + +// Transition from S1 to S2 due to event 1 +trans = new qx.util.fsm.Transition( + // Transition name + "S1_S2_ev1", + + // Object with transition information + { + // return TRUE to pass + "predicate" : + function(fsm, event) + { + var type = event.getType(); + if (type == "somethingWeCareAbout") + { + return true; + } + else if (type == "somethingToHandleInAnotherState") + { + // reattempt event delivery following state transition + fsm.postponeEvent(event); + + // do no further transition attempts for this event for now + return null; + } + else + { + return false; + } + }, + + // if event matches and predicate passes, pop the state stack and go to + // the state which was found at the top of the stack. States are added to + // the state stack by calling fsm.pushState() during a state's onexit + // function or by a transition's action function. + "nextState" : qx.util.fsm.FiniteStateMachine.StateChange..POP_STATE_STACK, + + // action taken during transisition + "action" : + function(fsm, event) + { + // save current state so a future transition can get back to + // this saved state + fsm.pushState(); + } + }); +state.addTransition(trans); + +// Default transition (any event): remain in current state +trans = new qx.util.fsm.Transition( + "S1_S1_default", + { + // true or undefined : always pass + "predicate" : + function(fsm, event) + { + // This predicate does not pass, and we return null to tell the finite + // state machine that no additional transitions in the transition list + // should be tested. (Note that the next transition is the one + // explicitly called for by the "interval" event on the object with + // friendly name "flash". We do not want a predicate search to find + // it. + return null; + }, + + // return to current state + "nextState" : qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE, + }); +state.addTransition(trans); + +// Transition from S1 to S2 due to event 2. Since the previous transition +// returned null in its predicate function, the only way to get to this +// transition is when it is called out explicitly in the state's event list. +// This one was specified for the "interval" event on the object with friendly +// name "flash". +trans = new qx.util.finitestatememachine.Transition( + "S1_S3_interval_flash", + { + // No predicate or a value of 'true' means that the predicate passes as if + // a predicate function returned true. + "predicate" : true, + + // if event matches, go to this state + "nextState" : "S2", + + // action taken during transisition + "action" : + function(fsm, event) + { + alert(this.getName() + "action function"); + } + }); +state.addTransition(trans); + +// We would, of course, need to add state S2 since it is specified in a +// nextState property. That is left as an exercise for the reader. + + +// Initialize and start the machine running +fsm.start(); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Document.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Document.js new file mode 100644 index 0000000000..2585b6920b --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Document.js @@ -0,0 +1,154 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * XML Document + * + * Tested with IE6, Firefox 2.0, WebKit/Safari 3.0 and Opera 9 + * + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/81f3de54-3b79-46dc-8e01-73ca2d94cdb5.asp + * http://developer.mozilla.org/en/docs/Parsing_and_serializing_XML + */ +qx.OO.defineClass("qx.xml.Document"); + +/** + * Create an XML document. + * http://www.w3.org/TR/DOM-Level-2-Core/core.html#i-Document + * + * @param namespaceUri {String|null?null} The namespace URI of the document element to create or null. + * @param qualifiedName {String|null?null} The qualified name of the document element to be created or null. + * + * @return {Document} empty XML document + */ +qx.Class.create = function(namespaceUri, qualifiedName) {}; + +if (document.implementation && document.implementation.createDocument) // The Mozilla style +{ + qx.Class.create = function(namespaceUri, qualifiedName) + { + return document.implementation.createDocument(namespaceUri || "", qualifiedName || "", null); + } +} +else if (qx.core.Client.getInstance().isMshtml()) // The Microsoft style +{ + qx.Class.create = function(namespaceUri, qualifiedName) + { + /* + According to information on the Microsoft XML Team's WebLog + it is recommended to check for availability of MSXML versions 6.0 and 3.0. + Other versions are included for completeness, 5.0 is excluded as it is + "off-by-default" in IE7 (which could trigger a goldbar). + + http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/aabe29a2-bad2-4cea-8387-314174252a74.asp + + */ + var vServers = + [ + "MSXML2.DOMDocument.3.0", + "MSXML2.DOMDocument.6.0", + "MSXML2.DOMDocument.4.0", + "MSXML2.DOMDocument", // v3.0 + "MSXML.DOMDocument", // v2.x + "Microsoft.XMLDOM" // v2.x + ]; + + var vObject; + + for (var i=0, l=vServers.length; i<l; i++) + { + + try + { + vObject = new ActiveXObject(vServers[i]); + break; + } + catch(ex) + { + vObject = null; + } + } + if (qualifiedName && vObject) { + xmlStr = new qx.util.StringBuilder(); + xmlStr.add("<?xml version='1.0' encoding='UTF-8'?>\n<"); + xmlStr.add(qualifiedName); + if (namespaceUri) { + xmlStr.add(" xmlns='"); + xmlStr.add(namespaceUri); + xmlStr.add("'"); + } + xmlStr.add(" />"); + vObject.loadXML(xmlStr.toString()); + } + return vObject; + }; +} +else +{ + throw new Error("This browser does not support xml dom creation."); +} + + +/** + * The string passed in is parsed into a DOM document. + * + * @param str {String} the string to be parsed + * @return {Document} + * + * TODO: move to create() + */ +qx.Class.fromString = function(str) {}; + +if (window.DOMParser) +{ + qx.Class.fromString = function(str) { + var dom = (new DOMParser()).parseFromString(str, "text/xml"); + return dom; + }; +} +else if (qx.core.Client.getInstance().isMshtml()) // The Microsoft style +{ + qx.Class.fromString = function(str) { + var dom = qx.xml.Document.create(); + dom.loadXML(str); + return dom; + }; +} +else +{ + throw new Error("This browser does not support xml dom creation from string."); +} + + +/** + * Check whether an object is a Document instance + * + * @param obj {Object} object to check + * @return {Boolean} whether the object is a Document instance + */ +qx.Class.isDocument = function(obj) { + return (obj.nodeType == qx.dom.Node.DOCUMENT); +}; diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Element.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Element.js new file mode 100644 index 0000000000..c71c57be5c --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Element.js @@ -0,0 +1,142 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * XML Element + * + * Tested with IE6, Firefox 2.0, WebKit/Safari 3.0 and Opera 9 + * + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/81f3de54-3b79-46dc-8e01-73ca2d94cdb5.asp + * http://developer.mozilla.org/en/docs/Parsing_and_serializing_XML + */ +qx.OO.defineClass("qx.xml.Element"); + + +/** + * The subtree rooted by the specified element or document is serialized to a string. + * + * @param element {Element|Document} The root of the subtree to be serialized. This could be any node, including a Document. + * @return {String} + */ +qx.Class.serialize = function(element) {} + +if (window.XMLSerializer) { + qx.Class.serialize = function(element) { + var element = qx.xml.Document.isDocument(element) ? element.documentElement : element; + return (new XMLSerializer()).serializeToString(element); + }; +} +else +{ + qx.Class.serialize = function(element) { + var element = qx.xml.Document.isDocument(element) ? element.documentElement : element; + return element.xml || element.outerHTML; + }; +} + + +/** + * Selects the first XmlNode that matches the XPath expression. + * + * @param element {Element|Document} root element for the search + * @param query {String} XPath query + * @return {Element} first matching element + */ + qx.Class.selectSingleNode = function(element, query) {}; + +if (window.XPathEvaluator) +{ + qx.Class.selectSingleNode = function(element, query) { + var xpe = new XPathEvaluator(); + return xpe.evaluate(query, element, xpe.createNSResolver(element), XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + }; +} +else if(qx.core.Client.getInstance().isMshtml() || document.selectSingleNode) // IE and Opera +{ + qx.Class.selectSingleNode = function(element, query) { + return element.selectSingleNode(query); + }; +} + + +/** + * Selects a list of nodes matching the XPath expression. + * + * @param element {Element|Document} root element for the search + * @param query {String} XPath query + * @return {Element[]} List of matching elements + */ + qx.Class.selectNodes = function(element, query) {}; + +if (window.XPathEvaluator) +{ + qx.Class.selectNodes = function(element, query) { + var xpe = new XPathEvaluator(); + var result = xpe.evaluate(query, element, xpe.createNSResolver(element), XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + var nodes = []; + + for (var i=0; i<result.snapshotLength; i++) { + nodes[i] = result.snapshotItem(i); + } + + return nodes; + }; +} +else if(qx.core.Client.getInstance().isMshtml() || document.selectNodes) // IE and Opera +{ + qx.Class.selectNodes = function(element, query) { + return element.selectNodes(query); + }; +} + + +/** + * Returns a list of elements with the given tag name belonging to the given namespace (http://developer.mozilla.org/en/docs/DOM:element.getElementsByTagNameNS). + * + * @param element {Element|Document} the element from where the search should start. + * Note that only the descendants of this element are included in the search, not the node itself. + * @param namespaceURI is the namespace URI of elements to look for . For example, if you need to look + * for XHTML elements, use the XHTML namespace URI, <tt>http://www.w3.org/1999/xhtml</tt>. + * @param tagname {String} the tagname to look for + * @return {Element[]} a list of found elements in the order they appear in the tree. + */ +qx.Class.getElementsByTagNameNS = function(element, namespaceURI, tagname) {}; + +if (document.getElementsByTagNameNS) +{ + qx.Class.getElementsByTagNameNS = function(element, namespaceURI, tagname) { + return element.getElementsByTagNameNS(namespaceURI, tagname); + }; +} +else if (qx.core.Client.getInstance().isMshtml()) +{ + qx.Class.getElementsByTagNameNS = function(element, namespaceURI, tagname) { + var doc = element.ownerDocument || element; + doc.setProperty("SelectionLanguage", "XPath"); + doc.setProperty("SelectionNamespaces", "xmlns:ns='" + namespaceURI + "'"); + return qx.xml.Element.selectNodes(element, '//ns:' + tagname); + }; +} diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Entity.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Entity.js new file mode 100644 index 0000000000..d4ab84d69f --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Entity.js @@ -0,0 +1,43 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.lang.Object) + +************************************************************************ */ + +/** + * XML Entities + */ +qx.OO.defineClass("qx.xml.Entity"); + + +/** Mapping of XML entity names to the corresponding char code */ +qx.Class.TO_CHARCODE = { + "quot": 34, // " - double-quote + "amp": 38, // & + "lt": 60, // < + "gt": 62, // > + "apos": 39 // XML apostrophe +}; + + +/** Mapping of char codes to XML entity names */ +qx.Class.FROM_CHARCODE = qx.lang.Object.invert(qx.Class.TO_CHARCODE); diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Namespace.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Namespace.js new file mode 100644 index 0000000000..0a054c0a88 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/Namespace.js @@ -0,0 +1,54 @@ +/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+************************************************************************ */
+
+/* ************************************************************************
+
+
+************************************************************************ */
+
+qx.OO.defineClass("qx.xml.Namespace",
+{
+ SVG : "http://www.w3.org/2000/svg",
+ SMIL : "http://www.w3.org/2001/SMIL20/",
+ MML : "http://www.w3.org/1998/Math/MathML",
+ CML : "http://www.xml-cml.org",
+ XLINK : "http://www.w3.org/1999/xlink",
+ XHTML : "http://www.w3.org/1999/xhtml",
+ XUL : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+ XBL : "http://www.mozilla.org/xbl",
+ FO : "http://www.w3.org/1999/XSL/Format",
+ XSL : "http://www.w3.org/1999/XSL/Transform",
+ XSLT : "http://www.w3.org/1999/XSL/Transform",
+ XI : "http://www.w3.org/2001/XInclude",
+ XFORMS : "http://www.w3.org/2002/01/xforms",
+ SAXON : "http://icl.com/saxon",
+ XALAN : "http://xml.apache.org/xslt",
+ XSD : "http://www.w3.org/2001/XMLSchema",
+ DT: "http://www.w3.org/2001/XMLSchema-datatypes",
+ XSI : "http://www.w3.org/2001/XMLSchema-instance",
+ RDF : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ RDFS : "http://www.w3.org/2000/01/rdf-schema#",
+ RSS1 : "http://purl.org/rss/1.0/modules/content/",
+ DC : "http://purl.org/dc/elements/1.1/",
+ DCQ: "http://purl.org/dc/qualifiers/1.0",
+ SOAPENV : "http://schemas.xmlsoap.org/soap/envelope/",
+ WSDL : "http://schemas.xmlsoap.org/wsdl/",
+ ADOBESVGEXTENSIONS : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+});
\ No newline at end of file diff --git a/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/String.js b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/String.js new file mode 100644 index 0000000000..5af99b8a54 --- /dev/null +++ b/webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/xml/String.js @@ -0,0 +1,73 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2007 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL: http://www.gnu.org/licenses/lgpl.html + EPL: http://www.eclipse.org/org/documents/epl-v10.php + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Fabian Jakobs (fjakobs) + +************************************************************************ */ + +/* ************************************************************************ + +#require(qx.lang.Object) + +************************************************************************ */ + +/** + * Escaping and unescaping of XML strings. + */ +qx.OO.defineClass("qx.xml.String"); + + +/** + * Escapes the characters in a <code>String</code> using XML entities. + * + * For example: <tt>"bread" & "butter"</tt> => + * <tt>&quot;bread&quot; &amp; &quot;butter&quot;</tt>. + * + * Supports only the four basic XML entities (gt, lt, quot, amp). + * Does not support DTDs or external entities. + * Note that unicode characters greater than 0x7f are currently escaped to their numerical \\u equivalent. + * + * @see #unescape + * + * @param str {String} the string to be escaped + * @return {String} the escaped string + */ +qx.Class.escape = function(str) { + return qx.dom.String.escapeEntities( + str, + qx.xml.Entity.FROM_CHARCODE + ); +}; + + +/** + * Unescapes a string containing XML entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. + * + * Supports only the four basic XML entities (gt, lt, quot, amp). + * Does not support DTDs or external entities. + * + * @see #escape + * + * @param str {String} the string to be unescaped + * @return {String} the unescaped string + */ +qx.Class.unescape = function(str) { + return qx.dom.String.unescapeEntities( + str, + qx.xml.Entity.TO_CHARCODE + ); +}; |