/qooxdoo/framework/source/class/qx/data/controller/Object.js
JavaScript | 359 lines | 148 code | 36 blank | 175 comment | 41 complexity | 48b46b3b41a8788143e491987f6c25bb MD5 | raw file
- /* ************************************************************************
- qooxdoo - the new era of web development
- http://qooxdoo.org
- Copyright:
- 2004-2009 1&1 Internet AG, Germany, http://www.1und1.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:
- * Martin Wittemann (martinwittemann)
- ************************************************************************ */
- /**
- * <h2>Object Controller</h2>
- *
- * *General idea*
- *
- * The idea of the object controller is to make the binding of one model object
- * containing one or more properties as easy as possible. Therefore the
- * controller can take a model as property. Every property in that model can be
- * bound to one ore more targets properties. The binding will be for
- * atomic types only like Numbers, Strings, ...
- *
- * *Features*
- *
- * * Manages the bindings between the model properties and the different targets
- * * No need for the user to take care of the binding ids
- * * Can create an bidirectional binding (read- / write-binding)
- * * Handles the change of the model which means adding the old targets
- *
- * *Usage*
- *
- * The controller only can work if a model is set. If the model property is
- * null, the controller is not working. But it can be null on any time.
- *
- * *Cross reference*
- *
- * * If you want to bind a list like widget, use {@link qx.data.controller.List}
- * * If you want to bind a tree widget, use {@link qx.data.controller.Tree}
- * * If you want to bind a form widget, use {@link qx.data.controller.Form}
- */
- qx.Class.define("qx.data.controller.Object",
- {
- extend : qx.core.Object,
- /*
- *****************************************************************************
- CONSTRUCTOR
- *****************************************************************************
- */
- /**
- * @param model {qx.core.Object?null} The model for the model property.
- */
- construct : function(model)
- {
- this.base(arguments);
- // create a map for all created binding ids
- this.__bindings = {};
- // create an array to store all current targets
- this.__targets = [];
- if (model != null) {
- this.setModel(model);
- }
- },
- /*
- *****************************************************************************
- PROPERTIES
- *****************************************************************************
- */
- properties :
- {
- /** The model object which does have the properties for the binding. */
- model :
- {
- check: "qx.core.Object",
- event: "changeModel",
- apply: "_applyModel",
- nullable: true
- }
- },
- /*
- *****************************************************************************
- MEMBERS
- *****************************************************************************
- */
- members :
- {
- // private members
- __targets : null,
- __bindings : null,
- /**
- * Apply-method which will be called if a new model has been set.
- * All bindings will be moved to the new model.
- *
- * @param value {qx.core.Object|null} The new model.
- * @param old {qx.core.Object|null} The old model.
- */
- _applyModel: function(value, old) {
- // for every target
- for (var i = 0; i < this.__targets.length; i++) {
- // get the properties
- var targetObject = this.__targets[i][0];
- var targetProperty = this.__targets[i][1];
- var sourceProperty = this.__targets[i][2];
- var bidirectional = this.__targets[i][3];
- var options = this.__targets[i][4];
- var reverseOptions = this.__targets[i][5];
- // remove it from the old if possible
- if (old != undefined) {
- this.__removeTargetFrom(targetObject, targetProperty, sourceProperty, old);
- }
- // add it to the new if available
- if (value != undefined) {
- this.__addTarget(
- targetObject, targetProperty, sourceProperty, bidirectional,
- options, reverseOptions
- );
- } else {
- // in shutdown situations, it may be that the target is already disposed
- if (targetObject.isDisposed()) {
- continue;
- }
- // if the model is null, reset the current target
- if (targetProperty.indexOf("[") == -1) {
- targetObject["reset" + qx.lang.String.firstUp(targetProperty)]();
- } else {
- var open = targetProperty.indexOf("[");
- var index = parseInt(
- targetProperty.substring(open + 1, targetProperty.length - 1)
- );
- targetProperty = targetProperty.substring(0, open);
- var targetArray = targetObject["get" + qx.lang.String.firstUp(targetProperty)]();
- if (index == "last") {
- index = targetArray.length;
- }
- if (targetArray) {
- targetArray.setItem(index, null);
- }
- }
- }
- }
- },
- /**
- * Adds a new target to the controller. After adding the target, the given
- * property of the model will be bound to the targets property.
- *
- * @param targetObject {qx.core.Object} The object on which the property
- * should be bound.
- *
- * @param targetProperty {String} The property to which the binding should
- * go.
- *
- * @param sourceProperty {String} The name of the property in the model.
- *
- * @param bidirectional {Boolean?false} Signals if the binding should also work
- * in the reverse direction, from the target to source.
- *
- * @param options {Map?null} The options Map used by the binding from source
- * to target. The possible options can be found in the
- * {@link qx.data.SingleValueBinding} class.
- *
- * @param reverseOptions {Map?null} The options used by the binding in the
- * reverse direction. The possible options can be found in the
- * {@link qx.data.SingleValueBinding} class.
- */
- addTarget: function(
- targetObject, targetProperty, sourceProperty,
- bidirectional, options, reverseOptions
- ) {
- // store the added target
- this.__targets.push([
- targetObject, targetProperty, sourceProperty,
- bidirectional, options, reverseOptions
- ]);
- // delegate the adding
- this.__addTarget(
- targetObject, targetProperty, sourceProperty,
- bidirectional, options, reverseOptions
- );
- },
- /**
- * Does the work for {@link #addTarget} but without saving the target
- * to the internal target registry.
- *
- * @param targetObject {qx.core.Object} The object on which the property
- * should be bound.
- *
- * @param targetProperty {String} The property to which the binding should
- * go.
- *
- * @param sourceProperty {String} The name of the property in the model.
- *
- * @param bidirectional {Boolean?false} Signals if the binding should also work
- * in the reverse direction, from the target to source.
- *
- * @param options {Map?null} The options Map used by the binding from source
- * to target. The possible options can be found in the
- * {@link qx.data.SingleValueBinding} class.
- *
- * @param reverseOptions {Map?null} The options used by the binding in the
- * reverse direction. The possible options can be found in the
- * {@link qx.data.SingleValueBinding} class.
- */
- __addTarget: function(
- targetObject, targetProperty, sourceProperty,
- bidirectional, options, reverseOptions
- ) {
- // do nothing if no model is set
- if (this.getModel() == null) {
- return;
- }
- // create the binding
- var id = this.getModel().bind(
- sourceProperty, targetObject, targetProperty, options
- );
- // create the reverse binding if necessary
- var idReverse = null
- if (bidirectional) {
- idReverse = targetObject.bind(
- targetProperty, this.getModel(), sourceProperty, reverseOptions
- );
- }
- // save the binding
- var targetHash = targetObject.toHashCode();
- if (this.__bindings[targetHash] == undefined) {
- this.__bindings[targetHash] = [];
- }
- this.__bindings[targetHash].push(
- [id, idReverse, targetProperty, sourceProperty, options, reverseOptions]
- );
- },
- /**
- * Removes the target identified by the three properties.
- *
- * @param targetObject {qx.core.Object} The target object on which the
- * binding exist.
- *
- * @param targetProperty {String} The targets property name used by the
- * adding of the target.
- *
- * @param sourceProperty {String} The name of the property of the model.
- */
- removeTarget: function(targetObject, targetProperty, sourceProperty) {
- this.__removeTargetFrom(
- targetObject, targetProperty, sourceProperty, this.getModel()
- );
- // delete the target in the targets reference
- for (var i = 0; i < this.__targets.length; i++) {
- if (
- this.__targets[i][0] == targetObject
- && this.__targets[i][1] == targetProperty
- && this.__targets[i][2] == sourceProperty
- ) {
- this.__targets.splice(i, 1);
- }
- }
- },
- /**
- * Does the work for {@link #removeTarget} but without removing the target
- * from the internal registry.
- *
- * @param targetObject {qx.core.Object} The target object on which the
- * binding exist.
- *
- * @param targetProperty {String} The targets property name used by the
- * adding of the target.
- *
- * @param sourceProperty {String} The name of the property of the model.
- *
- * @param sourceObject {String} The source object from which the binding
- * comes.
- */
- __removeTargetFrom: function(
- targetObject, targetProperty, sourceProperty, sourceObject
- ) {
- // check for not fitting targetObjects
- if (!(targetObject instanceof qx.core.Object)) {
- // just do nothing
- return;
- }
- var currentListing = this.__bindings[targetObject.toHashCode()];
- // if no binding is stored
- if (currentListing == undefined || currentListing.length == 0) {
- return;
- }
- // go threw all listings for the object
- for (var i = 0; i < currentListing.length; i++) {
- // if it is the listing
- if (
- currentListing[i][2] == targetProperty &&
- currentListing[i][3] == sourceProperty
- ) {
- // remove the binding
- var id = currentListing[i][0];
- sourceObject.removeBinding(id);
- // check for the reverse binding
- if (currentListing[i][1] != null) {
- targetObject.removeBinding(currentListing[i][1]);
- }
- // delete the entry and return
- currentListing.splice(i, 1);
- return;
- }
- }
- }
- },
- /*
- *****************************************************************************
- DESTRUCT
- *****************************************************************************
- */
- destruct : function() {
- // set the model to null to get the bindings removed
- if (this.getModel() != null && !this.getModel().isDisposed()) {
- this.setModel(null);
- }
- }
- });