<@doc alias="index"> An object that can be used for organizing the model units into a navigable hierarchy.

The ModelOrganizer class implements the TreeProvider interface (see @lib:TreeView). Therefore, it can be used to create TreeView controls for displaying and navigating the model's organizational hierarchy.

Instances of this class are created automatically by the system, and should not be created directly. To access the ModelOrganizer object of the currently open model use the Environment's @env:Environment!organizer property.

(c) SAP AG 2003-2006. All rights reserved. #ALIAS[g=core.svg:GmlDrawing] #INCLUDE[defs.inc] Class ModelOrganizer inherit Object; <@doc scope="private"> Creates a new ModelOrganizer object The model that is organized by this object constructor (model) this.model = model; this.index = {}; this.root = this.model.root; this.setupCompatibleOrganizer(); end method finalize() var C = this.index; for( var id in C){ var childs= C[id].children; for ( var n in childs){ delete childs[n]; } delete C[id].children; delete C[id]; } delete this.model; delete this.index; delete this.root; delete this.compatibleOrganizer; end /////////////////////////////////////////////////////////////////////// // PROPERTIES <@doc>Gets the model organized by this object readonly property model = ^gml:Model; <@doc>Gets the root Unit of the Organizer readonly property root = ^Unit; <@doc scope="private">Gets the internal index maintained by this object readonly property index = null; /////////////////////////////////////////////////////////////////////// // MODEL ORGANIZATION METHODS override method getIndex() return this.index; end <@doc scope="private"> Adds a new and empty node to the model index. The node sructure is : id: unit ID, name: the unit name parent: unit parent, children: all the units children of the given unit, usages: all the usages of the unit, unused: indicates if the unit has been deleted. method addIndexNode(id,name,type,parentId) var msg = "#TEXT[XMSG_INSERT_NON_UNIT]"; #DEVTIME[ var cls = CLASS(type); if (cls && !cls.isa('core.gml:Unit')) { throw new Error(-1, msg ); } ] if (!(id in this.index)) { this.index[id] = {id:id, name:name, type:type, parent:null, children:{}, usages:{}, unused:false}; } var node = this.index[id]; var pnode = parentId && this.index[parentId] || null; if (pnode) { node.parent = pnode; pnode.children[node.id] = node; } return node; end <@doc> Tests whether the unit is a reusable unit Return ~true iff the usage is a reusable usage. method isReusable(unitId) var node = this.index[unitId]; // The unit has not been loaded yet then check which of the usages are contained // in the reusables Module if (!node){ var usages = this.model.reusables.getCollection('#NS[Usage]'); for(var id in usages){ if (usages[id].target == unitId) return true; } return false; } // node exist in the index collection if (!node.parent) return false; if (node.parent.id == this.model.reusables.id) return true; return false; end <@doc> Gets the collection of sub-units of a given unit. The given unit The requested sub-units collection method getSubUnits(unit) return unit.getChildUnits(#[NOT_REUSABLE]); end <@doc> Provides a quick method for checking whether a given unit has any sub-units The given unit The test result method hasSubUnits(unit) return unit.hasChildUnits(#[NOT_REUSABLE]); end <@doc scope="private"> Makes the source unit to be reusable. The given unit returns ~true iff this action succeeded method makeUnitReusable(unit) if (!unit) return false; if (unit.isReusable())return false; try { var df=false, x0=0, y0=0; BEGIN('make unit reusable'); var C = this.getPrimaryUsages(unit); var copyList = this.model.cloneElements(C,#[FORCE_FLAT|FORCE_CLONE]); if(copyList) { for( var id in copyList){ var copy=copyList[id], copyId=copy.id; if (!copy || copy.state || !this.model.reusables.insertElement(copy, 'elements')) return false; this.addUsage(copy,this.model.reusables); } } var usage = null; for(var id in C) { usage = C[id]; break; } if (usage) $ENV.fireModelOrganize(usage.unit,null,null,usage); COMMIT(); return true; } catch(e) { ROLLBACK(); return false; } end <@doc scope="protected"> paste a usage as link method pasteAsLink(src, trgParent) try{ BEGIN('make unit reusable'); var mt = src.Class.metadata ; var psrcId = src.getParent().id; var newElem = null; if(src.isReusable()){ newElem = trgParent.createElement(mt.usageElement,'elements',{target:src.id}); }else{ var srcParent = src.getParent(); var psrcId = src.getParent().id; // make the source unit reusable. this.makeUnitReusable(src); // create the new usage newElem = trgParent.createElement(mt.usageElement,'elements',{target:src.id}); } COMMIT(); return newElem ; } catch(e) { ROLLBACK(); return null; } end <@doc scope="protected"> paste a usage as link method pasteAsLinkToBoard(src, trgParent,point,targetGroup) try{ BEGIN('make unit reusable'); var mt = src.Class.metadata ; var psrcId = src.getParent().id; var newElem = null; if(src.isReusable()){ newElem = SIGNAL('BOARD->createShape', mt.usageElement, {target:src.id}, point, targetGroup); }else{ var srcParent = src.getParent(); var psrcId = src.getParent().id; // make the source unit reusable. this.makeUnitReusable(src); // create the new usage newElem =SIGNAL('BOARD->createShape', mt.usageElement, {target:src.id}, point, targetGroup); } COMMIT(); return newElem ; } catch(e) { ROLLBACK(); return null; } end <@doc> Gets the ancestors chain of a given unit The given unit The list of the unit's ancestors, in nesting order method getAncestors(unit) var list = []; list.push(unit); var parent = unit ; while (parent = parent.getParent() ) { list.push(parent); } return list.reverse(); end <@doc> Gets the parent unit of a given unit The given unit The parent unit method getParent(unit) var dnode = this.index[unit.id]; var pnode = dnode && dnode.parent || null; return pnode && this.model.getUnit(pnode.id) || null; end <@doc> Provides a quick method for checking whether a given unit has a parent unit The given unit The test result method hasParent(unit) return (this.getParent(unit) != null) ; end /////////////////////////////////////////////////////////////////////// // USAGES MAINTENANCE METHODS <@doc scope="private"> Adds a new usage to the index method addUsage(usage,ctnUnit) try{ if (!usage || !ctnUnit) return; var usageId = ctnUnit.id+'.'+usage.id; var trgunit = usage.getTarget(); var trgUnitNode = this.index[trgunit.id]; if (!trgUnitNode) trgUnitNode = this.addIndexNode(trgunit.id,trgunit.name,trgunit.Class.fullname); trgUnitNode.usages[usageId] = (trgUnitNode.usagesFlag ? usage : usageId); if (!trgunit.isReusable() || ctnUnit.id == this.model.reusables.id){ var ctnUnitNode = this.getIndex()[ctnUnit.id]; if(!ctnUnitNode) ctnUnitNode = this.addIndexNode(ctnUnit.id,ctnUnit.name,ctnUnit.Class.fullname); if(ctnUnitNode){ trgUnitNode.parent = ctnUnitNode; ctnUnitNode.children[trgUnitNode.id] = trgUnitNode; } } //$ENV.fireModelOrganize(trgunit,ctnUnit,null,usage); $ENV.fireModelOrganize(null,ctnUnit,null,usage); }catch(e){ var msg='#TEXT[XMSG_FAILED_ADD_USAGE]'; #LOG[4,msg + ' ' + e.description] throw e; } end <@doc scope="private"> Deletes a usage from the index method delUsage(usage,ctnUnit) try{ if (!usage || !ctnUnit) return; var usageId = ctnUnit.id+'.'+usage.id; var trgunit = usage.getTarget(); var trgUnitNode = this.index[trgunit.id]; if (!trgUnitNode) trgUnitNode = this.addIndexNode(trgunit.id,trgunit.name,trgunit.Class.name); delete trgUnitNode.usages[usageId]; if (!trgunit.isReusable()){ var ctnUnitNode = this.getIndex()[ctnUnit.id]; if(!ctnUnitNode) ctnUnitNode = this.addIndexNode(ctnUnit.id,ctnUnit.name,ctnUnit.Class.fullname); if(ctnUnitNode){ delete ctnUnitNode.children[trgUnitNode.id] ; } // if the deleted usage is in the reusables module then assign the parent unit // to be one of the containing units. }else if(ctnUnit.id == this.model.reusables.id){ var usages = trgUnitNode.usages ; var obj = null; for (var id in usages){ obj= usages[id]; break; } if(obj){ trgUnitNode.parent = this.getIndex()[obj.unit.id]; //$ENV.fireModelOrganize(obj.unit, null, obj.unit, obj); $ENV.fireModelOrganize(null, null,obj.unit, obj); } } $ENV.fireModelOrganize(null,null , ctnUnit, usage); //this.updateIndex(); }catch(e){ var msg='#TEXT[XMSG_FAILED_DELETE_USAGE]'; #LOG[4,msg + ' ' + e.description] throw e; } end <@doc scope="private"> Add anelement to the index method addElement(elm,unit) if(!elm) return; $ENV.fireModelOrganize(null,unit,null , elm); end <@doc scope="private"> Deletes an element from the index method delElement(elm,unit) if(!elm) return; $ENV.fireModelOrganize(null,null,unit, elm); end <@doc scope="private"> Tests whether a given usage is a primary usage, means, Is the usage is defined in the parent of its unit. method isPrimaryUsage(usage) var node = this.index[usage.target]; return node && node.parent && usage.unit && node.parent.id == usage.unit.id|| false; end <@doc scope="private"> Gets the primary usages of a given unit, means, The usages that are defined in the parent of the unit. method getPrimaryUsages(unit) var usages = this.getUsages(unit); var parent = this.getParent(unit); var primary = {}; for (var k in usages) { if (usages[k].unit == parent) primary[k] = usages[k]; } return primary; end <@doc scope="private"> Removes the primary usages of a given unit (thus in effect removing the unit from the model organizational hierarchy) method removeAllUsages(unit) var primary=this.getUsages(unit); if (ISEMPTY(primary)) return false; try { BEGIN('remove unit'); for (var k in primary) { var u=primary[k], d=u.unit; if (d && !d.removeElement(u, 'elements')) throw -1; } COMMIT(); return true; } catch(e) { ROLLBACK(); return false; } end <@doc scope="private"> Gets all usages of a given unit method getUsages(unit) var unitId = typeof unit == 'string' ? unit : unit.id var node = this.index[unitId]; if (!node) node = this.addIndexNode(unitId,unit.name,unit.Class.fullname); if (!node.usagesFlag) { for (var k in node.usages) { var usage = this.model.getElement(k); if (!usage || !(typeof usage == 'object')){ #TRACE[4, "getUsages Method:Usage not an object, should check why this is happening. UsageId:" + k ]; delete node.usages[k]; }else{ node.usages[k] = usage; } } node.usagesFlag = true; } return node.usages; end method canRemoveUnit(unit){ if( !unit || !unit.isEnabled()) return false; // Do not allow removal of model.root or model.reusables if(unit == this.model.root || unit == this.model.reusables ) return false; var usages = this.getReusableUsages(unit); if (usages.length > 0 ){ var msg = '#TEXT[XMSG_CANNOT_DEL_REUSABLE_UNIT]'; PROMPT(msg); LOG[1,msg] return false; } return true; } <@doc> Gets only the reusables usages of a given unit. AN object of the type Unit Returns an array of reusable usages method getReusableUsages(unit) var list = []; if (!unit.isReusable()) return list; var usages = this.getUsages(unit); for (var id in usages){ if (this.isPrimaryUsage(usages[id])) continue; list.push(usages[id]); } return list; end <@doc> Checks iff unit is deleted. AN object of the type Unit returns ~true iff unit is deleted method isUnitDeleted(unit) if (!unit || typeof unit != "object") return true; var index = this.getIndex(); if (!index[unit.id]) return true; return index[unit.id].unused; end <@doc> Checks iff element is deleted. AN object of the type Element returns ~true iff element is deleted method isElementDeleted(elem) if (!elem || typeof elem != "object") return true; var not_in_model = (!elem.parent || !elem.unit) if (not_in_model) return true; //to identify an element that is part of a deleted unit (in this case its parent and unit properties are properly initialized): var elem_unused =false; var unit_id = elem.unit && elem.unit.id || null; if (unit_id) elem_unused = this.getIndex()[unit_id].unused; else elem_unused = true; return elem_unused; end /* <@doc scope="private"> Moves the primary usages of a given unit to another parent unit (thus in effect moving the unit in the model organizational hierarchy) method movePrimaryUsages(unit, parent, pos) var primary=this.getPrimaryUsages(unit); if (ISEMPTY(primary)) return false; try { var df=false, x0=0, y0=0; BEGIN('move unit'); for (var k in primary) { if (!parent.insertElement(primary[k], 'elements')) throw -1; if (!pos) continue; var pos2=SPLIT(primary[k].getProperty('@g:pos')), x=INT(pos2[0]), y=INT(pos2[1]); if (!df) x0=x, y0=y, df=true; primary[k].setProperty('@g:pos',(pos.x+x-x0)+' '+(pos.y+y-y0)); } COMMIT(); return true; } catch(e) { ROLLBACK(); return false; } end */ /////////////////////////////////////////////////////////////////////// // PRIVATE INDEX METHODS <@doc scope="private"> Parses an XML document containing the model index The XML document containing the model index to parse method parseIndex(xml) var model = this.model; model.lastId = xml.getAttribute('lastId')||''; model.masterLanguage = xml.getAttribute('masterLanguage')||'en'; SETVAR('masterLanguage', model.masterLanguage); this.index = {}; this.compatibleOrganizer.index = this.index; var children=xml.childNodes, ch; while (ch = children.nextNode()) { var id = ch.getAttribute('id')||''; var pid = ch.getAttribute('parent')||''; var usg = ch.getAttribute('usages')||''; var name = UNESCAPEXML(ch.getAttribute('name')||''); var type = ch.getAttribute('type')||'';; if (!id) continue; var node = this.addIndexNode(id,name,type); node.type = type; node.name = name; if (pid) { node.parent = this.index[pid]; if (!node.parent) node.parent = this.addIndexNode(pid); node.parent.children[id] = node; } if (usg) { for (var i=0, U=SPLIT(usg), len=U.length; i Produces an XML string representation of the model index The XML string representation of the model index You must call updateIndex before calling this method to make sure the index is uptodate method printIndex() var buf=[], model=this.model; var reusblesId = model.reusables && model.reusables.id || '' ; buf.push(''); var unusedUnits = this.getUnusedUnits(); for (var k in this.index) { var node = this.index[k], U=[], p='', u='' , type='' , name=''; if (unusedUnits[k]) continue; for (var k2 in node.usages) U.push(k2); if (U.length > 0) u=' usages="'+JOIN(U,' ')+'"'; if (node.parent) p=' parent="'+node.parent.id+'"'; type = ' type="'+ (node.type || 'core.gml:Unit')+'" '; name = ' name="' + ESCAPEXML(node.name) + '" ' buf.push(''); } buf.push(''); return JOIN(buf); end <@doc scope="private"> Updates the index and marks all units that are not in use (a unit is not in use if there is no usages chain that connects it to the root unit) method updateIndex() var unusedUnits = this.getUnusedUnits(); this.updateUsages(unusedUnits); for (var id in unusedUnits) this.index[id].unused = unusedUnits[id]; end <@doc scope="private"> Updates the usages collection of each unit in the index collection. A collection of all the unused units in the index collection method updateUsages(unusedUnits) if (!$ENV.recorder) return; var deleted = {}; $ENV.recorder.execute('doUpdateUsages',this.model,this.index,unusedUnits,deleted); end <@doc scope="private"> Gets an array of units which indicates for each unit whether it is unused (a unit is not in use if there is no usages chain that connects it to the root unit) Array of units which indicates for each unit whether it is unused method getUnusedUnits() var index=this.index, model=this.model; if (!model || !model.root) return []; var unusedUnits=[]; for (var id in index) unusedUnits[id] = false; var empty, done, unused, usages; var rootId=model.root.id; var reusablesId = model.reusables.id; //TEMPORARY var poolId = model.infoshape_pool.id; do { empty = true; done = true; for (var id in unusedUnits) { if (id == rootId || id == reusablesId || unusedUnits[id]) continue; //temporary if (id == poolId) continue; usages = index[id].usages; empty = false; unused = true; for (var key in usages) { var k = key.substring(0, key.indexOf('.')); if (!unusedUnits[k]) { unused = false; break; } } if (unused) { unusedUnits[id] = true; done = false; } } } while (!empty && !done); return unusedUnits; end <@doc> Gets the list of all orphan index nodes The list of orphan index nodes method getOrphansList() var index=this.index, unused=this.getUnusedUnits, list={}; for (var id in unused) { if (unused[id]) list[id] = index[id]; } return list; end /////////////////////////////////////////////////////////////////////// // TREE PROVIDER INTERFACE <@doc> Gets the root id of a given element An object of the type @Unit! An object of the type @Element! method getRootId(obj) var unit= null; if(obj.isa('#NS[Unit]')){ unit=obj; }else{ unit= obj.unit; } for( var node = this.getIndex()[unit.id],parent= node.parent ; parent; parent = node.parent){ node=parent; } return node && node.id || '' ; end method getNodeType(nodeId) var A = SPLIT(nodeId,'.'); if (!A) return null; switch (A.length){ case 1: return #[TREE_UNIT];// The id format unitId case 2: return #[TREE_ELEMENT];// The id format containing UnidId.elementId case 3: return #[TREE_USAGE];// The id format containing UnitId.UsageId.targetUnitId default: return null; } end <@doc scope="private"> Gets the root tree node The root node method getRoot() return this.ConfigRoot(); end <@doc scope="private"> Gets a specified tree node The Id of the tree node to get The requested tree node method getNode(id) if ( id == 'root') return this.getRoot(); var type = this.getNodeType(id); if (type == #[TREE_UNIT]){ return this.ConfigUnit(this.model,this.model.getUnit(id) ); }else{ id = this.getElementId(id); return this.ConfigNode(this.model,this.model.getElement(id)); } end //TODO: optimize this method. <@doc scope="private"> Gets the child nodes of a specified tree node The Id of the tree node to get The requested child nodes array method getChildNodes(id) try { var level = GETVAR('browserFilterLevel'); if (!level) return {}; var list = []; if( id =='root'){ list.push(this.ConfigUnit(this.model.reusables)); list.push(this.ConfigUnit(this.model.root)); return list; } var unit = this.model.getUnit(id); var C = unit.getCollection('core.gml:Usage'); var usagesList = this.configSet(C); var portsList = null; var interactorsList = null; var statesList = null; var stepsList = null; if(level == #[SHOW_ALL]){ C = unit.getCollection('core.gml:Interactor'); interactorsList = this.configSet(C); C = unit.getCollection('core.gml:Port'); portsList = this.configSet(C); C = unit.getCollection('core.gml:State'); statesList = this.configSet(C); C = unit.getCollection('core.gml:ProcessStep'); stepsList = this.configSet(C); } var node = this.getIndex()[id] ; if (!node) return list; for (var k in C) { if(C[k].isa('core.gml:Usage')) list.push(this.ConfigUsage(C[k])); else list.push(this.ConfigElement(C[k])); } usagesList.sort(collateUsages); SORT(portsList,'name'); SORT(interactorsList,'name'); SORT(statesList,'name'); SORT(stepsList,'name'); return usagesList.concat( statesList||[], stepsList||[] ,interactorsList||[] , portsList||[]) ; function collateUsages(obj1, obj2) { var type1 = obj1._object.Class.fullname; var type2 = obj2._object.Class.fullname; if (type1 == 'core.gml:Module') type1 = '!'; if (type2 == 'core.gml:Module') type2 = '!'; if( !obj1._object.isReusable() ) type1='#'; if( !obj2._object.isReusable() ) type2='#'; var name1 = (type1 + '!' + obj1.name).toUpperCase(); var name2 = (type2 + '!' + obj2.name).toUpperCase(); return (name1name2 ? 1 : 0)); } } catch (e) { #LOG[4 , 'An error occured in getChildNodes :' + e.description] } end <@doc>Configs a set of elements. return an array of tree nodes. method configSet(set) var list = []; for (var k in set) { if(set[k].isa('core.gml:Usage')) list.push(this.ConfigUsage(set[k])); else list.push(this.ConfigElement(set[k])); } return list; end <@doc> Provides a quick method for checking whether a given unit has any child-units return ~true iff the unit has child units method hasChildren(unit) var level = GETVAR('browserFilterLevel'); if(level == #[SHOW_UNITS_AND_USAGES]){ return !ISEMPTY(this.getIndex()[unit.id] && this.getIndex()[unit.id].children ) || !ISEMPTY(unit.getCollection('#NS[Usage]')) ; }else{ return !ISEMPTY(this.getIndex()[unit.id]&& this.getIndex()[unit.id].children) || !ISEMPTY(unit.elements); } end method ConfigUnit(unit) var me = this; return new Config(); function Config(){ this.id = unit.id; if(this.id != me.model.root.id) this.name = unit.name ; else this.name = 'Root Model' ; if ( this.id == me.model.reusables.id && !GETVAR('ReusableMode') ) this.hidden = true; else this.hidden = false; this.size = me.hasChildren(unit) ? 1 : 0 ; this.icon = unit.Class.metadata.icon16 ; this._object = unit; } end method ConfigUsage(usage) var me = this ; return new Config(); function Config (){ this.id = me.getNodeId(usage); var isReusable = me.isReusable(usage.target); var hasChildren = false; // Reusable usage which is not conatained inside reusables module if (isReusable && usage.unit !== me.model.reusables){ this.id = me.getNodeId(usage); this.name = usage.name; this.icon = usage.Class.metadata.icon16 ; this._object = usage; }else{ var unit = me.model.getUnit(usage.target); this.id = unit.id; this.name = unit.name ; hasChildren = me.hasChildren(unit); this.icon = unit.Class.metadata.icon16 ; this._object = unit; } this.size = hasChildren ? 1 : 0 ; } end method ConfigElement(element) var me = this ; return new Config(); function Config (){ this.id = me.getNodeId(element); this.name = element.name; this.size = 0 ; this.icon = element.Class.metadata.icon16 ; this._object = element; } end method ConfigRoot() return new Config(); function Config(){ this.id = 'root'; this.name = ''; this.size = 1; } end <@doc scope="private"> Gets the path of Ids leading upto a specified tree node The Id of the tree node to get The requested tree node path method getNodePath(id) var unitId = this.getUnitId(id); var list = []; var type = this.getNodeType(id); if ( type == #[TREE_ELEMENT] || type == #[TREE_USAGE] ) list.push(id); var unit = this.model.getUnit(unitId); while (unit) { list.push(this.getNodeId(unit)); unit = unit.getParent(); } if(unit) list.push(this.getNodeId(unit)); return list.reverse(); end <@doc> Gets the node id acourding to it's type: Unit : unitId reusable Usage: containingUnit.usageId.targetUnitId not reusable Usage: targetUnitId other elements: containingUnitId.elementId A Gml object method getNodeId(obj) if (!obj) return ''; // handle unit if ( obj.isa('core.gml:Unit')){ return obj.id || ''; // handle usage }else if(obj.isa('core.gml:Usage')){ var usageId = obj.id ; var unitId = obj.unit && obj.unit.id || null; var target = obj.target || null ; if ( this.isPrimaryUsage(obj) && target ) return target; if (usageId && unitId && target ) return unitId +'.'+ usageId +'.'+target ; return ''; // handle the rest of the elements }else{ var unitId = obj.unit && obj.unit.id || null; if(unitId) return unitId + "." + obj.id; return ''; } end method getUnitId(nodeId) if( nodeId == 'root') return this.model.root.id ; var A = SPLIT(nodeId , '.'); if (!A) return ''; return A[0]; end method getElementId(nodeId) var A = SPLIT(nodeId , '.'); if (!A) return ''; switch (A.length){ case 2: return nodeId;// The id format containingUnidId.elementId case 3: return A[0] +'.'+ A[1];// The id format containingUnitId.UsageId.targetUnitId default: return ''; } end /*<@doc scope="private"> specifies whther a given element is filtered method isFiltered(elm) if(!elm) return true; // There is no filter on Units or usages. if(elm.isa('core.gml:Unit') || elm.isa('core.gml:Usage')) return false; //All other elements - do filter only if the filter level is SHOW_uNITS_AND_USAGES if(GETVAR('browserFilterLevel') == #[SHOW_ALL]) return false; return true; end */ transaction doUpdateUsages(model, index,unusedUnits,deleted) do,redo: deleted = {}; for ( var id in index){ var usages = index[id].usages ; for (var uid in usages){ var A = model.parseFullId(uid); if(!A){ continue; } if(unusedUnits[ A[0] ]){ if (!deleted[id]) deleted[id] = {} ; deleted[id][uid] = usages[uid]; delete usages[uid] ; } } } undo: for (var id in deleted){ if (!deleted[id]) continue; for (var uid in deleted[id]){ index[id].usages[uid] = deleted[id][uid]; } } end listen onRenameObject for core.gml:Unit var unitNode = $ENV.organizer.index[object.id]; if (!unitNode) { // The Unit is not yet in the index file, Therefore no update should be done. return; } $ENV.recorder.execute('renameUnitInIndex', unitNode, newname, oldname); end transaction renameUnitInIndex(item, newName,oldName) do,redo: if (item.hasOwnProperty("name")) item.name = newName; undo: if (item.hasOwnProperty("name")) item.name = oldName; end /////////////////////////////////////////////////////////////////////// // YOU'VE GOT TO BE KIDDING // // The above must be the definition of the class from hell. // This is the sorriest example of object oriented programming I've seen in my life. // What has happened to have caused it is beyond my comprehension. // I give up. I'll just setup a cleaned up interface and will look the other way. // // Yuval, 16/02/2006 // method setupCompatibleOrganizer() this.compatibleOrganizer = { model: this.model, index: this.index, getRoot: this._getRoot, getParent: this._getParent, getAncestors: this._getAncestors, getChildNodes: this._getChildNodes, hasChildNodes: this._hasChildNodes } end method _getRoot() return this.index[this.model.root.id]; end method _getParent(id) var node = this.index[id]; return node && node.parent || null; end method _getAncestors(id) var node=this.index[id], list=[]; while (node) { list.push(node); node = node.parent; } return list.reverse(); end method _getChildNodes(id) var node=this.index[id], list=[]; if (node) { for (var k in node.children) { list.push(node.children[k]); } } return list; end method _hasChildNodes(id) var node=this.index[id]; return node && !ISEMPTY(node.children) || false; end