r25048: From the archives (patch found in one of my old working trees):
[jelmer/samba4-debian.git] / webapps / qooxdoo-0.6.5-sdk / frontend / framework / source / class / qx / core / Object.js
1 /* ************************************************************************
2
3    qooxdoo - the new era of web development
4
5    http://qooxdoo.org
6
7    Copyright:
8      2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
9
10    License:
11      LGPL: http://www.gnu.org/licenses/lgpl.html
12      EPL: http://www.eclipse.org/org/documents/epl-v10.php
13      See the LICENSE file in the project's top-level directory for details.
14
15    Authors:
16      * Sebastian Werner (wpbasti)
17      * Andreas Ecker (ecker)
18
19 ************************************************************************ */
20
21 /* ************************************************************************
22
23 #module(core)
24 #load(qx.core.Init)
25 #resource(static:static)
26
27 ************************************************************************ */
28
29 /**
30  * The qooxdoo root class. All other classes are direct or indirect subclasses of this one.
31  *
32  * This class contains methods for:
33  * <ul>
34  *   <li> object management (creation and destruction) </li>
35  *   <li> logging & debugging </li>
36  *   <li> generic getter/setter </li>
37  *   <li> user data </li>
38  *   <li> settings </li>
39  *   <li> internationalization </li>
40  * </ul>
41  *
42  * @param vAutoDispose {Boolean ? true} whether the object should be automatically disposed
43  */
44 qx.OO.defineClass("qx.core.Object", Object,
45 function(vAutoDispose)
46 {
47   this._hashCode = qx.core.Object._availableHashCode++;
48
49   if (vAutoDispose !== false)
50   {
51     this._dbKey = qx.core.Object._db.length;
52     qx.core.Object._db.push(this);
53   }
54 });
55
56
57 /*
58 ---------------------------------------------------------------------------
59   DEFAULT SETTINGS
60 ---------------------------------------------------------------------------
61 */
62
63 qx.Settings.setDefault("enableDisposerDebug", false);
64
65
66
67
68
69 /* ************************************************************************
70    Class data, properties and methods
71 ************************************************************************ */
72
73 qx.Class._availableHashCode = 0;
74 qx.Class._db = [];
75 qx.Class._disposeAll = false;
76
77
78 /**
79  * Returns an unique identifier for the given object. If such an identifier
80  * does not yet exist, create it.
81  *
82  * @param o {Object} the Object to get the hashcode for
83  * @return {Integer} unique identifier for the given object
84  */
85 qx.Class.toHashCode = function(o)
86 {
87   if(o._hashCode != null) {
88     return o._hashCode;
89   }
90
91   return o._hashCode = qx.core.Object._availableHashCode++;
92 }
93
94
95 /**
96  * Destructor. This method is called by qooxdoo on object destruction.
97  *
98  * Any class that holds resources like links to DOM nodes must overwrite
99  * this method and free these resources.
100  */
101 qx.Class.dispose = function()
102 {
103   // var logger = qx.log.Logger.getClassLogger(qx.core.Object);
104   // logger.debug("Disposing Application");
105
106   // var vStart = (new Date).valueOf();
107   qx.core.Object._disposeAll = true;
108   var vObject;
109
110   for (var i=qx.core.Object._db.length-1; i>=0; i--)
111   {
112     vObject = qx.core.Object._db[i];
113
114     if (vObject && vObject._disposed === false)
115     {
116       // logger.debug("Disposing: " + vObject);
117       vObject.dispose();
118     }
119   }
120
121   // logger.debug("Done in: " + ((new Date).valueOf() - vStart) + "ms");
122 }
123
124
125 /**
126  * Summary of allocated objects
127  *
128  * @return {String} summary of allocated objects.
129  */
130 qx.Class.summary = function()
131 {
132   var vData = {};
133   var vCounter = 0;
134   var vObject;
135
136   for (var i=qx.core.Object._db.length-1; i>=0; i--)
137   {
138     vObject = qx.core.Object._db[i];
139
140     if (vObject && vObject._disposed === false)
141     {
142       if (vData[vObject.classname] == null)
143       {
144         vData[vObject.classname] = 1;
145       }
146       else
147       {
148         vData[vObject.classname]++;
149       }
150
151       vCounter++;
152     }
153   }
154
155   var vArrData = [];
156
157   for (var vClassName in vData) {
158     vArrData.push({ classname : vClassName, number : vData[vClassName] });
159   }
160
161   vArrData.sort(function(a, b) {
162     return b.number - a.number;
163   });
164
165   var vMsg = "Summary: (" + vCounter + " Objects)\n\n";
166
167   for (var i=0; i<vArrData.length; i++) {
168     vMsg += vArrData[i].number + ": " + vArrData[i].classname + "\n";
169   }
170
171   alert(vMsg);
172 };
173
174 /**
175  * Enable or disable the Object.
176  *
177  * The actual semantic of this property depends on concrete subclass of qx.core.Object.
178  */
179 qx.OO.addProperty({ name : "enabled", type : "boolean", defaultValue : true, getAlias : "isEnabled" });
180
181
182
183
184
185
186 /* ************************************************************************
187    Instance data, properties and methods
188 ************************************************************************ */
189
190 /*
191 ---------------------------------------------------------------------------
192   UTILITIES
193 ---------------------------------------------------------------------------
194 */
195
196 /**
197  * Returns a string represantation of the qooxdoo object.
198  *
199  * @return {String} string representation of the object
200  */
201 qx.Proto.toString = function()
202 {
203   if(this.classname) {
204     return "[object " + this.classname + "]";
205   }
206
207   return "[object Object]";
208 }
209
210
211 /**
212  * Return unique hash code of object
213  *
214  * @return {Integer} unique hash code of the object
215  */
216 qx.Proto.toHashCode = function() {
217   return this._hashCode;
218 }
219
220
221 /**
222  * Returns true if the object is disposed.
223  *
224  * @return {Boolean} wether the object has been disposed
225  */
226 qx.Proto.getDisposed = function() {
227   return this._disposed;
228 }
229
230
231 /**
232  * Returns true if the object is disposed.
233  *
234  * @return {Boolean} wether the object has been disposed
235  */
236 qx.Proto.isDisposed = function() {
237   return this._disposed;
238 }
239
240
241 /**
242  * Returns a settings from global setting definition
243  *
244  * @param vKey {String} the key
245  * @return {Object} value of the global setting
246  */
247 qx.Proto.getSetting = function(vKey) {
248   return qx.Settings.getValueOfClass(this.classname, vKey);
249 }
250
251
252 /*
253 ---------------------------------------------------------------------------
254   I18N INTERFACE
255 ---------------------------------------------------------------------------
256 */
257
258 /**
259  * Translate a message
260  * Mark the message for translation.
261  * @see qx.lang.String.format
262  *
263  * @param messageId {String} message id (may contain format strings)
264  * @param varargs {Object} variable number of argumes applied to the format string
265  * @return {qx.locale.LocalizedString}
266  */
267 qx.Proto.tr = function(messageId, varargs) {
268   var nlsManager = qx.locale.Manager;
269   return nlsManager.tr.apply(nlsManager, arguments);
270 };
271
272
273 /**
274  * Translate a plural message
275  * Mark the messages for translation.
276  *
277  * Depending on the third argument the plursl or the singular form is chosen.
278  *
279  * @see qx.lang.String.format
280  *
281  * @param singularMessageId {String} message id of the singular form (may contain format strings)
282  * @param pluralMessageId {String} message id of the plural form (may contain format strings)
283  * @param count {Integer} if greater than 1 the plural form otherwhise the singular form is returned.
284  * @param varargs {Object} variable number of argumes applied to the format string
285  * @return {qx.locale.LocalizedString)
286  */
287 qx.Proto.trn = function(singularMessageId, pluralMessageId, count, varargs) {
288   var nlsManager = qx.locale.Manager;
289   return nlsManager.trn.apply(nlsManager, arguments);
290 };
291
292
293 /**
294  * Mark the message for translation but return the original message.
295  *
296  * @param messageId {String} the message ID
297  * @return {String} messageId
298  */
299 qx.Proto.marktr = function(messageId) {
300   var nlsManager = qx.locale.Manager;
301   return nlsManager.marktr.apply(nlsManager, arguments);
302 };
303
304 /*
305 ---------------------------------------------------------------------------
306   LOGGING INTERFACE
307 ---------------------------------------------------------------------------
308 */
309
310 /**
311  * Returns the logger of this class.
312  *
313  * @return {qx.log.Logger} the logger of this class.
314  */
315 qx.Proto.getLogger = function() {
316   return qx.log.Logger.getClassLogger(this.constructor);
317 }
318
319
320 /**
321  * Logs a debug message.
322  *
323  * @param msg {var} the message to log. If this is not a string, the
324  *        object dump will be logged.
325  * @param exc {var ? null} the exception to log.
326  */
327 qx.Proto.debug = function(msg, exc) {
328   this.getLogger().debug(msg, this._hashCode, exc);
329 }
330
331
332 /**
333  * Logs an info message.
334  *
335  * @param msg {var} the message to log. If this is not a string, the
336  *    object dump will be logged.
337  * @param exc {var ? null} the exception to log.
338  */
339 qx.Proto.info = function(msg, exc) {
340   this.getLogger().info(msg, this._hashCode, exc);
341 }
342
343
344 /**
345  * Logs a warning message.
346  *
347  * @param msg {var} the message to log. If this is not a string, the
348  *    object dump will be logged.
349  * @param exc {var ? null} the exception to log.
350  */
351 qx.Proto.warn = function(msg, exc) {
352   this.getLogger().warn(msg, this._hashCode, exc);
353 }
354
355
356 /**
357  * Logs an error message.
358  *
359  * @param msg {var} the message to log. If this is not a string, the
360  *    object dump will be logged.
361  * @param exc {var ? null} the exception to log.
362  */
363 qx.Proto.error = function(msg, exc) {
364   this.getLogger().error(msg, this._hashCode, exc);
365 }
366
367
368
369
370 /*
371 ---------------------------------------------------------------------------
372   COMMON SETTER/GETTER SUPPORT
373 ---------------------------------------------------------------------------
374 */
375
376 /**
377  * Sets multiple properties at once by using a property list
378  *
379  * @param propertyValues {Object} A hash of key-value pairs.
380  */
381 qx.Proto.set = function(propertyValues)
382 {
383   if (typeof propertyValues !== "object") {
384     throw new Error("Please use a valid hash of property key-values pairs.");
385   }
386
387   for (var prop in propertyValues)
388   {
389     try
390     {
391       this[qx.OO.setter[prop]](propertyValues[prop]);
392     }
393     catch(ex)
394     {
395       this.error("Setter of property '" + prop + "' returned with an error", ex);
396     }
397   }
398
399   return this;
400 }
401
402 /**
403  * Gets multiple properties at once by using a property list
404  *
405  * @param propertyNames {String | Array | Map} list of the properties to get
406  * @param outputHint {String ? "array"} how should the values be returned. Possible values are "hash" and "array".
407 */
408 qx.Proto.get = function(propertyNames, outputHint)
409 {
410   switch(typeof propertyNames)
411   {
412     case "string":
413       return this["get" + qx.lang.String.toFirstUp(propertyNames)]();
414
415     case "object":
416       if (typeof propertyNames.length === "number")
417       {
418         if (outputHint == "hash")
419         {
420           var h = {};
421
422           propertyLength = propertyNames.length;
423           for (var i=0; i<propertyLength; i++)
424           {
425             try{
426               h[propertyNames[i]] = this["get" + qx.lang.String.toFirstUp(propertyNames[i])]();
427             }
428             catch(ex)
429             {
430               throw new Error("Could not get a valid value from property: " + propertyNames[i] + "! Is the property existing? (" + ex + ")");
431             }
432           }
433
434           return h;
435         }
436         else
437         {
438           propertyLength = propertyNames.length;
439           for (var i=0; i<propertyLength; i++)
440           {
441             try{
442               propertyNames[i] = this["get" + qx.lang.String.toFirstUp(propertyNames[i])]();
443             }
444             catch(ex)
445             {
446               throw new Error("Could not get a valid value from property: " + propertyNames[i] + "! Is the property existing? (" + ex + ")");
447             }
448           }
449
450           return propertyNames;
451         }
452       }
453       else
454       {
455         for (var i in propertyNames) {
456           propertyNames[i] = this["get" + qx.lang.String.toFirstUp(i)]();
457         }
458
459         return propertyNames;
460       }
461
462     default:
463       throw new Error("Please use a valid array, hash or string as parameter!");
464   }
465 }
466
467
468
469
470
471 /*
472 ---------------------------------------------------------------------------
473   USER DATA
474 ---------------------------------------------------------------------------
475 */
476
477 /**
478  * Store user defined data inside the object.
479  *
480  * @param vKey {String} the key
481  * @param vValue {Object} the value of the user data
482  */
483 qx.Proto.setUserData = function(vKey, vValue)
484 {
485   if (!this._userData) {
486     this._userData = {};
487   }
488
489   this._userData[vKey] = vValue;
490 }
491
492
493 /**
494  * Load user defined data from the object
495  *
496  * @param vKey {String} the key
497  * @return {Object} the user data
498  */
499 qx.Proto.getUserData = function(vKey)
500 {
501   if (!this._userData) {
502     return null;
503   }
504
505   return this._userData[vKey];
506 }
507
508
509
510
511
512
513 /*
514 ---------------------------------------------------------------------------
515   DISPOSER
516 ---------------------------------------------------------------------------
517 */
518
519 qx.Proto._disposed = false;
520
521 /**
522  * Dispose this object
523  */
524 qx.Proto.dispose = function()
525 {
526   if (this.getDisposed()) {
527     return;
528   }
529
530   // Dispose user data
531   if (this._userData)
532   {
533     for(var vKey in this._userData) {
534       this._userData[vKey] = null;
535     }
536
537     this._userData = null;
538   }
539
540   // Finally cleanup properties
541   if (this._objectproperties)
542   {
543     var a = this._objectproperties.split(",");
544     var d = qx.OO.values;
545
546     for (var i=0, l=a.length; i<l; i++) {
547       this[d[a[i]]] = null;
548     }
549
550     this._objectproperties = null;
551   }
552
553   if (this.getSetting("enableDisposerDebug"))
554   {
555     for (var vKey in this)
556     {
557       if (this[vKey] !== null && typeof this[vKey] === "object")
558       {
559         this.debug("Missing class implementation to dispose: " + vKey);
560         delete this[vKey];
561       }
562     }
563   }
564
565   /*
566   if (typeof CollectGarbage === "function") {
567     CollectGarbage();
568   }
569   */
570
571   /*
572   // see bug #258.
573   if(this._dbKey != this._hashCode) {
574     console.log("Disposing wrong entry: " + this._dbKey + " vs. " + this._hashCode);
575   }
576   */
577
578   // Delete Entry from Object DB
579   if (this._dbKey != null)
580   {
581     if (qx.core.Object._disposeAll)
582     {
583       qx.core.Object._db[this._dbKey] = null;
584       this._hashCode = null;
585       this._dbKey = null;
586     }
587     else
588     {
589       delete qx.core.Object._db[this._dbKey];
590       delete this._hashCode;
591       delete this._dbKey;
592     }
593   }
594
595   // Mark as disposed
596   this._disposed = true;
597 }