home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / AIMP2 / aimp_2.61.583.exe / $TEMP / YandexPackSetup.msi / fil992F0B355CFFC8433DA8134B0637E137 < prev    next >
Text File  |  2010-07-12  |  26KB  |  761 lines

  1. XB._calcNodes = {};
  2.  
  3. XB._calcNodes.NodeBase = Base.extend({
  4.     $name: "NodeBase",
  5.     
  6.     constructor: function NodeBase_constructor(baseUID) {
  7.         if (!baseUID)
  8.             throw new Error(XB._base.consts.ERR_UID_REQUIRED);
  9.         this._baseUID = baseUID;
  10.     },
  11.     
  12.     get baseID() {
  13.         return this._baseUID;
  14.     },
  15.     
  16.     set debugMode(value) {
  17.         return this._debugMode = !!value;
  18.     },
  19.     
  20.     _baseUID: undefined,
  21.     _storedValue: undefined,
  22.     _debugMode: false
  23. });
  24.  
  25. XB._calcNodes.ConstNodeProto = XB._calcNodes.NodeBase.extend({
  26.     $name: "ConstNodeProto",
  27.     
  28.     constructor: function ConstNodeProto_constructor(baseUID, initVal) {
  29.         this.base(baseUID);
  30.         this._storedValue = initVal;
  31.     },
  32.     
  33.     createInstance: function ConstNodeProto_createInstance(widgetInstance) {
  34.         var nodeInst = new XB._calcNodes.ConstNode(this._baseUID, widgetInstance, this._storedValue);
  35.         return nodeInst;
  36.     }
  37. });
  38.  
  39. XB._calcNodes.VarNodeProto = XB._calcNodes.ConstNodeProto.extend({
  40.     $name: "VarNodeProto",
  41.     
  42.     createInstance: function VarNodeProto_createInstance(widgetInstance) {
  43.         var nodeInst = new XB._calcNodes.VarNode(this._baseUID, widgetInstance, this._storedValue);
  44.         return nodeInst;
  45.     }
  46. });
  47.  
  48. XB._calcNodes.FuncNodeProto = XB._calcNodes.NodeBase.extend({
  49.     $name: "FuncNodeProto",
  50.     
  51.     constructor: function FuncNodeProto_constructor(baseUID, instanceClass) {
  52.         if ( !instanceClass.inherits(XB._calcNodes.FuncNode) && !instanceClass.inherits(XB._calcNodes.ProcNode) )
  53.             throw new TypeError(this._consts.ERR_NODE_CONSTRUCTOR_EXPECTED);
  54.         this.base(baseUID);
  55.         this._instanceClass = instanceClass;
  56.         this._argsMap = { __proto__: null };
  57.     },
  58.     
  59.     proposeArgName: function FuncNodeProto_proposeArgName() {
  60.         for each (let argName in this._instanceClass.prototype.expectedArgNames) {
  61.             if (!this.argumentAttached(argName))
  62.                 return argName;
  63.         }
  64.         return "param" + this._argsCount;
  65.     },
  66.     
  67.     attachArgument: function FuncNodeProto_attachArgument(argName, argProto) {
  68.         if ( !(argProto instanceof XB._calcNodes.NodeBase) || (typeof argProto.createInstance != "function") )
  69.             throw new TypeError(this._consts.ERR_FNODE_PROTO_EXPECTED);
  70.         this._argsMap[argName] = argProto;
  71.         this._argsCount++;
  72.     },
  73.     
  74.     argumentAttached: function FuncnodeProto_argumentAttached(argName) {
  75.         return !!this._argsMap[argName];
  76.     },
  77.     
  78.     createInstance: function FuncNodeProto_createInstance(widgetInstance) {
  79.         var nodeInst = new this._instanceClass(this._baseUID, widgetInstance, this._argsMap, this._debugMode);
  80.         return nodeInst;
  81.     },
  82.     
  83.     _consts: {
  84.         ERR_FNODE_PROTO_EXPECTED: "Function node prototype object expected",
  85.         ERR_NODE_CONSTRUCTOR_EXPECTED: "Widget node constructor expected"
  86.     },
  87.     _argsMap: null,
  88.     _argsCount: 0,
  89.     _instanceClass: null
  90. });
  91.  
  92. XB._calcNodes.BoundNode = XB._calcNodes.NodeBase.extend({
  93.     $name: "BoundNode",
  94.     
  95.     constructor: function BoundNode_constructor(baseUID, widget) {
  96.         if ( !(widget instanceof XB._Parser.Unit.WidgetPrototype ||
  97.                widget instanceof XB._Parser.Unit.WidgetInstance) )
  98.             throw new TypeError(XB._base.consts.ERR_WINST_REQUIRED);
  99.         this.base(baseUID);
  100.         this._parentWidget = widget;
  101.     },
  102.     
  103.     get effectiveID() {
  104.         var idParts = [this._parentWidget.id, this._baseUID];
  105.         if (this._parentWidget instanceof XB._Parser.Unit.WidgetInstance)
  106.             idParts.unshift(this._parentWidget.host.id);
  107.         return idParts.join("_");
  108.     },
  109.     
  110.     get parentWidget() {
  111.         return this._parentWidget;
  112.     },
  113.     
  114.     finalize: function BoundNode_finalize() {
  115.         
  116.     },
  117.     
  118.     _parentWidget: null,
  119.     
  120.     _formatRuntimeError: function BoundNode_formatRuntimeError(e) {
  121.         return XB._base.consts.ERR_RUNTIME_ERROR + " in node " + this._getHumanReadableID() + ". " + misc.formatError(e);
  122.     },
  123.     
  124.     _hasSubscribers: function BoundNode_hasSubscribers() {
  125.         return false;
  126.     },
  127.     
  128.     _getHumanReadableID: function FuncNode_getHumanReadableID() {
  129.         return this.$class.$name + "(" + this.effectiveID + ")";
  130.     }
  131. });
  132.  
  133. XB._calcNodes.ConstNode = XB._calcNodes.BoundNode.extend({
  134.     $name: "ConstNode",
  135.     
  136.     constructor: function ConstNode_constructor(baseUID, widget, initVal) {
  137.         this.base(baseUID, widget);
  138.         this._storedValue = initVal;
  139.         if (XB._base.runtime.isXML(initVal))
  140.             initVal.owner = this;
  141.     },
  142.     
  143.     getValue: function ConstNode_getValue() {
  144.         return this._storedValue;
  145.     },
  146.     
  147.     unsubscribe: function ConstNode_unsubscribe() {
  148.     },
  149.     
  150.     finalize: function ConstNode_finalize() {
  151.         if (XB._base.runtime.isXML(this._storedValue))
  152.             this._storedValue.dispose();
  153.         this._storedValue = undefined;
  154.     },
  155.  
  156.     freeze: function ConstNode_freeze() {
  157.         throw new Error(XB._calcNodes.ConstNode.ERR_UNSUPPORTED_ACTION);
  158.     },
  159.     
  160.     melt: function ConstNode_usedNodeChange() {
  161.         throw new Error(XB._calcNodes.ConstNode.ERR_UNSUPPORTED_ACTION);
  162.     }
  163. }, {
  164.     ERR_UNSUPPORTED_ACTION: "ConstNode does not support this method"
  165. });
  166.  
  167. XB._calcNodes.DynNode = XB._calcNodes.ConstNode.extend({
  168.     $name: "DynNode",
  169.     
  170.     constructor: function DynNode_constructor(baseUID, widget, initVal) {
  171.         this.base.apply(this, arguments);
  172.         this._dependants = {};
  173.     },
  174.     
  175.     getValue: function DynNode_getValue(subscriber) {
  176.         if (subscriber)
  177.             this._subscribe(subscriber);
  178.         return this.base();
  179.     },
  180.     
  181.     unsubscribe: function DynNode_unsubscribe(subscriber) {
  182.         var subscriberID = subscriber.effectiveID;
  183.         if ( !(subscriberID in this._dependants) ) return;
  184.         
  185.         delete this._dependants[subscriberID];
  186.         
  187.         if (!this._hasSubscribers()) {
  188.             if (this._debugMode)
  189.                 this._parentWidget.logger.debug("Node " + this._getHumanReadableID() +
  190.                                                 " lost all subscribers. Last one was " + subscriber._getHumanReadableID());
  191.             this._setNewVal(undefined);
  192.             try {
  193.                 this._notNeeded();
  194.             }
  195.             catch (e) {
  196.                 this._parentWidget.logger.error("Node " + this._getHumanReadableID() + " failed in _notNeeded. " +
  197.                                                 this._formatRuntimeError(e));
  198.                 this._parentWidget.logger.debug(e.stack);
  199.             }
  200.         }
  201.     },
  202.     
  203.     finalize: function DynNode_finalize() {
  204.         try {
  205.             this._dependants = {};
  206.             this._notNeeded();
  207.             this._setNewVal(XB.types.empty);
  208.         }
  209.         finally {
  210.             this.base();
  211.         }
  212.     },
  213.     
  214.     _setNewVal: function DynNode_setNewVal(newVal) {
  215.         if (newVal !== undefined && this._storedValue !== undefined) {
  216.             var valuesDiffer = (XB._base.runtime.compareValues(newVal, this._storedValue,
  217.                                                            XB._base.runtime.cmpModes.CMP_STRICT) != 0);
  218.         }
  219.         
  220.         if (this._debugMode && (this._parentWidget.logger.level <= XB._base.application.core.Log4Moz.Level.Debug)) {
  221.             this._parentWidget.logger.debug("Node " + this._getHumanReadableID() +
  222.                 " _setNewVal from " + (this._storedValue === undefined ?
  223.                     "undefined" : XB._base.runtime.describeValue(this._storedValue)) +
  224.                 " to " + (newVal === undefined ?
  225.                     "undefined" : XB._base.runtime.describeValue(newVal))  +
  226.                 ", differ: " + valuesDiffer);
  227.             if (XB._base.runtime.isXML(newVal))
  228.                 this._parentWidget.logger.debug("new value is:" + newVal.toString());
  229.         }
  230.         
  231.         if (valuesDiffer || newVal === undefined || this._storedValue === undefined) {
  232.             if (XB._base.runtime.isXML(newVal)) {
  233.                 if (newVal.disposed && this._debugMode)
  234.                     this._parentWidget.logger.warn(this._getHumanReadableID() + " got disposed XML");
  235.             }
  236.             if (XB._base.runtime.isXML(this._storedValue) && (this._storedValue.owner === this))
  237.                 this._storedValue.dispose();
  238.             this._storedValue = newVal;
  239.             if (XB._base.runtime.isXML(newVal) && !newVal.owner)
  240.                 newVal.owner = this;
  241.         }
  242.         else {
  243.             if ( XB._base.runtime.isXML(newVal) && (newVal !== this._storedValue) ) {
  244.                 newVal.dispose();
  245.             }
  246.         }
  247.         return valuesDiffer;
  248.     },
  249.     
  250.     _subscribe: function DynNode_subscribe(subscriber) {
  251.         this._dependants[subscriber.effectiveID] = subscriber;
  252.     },
  253.     
  254.     _notifyDeps: function DynNode_notifyDeps() {
  255.         if (this._debugMode)
  256.             this._parentWidget.logger.debug("FuncNode " + this._getHumanReadableID() + " notifies dependants");
  257.         try {
  258.             this._freezeDeps();
  259.         }
  260.         finally {
  261.             this._meltDeps(true);
  262.         }
  263.     },
  264.     
  265.     _freezeDeps: function DynNode_freezeDeps() {
  266.         for each (let dependant in this._dependants)
  267.             dependant.freeze();
  268.     },
  269.     
  270.     _meltDeps: function DynNode_meltDeps(iChanged) {
  271.         for each (let dependant in this._dependants) {
  272.             try {
  273.                 if (this._debugMode || dependant._debugMode)
  274.                     this._parentWidget.logger.debug(this._getHumanReadableID() + " ++ " + dependant._getHumanReadableID());
  275.                 dependant.melt(iChanged? this: null);
  276.             }
  277.             catch (e) {
  278.                 this._parentWidget.logger.error(this._getHumanReadableID() + " failed melting dependant node " + dependant._getHumanReadableID() +
  279.                                                 ". " + misc.formatError(e));
  280.                 this._parentWidget.logger.debug(e.stack);
  281.             }
  282.         }
  283.     },
  284.     
  285.     _hasSubscribers: function DynNode_hasSubscribers() {
  286.         return !sysutils.isEmptyObject(this._dependants);
  287.     },
  288.     
  289.     _notNeeded: function DynNode_notNeeded() {
  290.     },
  291.     
  292.     _dependants: null
  293. });
  294.  
  295. XB._calcNodes.IVariable = {
  296.     $name: "IVariable",
  297.     
  298.     setValue: function IVariable_setValue(newValue) {
  299.         if (this._setNewVal(newValue))
  300.             this._notifyDeps();
  301.     }
  302. };
  303.  
  304. XB._calcNodes.VarNode = XB._calcNodes.DynNode.extend(XB._calcNodes.IVariable);
  305.  
  306. XB._calcNodes.IHasArguments = {
  307.     constructor: function HasArgs_constructor(baseUID, widget, argsMap) {
  308.         this.base(baseUID, widget);
  309.         this._argManager = new XB._calcNodes.FuncNode.ArgManager(this);
  310.         
  311.         for (let argName in argsMap) {
  312.             var argProto = argsMap[argName];
  313.             this._argManager.attachArgument(argName, argProto.createInstance(widget));
  314.         }
  315.     },
  316.     
  317.     unsubscribe: function HasArgs_unsubscribe(subscriber) {
  318.         try {
  319.             this.base(subscriber);
  320.         }
  321.         finally {
  322.             if (!this._hasSubscribers())
  323.                 this._argManager.freeAll();
  324.         }
  325.     },
  326.     
  327.     finalize: function HasArgs_finalize() {
  328.         try {
  329.             this.base();
  330.         }
  331.         finally {
  332.             this._argManager.freeAll();
  333.         }
  334.     },
  335.     
  336.     _argManager: null
  337. };
  338.  
  339. XB._calcNodes.ProcNodeBase = XB._calcNodes.ConstNode.extend(XB._calcNodes.IHasArguments);
  340.  
  341. XB._calcNodes.ProcNode = XB._calcNodes.ProcNodeBase.extend({
  342.     $name: "ProcNode",
  343.     
  344.     perform: function ProcNode_perform(eventInfo) {
  345.         this._proc(eventInfo);
  346.     },
  347.     
  348.     getValue: function ProcNode_getValue() {
  349.         return this._proc();
  350.     }
  351. });
  352.  
  353. XB._calcNodes.FuncNodeBase = XB._calcNodes.DynNode.extend(XB._calcNodes.IHasArguments);
  354.  
  355. XB._calcNodes.FuncNode = XB._calcNodes.FuncNodeBase.extend({
  356.     $name: "FuncNode",
  357.     
  358.     constructor: function FuncNode_constructor(baseUID, widget, argsMap, debugMode) {
  359.         this.base(baseUID, widget, argsMap);
  360.         this._changedArgs = [];
  361.         this._debugMode = !!debugMode;
  362.     },
  363.     
  364.     freeze: function FuncNode_freeze() {
  365.         if (!this._hasSubscribers()) {
  366.             XB._base.logger.warn("Attempt to freeze " + this._getHumanReadableID() + ", which has no subscribers.");
  367.             return;
  368.         }
  369.         this._freezeLevel++;
  370.         if (this._debugMode)
  371.             this._parentWidget.logger.debug("Freezing node " + this._getHumanReadableID() + " " + this._freezeLevel);
  372.         this._freezeDeps();
  373.     },
  374.     
  375.     melt: function FuncNode_melt(changedArgNode) {
  376.         if (this._freezeLevel == 0) return;
  377.         this._freezeLevel = Math.max(0, this._freezeLevel - 1);
  378.         var hasSubscribers = this._hasSubscribers();
  379.         if (changedArgNode)
  380.             this._changedArgs.push(changedArgNode);
  381.         if (this._debugMode)
  382.             this._parentWidget.logger.debug("Melting node " + this._getHumanReadableID() + ". Freeze level: " + this._freezeLevel +
  383.                                             ", changed args: " + this._changedArgs.length + ", hasSubscribers: " + hasSubscribers);
  384.         var iChanged = false;
  385.         try {
  386.             if ((this._freezeLevel == 0) && (this._changedArgs.length > 0) && hasSubscribers) {
  387.                 var newVal = this._calculateSafely();
  388.                 if (this._debugMode)
  389.                     this._parentWidget.logger.debug("Node " + this._getHumanReadableID() + " recalculated to " +
  390.                                                     XB._base.runtime.describeValue(newVal));
  391.                 iChanged = this._setNewVal(newVal);
  392.             }
  393.         }
  394.         finally {
  395.             this._changedArgs = [];
  396.             this._meltDeps(iChanged);
  397.         }
  398.     },
  399.     
  400.     unsubscribe: function FuncNode_unsubscribe(subscriber) {
  401.         if ( !(subscriber.effectiveID in this._dependants) ) return;
  402.         try {
  403.             this.base(subscriber);
  404.             if (!this._hasSubscribers())
  405.                 this._freezeLevel = 0;
  406.         }
  407.         finally {
  408.             for (let i = this._freezeLevel; i > 0; i--)
  409.                 subscriber.melt(null);
  410.         }
  411.     },
  412.     
  413.     getValue: function FuncNode_getValue(subscriber) {
  414.         var prevValue = this.base(subscriber);
  415.         if (prevValue === undefined) {
  416.             var newVal = this._calculateSafely();
  417.             if (this._hasSubscribers())
  418.                 this._setNewVal(newVal);
  419.             return newVal;
  420.         }
  421.         return prevValue;
  422.     },
  423.     
  424.     _freezeLevel: 0,
  425.     _changedArgs: null,
  426.     _debugMode: false,
  427.     
  428.     _subscribe: function FuncNode_subscribe(subscriber) {
  429.         try {
  430.             this.base(subscriber);
  431.         }
  432.         finally {
  433.             for (let i = this._freezeLevel; i > 0; i--)
  434.                 subscriber.freeze();
  435.         }
  436.     },
  437.     
  438.     _calculateSafely: function FuncNode_calculateSafely() {
  439.         var val;
  440.         this._argManager.resetUseStat();
  441.         try {
  442.             val = this._calculate(this._changedArgs);
  443.         }
  444.         catch (e) {
  445.             if (e instanceof XB.types.Exception)
  446.                 val = e;
  447.             else {
  448.                 val = XB._base.runtime.createXBExceptionFromRTError(this.effectiveID, e);
  449.                 this._parentWidget.logger.error(this._formatRuntimeError(e));
  450.                 if (this._debugMode)
  451.                     this._parentWidget.logger.debug(e.stack);
  452.             }
  453.         }
  454.         finally {
  455.             this._argManager.freeUnused();
  456.         }
  457.         return val;
  458.     }
  459. });
  460.  
  461. XB._calcNodes.FuncNode.ArgManager = function FNArgManager_constructor(managedNode) {
  462.     if ( !(managedNode instanceof XB._calcNodes.FuncNode || managedNode instanceof XB._calcNodes.ProcNode) )
  463.         throw new TypeError(this._consts.ERR_FP_NODE_EXPECTED);
  464.     this._managedNode = managedNode;
  465.     this._namedArgs = {};
  466.     this._orderedArgs = [];
  467. };
  468.  
  469. XB._calcNodes.FuncNode.ArgManager.prototype = {
  470.     constructor: XB._calcNodes.FuncNode.ArgManager,
  471.     
  472.     attachArgument: function ArgMan_AttachArgument(argName, argNode) {
  473.         if (argName == "")
  474.             throw new Error(ERR_NAME_REQUIRED);
  475.         if ( !(argNode instanceof XB._calcNodes.BoundNode) )
  476.             throw new TypeError(XB._base.consts.ERR_FUNC_NODE_EXPECTED);
  477.         
  478.         var argInfo = {
  479.             node: argNode,
  480.             used: false
  481.         };
  482.         this._argsCount = this._orderedArgs.push(argInfo);
  483.         this._namedArgs[argName] = argInfo;
  484.     },
  485.     
  486.     detachArgument: function ArgMan_DetachArgument(argName) {
  487.         var argInfo = this._getArgInfoByName(argName);
  488.         argInfo.used = false;
  489.         argInfo.node.unsubscribe(this._managedNode);
  490.         delete this._namedArgs[argName];
  491.     },
  492.     
  493.     resetUseStat: function ArgMan_ResetUseStat() {
  494.         for each (let argInfo in this._namedArgs)
  495.             argInfo.used = false;
  496.     },
  497.     
  498.     freeUnused: function ArgMan_FreeUnused() {
  499.         for each (let argInfo in this._namedArgs) {
  500.             if (!argInfo.used)
  501.                 argInfo.node.unsubscribe(this._managedNode);
  502.         }
  503.     },
  504.     
  505.     freeAll: function ArgMan_FreeAll() {
  506.         for each (let argInfo in this._namedArgs) {
  507.             argInfo.used = false;
  508.             argInfo.node.unsubscribe(this._managedNode);
  509.         }
  510.     },
  511.     
  512.     argExists: function ArgMan_ArgExists(argName) {
  513.         return (argName in this._namedArgs) && (this._namedArgs[argName] instanceof Object);
  514.     },
  515.     
  516.     get argsNames() {
  517.         var names = [];
  518.         for (let name in this._namedArgs)
  519.             names.push(name);
  520.         return names;
  521.     },
  522.     
  523.     getValByName: function ArgMan_GetValByName(argName, preferedType) {
  524.         return this._processArgInfo(this._getArgInfoByName(argName), preferedType);
  525.     },
  526.     
  527.     getValByIndex: function ArgMan_GetValByIndex(argIndex, preferedType) {
  528.         return this._processArgInfo(this._getArgInfoByIndex(argIndex), preferedType);
  529.     },
  530.     
  531.     getValByNameDef: function ArgMan_GetValByNameDef(argName, preferedType, defaultValue) {
  532.         if ( !this.argExists(argName) )
  533.             return defaultValue;
  534.         return this._processArgInfo(this._getArgInfoByName(argName), preferedType, defaultValue);
  535.     },
  536.     
  537.     getValByIndexDef: function ArgMan_GetValByIndexDef(argIndex, preferedType, defaultValue) {
  538.         if ( !(argIndex in this._orderedArgs) )
  539.             return defaultValue;
  540.         return this._processArgInfo(this._getArgInfoByIndex(argIndex), preferedType, defaultValue);
  541.     },
  542.     
  543.     findNodeByName: function ArgMan_GetNodeByName(argName) {
  544.         var argInfo = this._namedArgs[argName];
  545.         if (argInfo) {
  546.             argInfo.used = true;
  547.             return argInfo.node;
  548.         }
  549.         return null;
  550.     },
  551.     
  552.     findNodeByIndex: function ArgMan_GetNodeByIndex(argIndex) {
  553.         var argInfo = this._orderedArgs[argIndex];
  554.         if (argInfo) {
  555.             argInfo.used = true;
  556.             return argInfo.node;
  557.         }
  558.         return null;
  559.     },
  560.     
  561.     get argsCount() {
  562.         return this._argsCount;
  563.     },
  564.     
  565.     argInArray: function (argName, array) {
  566.         if (!(array instanceof Array))
  567.             throw new TypeError("Array expected");
  568.         
  569.         var argNode = this.findNodeByName(argName);
  570.         if (!argNode)
  571.             return false;
  572.         
  573.         for each (let item in array) {
  574.             if (item === argNode)
  575.                 return true;
  576.         }
  577.         
  578.         return false;
  579.     },
  580.     
  581.     _consts: {
  582.         ERR_FP_NODE_EXPECTED: "FuncNode or ProcNode instance expected",
  583.         ERR_NO_ARG: "No such argument"
  584.     },
  585.     _managedNode: null,
  586.     _namedArgs: null,
  587.     _orderedArgs: null,
  588.     _argsCount: 0,
  589.     
  590.     _getArgInfoByName: function ArgMan_getArgInfoByName(argName) {
  591.         if ( !(argName in this._namedArgs) )
  592.             throw new Error(this._consts.ERR_NO_ARG + ": \"" + argName + "\"");
  593.         return this._namedArgs[argName];
  594.     },
  595.     
  596.     _getArgInfoByIndex: function ArgMan_getArgInfoByName(argIndex) {
  597.         if ( !(argIndex in this._orderedArgs) )
  598.             throw new Error(this._consts.ERR_NO_ARG + ": " + argIndex);
  599.         return this._orderedArgs[argIndex];
  600.     },
  601.     
  602.     _processArgInfo: function ArgMan_processArgInfo(argInfo, preferedType, defaultValue) {
  603.         if (argInfo == undefined)
  604.             throw new Error(this._consts.ERR_NO_ARG);
  605.         argInfo.used = true;
  606.         var argVal = argInfo.node.getValue(this._managedNode._hasSubscribers()? this._managedNode: null);
  607.         if (argVal instanceof XB.types.Exception)
  608.             throw argVal;
  609.         
  610.         try {
  611.             switch(preferedType) {
  612.                 case "Number":
  613.                     return XB._base.runtime.xToNumber(argVal);
  614.                 case "String":
  615.                     return XB._base.runtime.xToString(argVal);
  616.                 case "Bool":
  617.                     return XB._base.runtime.xToBool(argVal);
  618.                 case "XML":
  619.                     return XB._base.runtime.xToXML(argVal);
  620.                 case "RequestData":
  621.                     return XB._base.runtime.xToRequestData(argVal);
  622.                 default:
  623.                     return argVal;
  624.             }
  625.         }
  626.         catch (e) {
  627.             if ((e instanceof XB.types.Exception) || (defaultValue == undefined))
  628.                 throw e;
  629.             return defaultValue;
  630.         }
  631.     }
  632. };
  633.  
  634. XB._calcNodes.Persistent = XB._calcNodes.DynNode.extend({
  635.     $name: "Persistent",
  636.     
  637.     constructor: function FPersistentNode_constructor(baseUID, widgetInstance, persistCategory, persistKey, defaultValue) {
  638.         this._defaultValue = defaultValue || XB.types.empty;
  639.         this.base(baseUID, widgetInstance, this._defaultValue);
  640.         
  641.         if (!persistCategory)
  642.             throw new Error(this._consts.ERR_PCATEGORY_EXPECTED);
  643.         this._persistCategory = persistCategory;
  644.         if (!persistKey)
  645.             throw new Error(this._consts.ERR_PKEY_EXPECTED);
  646.         this._persistKey = persistKey;
  647.         
  648.         this._widgetProtoID = (widgetInstance instanceof XB._Parser.Unit.WidgetInstance)?
  649.             widgetInstance.prototype.id:
  650.             widgetInstance.id;
  651.         
  652.         this._prefsModule = XB._base.application.core.Preferences;
  653.         let storedPref = this._prefsModule.get(this._prefFullPath);
  654.         if (storedPref !== undefined) {
  655.             this._dontWrite = true;
  656.             try {
  657.                 this._setNewVal(storedPref);
  658.             }
  659.             finally {
  660.                 this._dontWrite = false;
  661.             }
  662.         }
  663.         this._prefsModule.observe(this._prefFullPath, this);
  664.     },
  665.     
  666.     finalize: function FPersistentNode_finalize() {
  667.         this._prefsModule.ignore(this._prefFullPath, this);
  668.         this._dontWrite = true;
  669.         this.base();
  670.     },
  671.     
  672.     get defaultValue() {
  673.         return this._defaultValue;
  674.     },
  675.     
  676.     erase: function FPersistentNode_erase() {
  677.         this._erasing = true;
  678.         try {
  679.             this._prefsModule.reset(this._prefFullPath);
  680.         }
  681.         finally {
  682.             this._erasing = false;
  683.         }
  684.     },
  685.     
  686.     observe: function FPersistentNode_observe(subject, topic, data) {
  687.         if (this._erasing) return;
  688.         var prefPath = data;
  689.         this._parentWidget.logger.debug("Persistent node " + prefPath + " observes " + topic);
  690.         var value = this._prefsModule.get(prefPath, this._defaultValue);
  691.         this._dontWrite = true;
  692.         try {
  693.             if (this._setNewVal(value))
  694.                 this._notifyDeps();
  695.         }
  696.         finally {
  697.             this._dontWrite = false;
  698.         }
  699.     },
  700.     
  701.     _consts: {
  702.         ERR_PCATEGORY_EXPECTED: "Persist category expected",
  703.         ERR_PKEY_EXPECTED: "Persist key expected"
  704.     },
  705.     _prefsModule: null,
  706.     _persistCategory: undefined,
  707.     _persistKey: undefined,
  708.     _dontWrite: false,
  709.     _erasing: false,
  710.     
  711.     _setNewVal: function FPersistentNode_set(value) {
  712.         if (value === undefined)
  713.             return undefined;
  714.         var reset = (typeof this._storedValue) !== (typeof value);
  715.         var changed = this.base(value);
  716.         if (changed && !this._dontWrite) {
  717.             this._parentWidget.logger.debug("Persistent node " + this._prefFullPath + " writes new value " + value);
  718.             this._prefsModule.ignore(this._prefFullPath, this);
  719.             try {
  720.                 if (reset)
  721.                     this._prefsModule.reset(this._prefFullPath);
  722.                 if (!XB._base.runtime.isXML(value))
  723.                     this._prefsModule.set(this._prefFullPath, value);
  724.             }
  725.             finally {
  726.                 this._prefsModule.observe(this._prefFullPath, this);
  727.             }
  728.         }
  729.         return changed;
  730.     },
  731.     
  732.     get _prefFullPath() {
  733.         let prefPath = XB._base.application.name + ".xbwidgets." + this._widgetProtoID + ".";
  734.         if (this._parentWidget instanceof XB._Parser.Unit.WidgetInstance) {
  735.             prefPath += (this._parentWidget.id + ".");
  736.         }
  737.         else
  738.             prefPath += "all.";
  739.         prefPath += (this._persistCategory + "." + this._persistKey);
  740.         
  741.         delete this._fullPrefPath;
  742.         this._fullPrefPath = prefPath;
  743.         
  744.         return prefPath;
  745.     }
  746. });
  747.  
  748. XB._calcNodes.Persistent.implement(XB._calcNodes.IVariable);
  749.  
  750. XB._calcNodes.SettingNode = XB._calcNodes.Persistent.extend({
  751.     constructor: function FSettingNode_constructor(baseUID, widgetInstance, prefName, defaultValue) {
  752.         this.base(baseUID, widgetInstance, "settings", prefName, defaultValue);
  753.     }
  754. });
  755.  
  756. XB._calcNodes.PersistentVarNode = XB._calcNodes.Persistent.extend({
  757.     constructor: function FPersistentVarNode_constructor(baseUID, widgetInstance, varName, defaultValue) {
  758.         this.base(baseUID, widgetInstance, "variables", varName, defaultValue);
  759.     }
  760. });
  761.