<@doc alias="unit" hierarchy="GMLDOM"> The Unit is the basic organizational unit in %GML%, enabling modularity and reusability. A %GML% model is always made of a collection of one or more %GML% units, referenced by unique identifiers. A %GML% unit, in turn, is made of a collection of one or more %GML% elements, referenced by unique identifiers. The %GML% unit is also the basic unit for persistance and for communication. When a model is read, saved, or transported, it is always done by whole units. A %GML% unit may be presented to the user using different design boards. (c) SAP AG 2003-2006. All rights reserved. #ALIAS[g=core.svg:GmlDrawing] #INCLUDE[svg:defs.inc] #INCLUDE[dev:defs.inc] #INCLUDE[defs.inc] #INCLUDE[defs.inc] /////////////////////////////////////////////////////////////////////// // CLASS HEADER Class Unit inherit TransObject; implement dev:IInfosetEnumerator; metadata title = '#TEXT[XTIT_UNIT]'; metadata descr = '#TEXT[XTOL_UNIT]'; metadata usageElement = 'core.gml:Usage'; attach svg:PlanarDiagram; attach dev:PalChildElements; /////////////////////////////////////////////////////////////////////// // PROPERTIES <@doc>Gets the last unit modification date (in string representation) readonly property modified = ''; <@doc>Gets the unit version number readonly property version = ''; /////////////////////////////////////////////////////////////////////// // VIRTUAL/STATIC PROPERTIES <@doc>Indicates whether the unit is deleted (has been removed from the model since last open) virtual readonly property deleted = false; <@doc>Indicates whether the unit is dirty (has been changed since last save) virtual readonly property dirty = false; <@doc scope="private">Gets the collection of all elements owned by this unit (recursively). this member is used for optimizing access to elements. virtual readonly property all_elements = ^Element[id]; <@doc>Gets the collection of all elements directly owned by this unit (non-recursive) strong readonly property elements = ^Element[id]; <@doc>Gets the model that owns this unit virtual readonly property model = ^Model; <@doc>Holds resoureces such as translations table. strong readonly property resources = ^Resource[id]; // For future uses for resources other than translations /////////////////////////////////////////////////////////////////////// // METHODS <@doc> Creates a new unit and inserts a corresponding unit usage into this unit The unit class name A collection of property values for initializing the new unit A collection of property values for initializing the new unit usage The usage of the newly created unit, or ~null in case of any error method createUnit(className, unitValues, usageValues) var newunit = this.model.createUnit(className, unitValues); if (!newunit) return null; var usage = newunit.createNewUsage(usageValues); if (!usage) return null; if (!this.insertElement(usage, 'elements')) return null; return usage; end <@doc> Creates a new usage object that is pointing to this unit. This usage is not inserted in the model yet. A collection of property values for initializing the new unit usage The new usage for this unit method createNewUsage(usageValues) var usageClass = this.Class.metadata.usageElement; if (!usageClass) return null; if (!usageValues) usageValues = {}; usageValues.target = this.id; return $ENV.model.createElement(usageClass, usageValues); end override method getCollection(className, deep) var E={}, C=this[deep ? 'all_elements' : 'children']; className=$DOM.toQName(className); if (!className) return E; for (var k in C) { if (className in C[k].Class.precedents) E[k]=C[k]; } return E; end override method getElement(id, deep) return this[deep ? 'all_elements' : 'children'][id] || null; end <@doc> Gets the collection of all usage elements that point to this unit The usages collection, indexed by usage key method getUsages() return $ENV.organizer.getUsages(this); end <@doc> Gets the collection of units that are referenced by this unit (and thus precede it). The requested units collection method getPrecedents() var C={}, E=this.children; for (var id in E) { if (!('core.gml:Usage' in E[id].Class.precedents)) continue; var trg=E[id].getTarget(); if (trg) C[trg.id] = trg; } return C; end <@doc> Gets the collection of units that reference this unit (and thus depend on it). The requested units collection method getDependents() var C={}, U=$ENV.organizer.getUsages(this); for (var key in U) { var unitobj=U[key].unit; C[unitobj.id] = unitobj; } return C; end <@doc> Gets the table of all element plugs that can be connected to a given plug. The plug to query. It can be either an source plug or a target plug. The table of plugs that can be connected to the given plug, or ~null in case no valid target plugs were found. method getConnectablePlugs(plug) return null; end <@doc> Indicates whether the unit is editable Returns ~true when the unit is editable, and ~false when it is readonly method isEditable() return this.model.isEditable(); end <@doc> Indicates whether the unit is enabled for editing Returns ~true when the unit is enabled, ~false otherwise method isEnabled() return this.model.isEnabled(); end override method onCreate() if (!this.name) this.name = this.Class.name + ' ' + this.id; if (!this.modified) this.modified = DSTR(new Date(), 'DD/MM/YYYY'); if (!this.version) this.version = '1.0'; this.supercall(); end override method onInsert(child, trans) this.supercall(); // if child has a namestem, enumerate it accordingly var stem = child.Class.metadata.namestem; if (stem && child.name == stem) { var C = this.children, max=0; for (var k in C) { if (C[k].Class.metadata.namestem != stem) continue; var name=C[k].name, num=POS(name.substring(stem.length)); if (name == stem+num) max = MAX(num, max); } child.setProperty('name', stem+(max+1)); } end override method setDirty(isSVGChange) this.dirty = true; if (this.model) this.model.setDirty(isSVGChange); end <@doc> Determines whether the object can be drilled into or not. True if the unit can be drilled into. method canActivate() return true; end <@doc scope=private> Performs a deep copy of this unit's properties and elements. A collection that maps the 'old unit's children ID to a new unit's children ID The newly cloned unit method clone(elementsMap) try { var copy = $ENV.model.createRawUnit(this.Class.fullname, cloneProperties(this)); if (!copy) throw new Error(-1, '#TEXT[XMSG_FAILED_TO_CREATE] '+className+' unit'); // clone children var clonedElems = $ENV.model.cloneElements(this.children, null, elementsMap); for (var k in clonedElems) { var elem = clonedElems[k]; if (elem && elem.parent_prop != '') copy.insertElement(elem, elem.parent_prop); } return copy; } catch(e) { WRITE(e.description); return null; } function cloneProperties(elem) { var P=elem.Class.properties, V={}; for (var name in P) { var prop=P[name], value=elem[name]; if (!elem.hasOwnProperty(name) || name== 'id') continue; if ((!prop.isVirtual || (prop.name == 'parent_prop')) && !prop.isStatic && prop.type != 'vector' && prop.type != 'collection') V[name] = CLONE(value); } return V; } end <@doc> Tests whether the unit is a reusable unit Return ~true iff the unit is a reusable unit. method isReusable() return $ENV.organizer.isReusable(this.id); end <@doc> Gets the parent unit of the current unit. Returns the parent unit, or ~null in the case this is root unit method getParent() return $ENV.organizer.getParent(this); end method getPrimaryUsages() return $ENV.organizer.getPrimaryUsages(this); end <@doc> Gets a collection of all the child units of the current unit specify reusable or not reusable units The requested units collection if @gml:Unit is omitted then all child units are returned method getChildUnits(type) var C = {}; var term = function (){ return false;}; switch(type){ case #[REUSABLE]: term = function (obj){return !obj.isReusable();}; break; case #[NOT_REUSABLE]: term = function (obj){return obj.isReusable();}; break; } var usages = this.getCollection('#NS[Usage]'); for ( var id in usages){ var usage = usages[id] ; if(term(usage)) continue; var unit = usage.getTarget(); C[unit.id] = unit ; } return C; end <@doc> Provides a method for checking whether a given unit is contained in this unit's child units the taarget unit to check return ~true iff the unit is contained method isContainedInUnit(targetUnit) if (this.id==targetUnit.id) return true; var parent = targetUnit.getParent(); if (parent && this.isContainedInUnit(parent)) return true; return false; end <@doc> Provides a method for checking whether a given unit has any child-units specify reusable or not reusable units return ~true iff the unit has child units method hasChildUnits(type) var usages = this.getCollection('#NS[Usage]'); if (!type) return !ISEMPTY(this.getCollection('#NS[Usage]')); var term = function (){ return false;}; switch(type){ case #[REUSABLE]: term = function (obj){return obj.isReusable();}; break; case #[NOT_REUSABLE]: term = function (obj){return !obj.isReusable();}; break; } for(var id in usages){ if (term(usages[id])) return true; } return false; end ///////////////////////////////////// // IINFOSETENUMERATOR METHODS - prototype implementation <@doc> Gets a flat list of infosets The list can contain interactor/ports/plugs as infoset IDs. Indicates whether to perform a deep search Collection of @dev:IInfoset! elements override method getInfosetList(deep) var infosets = this.getCollection('dev:IInfoset', deep); for(var i in infosets ) { var set = infosets[i]; if(ISA(set, 'dev:IInfosetEnumerator')) //check if a usage { // Get the usage infosets (plugs): var innerInfoSets = set.getInfosetList(false); if(innerInfoSets ) { for(var j in innerInfoSets) { // Add to the rest of the infosets: infosets[j] = innerInfoSets[j]; } } } } return infosets; end <@doc> Gets a tree of infosets. Tree provider of the infosets override method getInfosetTree() // TO BE IMPLEMENTED return null; end <@doc> Tell if the object or it's expected children can have properties that can be translated. ~true if strings are possible, ~false otherwise override method canBeTranslated() return(true); // false by default; end /////////////////////////////////////////////////////////////////////// // EVENT LISTENERS listen onDiagramMenu menu.append({button:'SEARCH_UPWARD'}); menu.append({button:'EDIT_PROPERTIES'}); menu.append(); //menu.append({button:'EDIT_PASTE', signal:'BOARD->paste({x:'+pos.x+',y:'+pos.y+'})'}); if(GETVAR('ReusableMode')) menu.append({button:'EDIT_PASTE_AS_LINK', signal:'BOARD->paste({x:'+pos.x+',y:'+pos.y+'},#[FORCE_LINK])'}); //[DIS_CPUR]menu.append({button:'EDIT_PASTE_AS_COPY', signal:'BOARD->paste({x:'+pos.x+',y:'+pos.y+'},#[FORCE_COPY])'}); menu.append({button:'EDIT_RENAME'}); menu.append({button:'EDIT_ANNOTATE', signal:'BOARD->annotate({x:'+pos.x+',y:'+pos.y+'})'}); menu.append(); var clipboardElement=$ENV.model.getClipboard("element"); if (clipboardElement && $ENV.triggerEvent("canInsertElement",$ENV.context.object,clipboardElement,$ENV.context.object,"elements","pasteEvent")){ menu.append({button:'PASTE_ELEMENT'}); menu.append(); } menu.append({button:'VIEW_ACTUAL_SIZE'}); menu.append({button:'VIEW_FIT_WINDOW'}); menu.append({button:'FILE_PRINT'}); end listen onRegionMenu var box=STR(rect); menu.append({signal:'BOARD->selectByArea('+box+')', text:'#TEXT[XMIT_SELECT]', icon:'#URL[dev~skin:icons.select.gif]'}); menu.append({signal:'BOARD->zoomArea('+box+')', text:'#TEXT[XMIT_ZOOM]', icon:'#URL[dev~skin:icons.zoom.gif]'}); menu.append(); menu.append({signal:'BOARD->cancel', text:'#TEXT[XMIT_CANCEL]'}); end listen onRenameObject for core.gml:Unit BEGIN('rename usages'); var U=object.getPrimaryUsages(); for (var key in U) { if (U[key].name == oldname) U[key].setProperty('name', newname); } COMMIT(); $ENV.fireModelOrganize(object); end listen onRenameObject for core.gml:Usage BEGIN('rename unit'); if(object.isPrimaryUsage() ) { object.getTarget().setProperty('name', newname); $ENV.fireModelOrganize(object.getTarget()); }else{ $ENV.fireModelOrganize(null,null,null,object); } COMMIT(); end listen canInsertElement for core.gml:Unit if (prop_name != 'elements') return; //childElements restriction on Unit 'elements' var C=evt.unit.Class.metadata.childElements, P=evt.child.Class.precedents; if (!C) { evt.cancel = true; return; } if (evt.subType=="pasteEvent" && ISA(evt.child,"core.gml:Usage") && evt.child.getTarget().isContainedInUnit(evt.unit)) { evt.cancel = true; return; } for (var i=0, len=C.length; i An enumeration of the unit types REUSABLE | Reusable unit NOT_REUSABLE | Not reusable unit