@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