@doc hierarchy="GMLDOM">
DEPRECATED. Aspect for drawing planar diagrams based on the old GMLDOM transactional model.
(c) SAP AG 2003-2006. All rights reserved.
#INCLUDE[dev:defs.inc]
Aspect PlanarDiagram for GmlDrawing;
inherit Diagram;
//////////////////////////////////////////////////////////////////////////////////////
// GENERIC DRAWING TRANSACTION
override virtual method begin(name, ptr)
if (this.inTrans) return;
var snapshot = ptr && ptr.snapshot || null;
$ENV.recorder.begin(name, snapshot);
this.board.freeze(#[SVG_FREEZE_CANVAS]);
this.inTrans = true;
end
override virtual method commit(ptr)
if (!this.inTrans) return;
this.inTrans = false;
var snapshot = (ptr && ptr.scrolled) ? this.board.captureSnapshot() : null;
try {
// commit buffered reroutes
if (this.reroutesBuf) {
var buf=this.reroutesBuf, L={};
for (var k in buf) {
var line = buf[k];
// TODO: verify whether following test is indeed required
if (line.base !== this.base.getElement(k)) continue;
L[k] = line;
}
this.reroutesBuf = null;
for (var k in L) L[k].reroute();
}
this.board.unfreeze(#[SVG_FREEZE_ALL]);
$ENV.recorder.commit(snapshot);
} catch(e) {
this.board.unfreeze(#[SVG_FREEZE_ALL]);
$ENV.recorder.rollback();
throw e;
}
end
override virtual method rollback()
this.inTrans = false;
this.reroutesBuf = null;
this.updatesBuf = null;
this.board.unfreeze(#[SVG_FREEZE_ALL]);
$ENV.recorder.rollback();
end
override virtual method bufferedReroute(line)
if (!this.inTrans) return false;
if (!this.reroutesBuf) this.reroutesBuf = {};
this.reroutesBuf[line.id] = line;
return true;
end
override virtual method bufferedUpdate(graphic, prop, value)
graphic.base.setProperty(prop, value);
end
override virtual method silentUpdate(graphic, prop, value)
graphic.base.setProperty(prop, value, true);
end
//////////////////////////////////////////////////////////////////////////////////////
// CONCRETE DRAWING TRANSACTIONS
override virtual method copyClipboard()
if (!this.isEditable || this.nselected == 0) return false;
var b=this.board, C=this.getSelectedObjects();
if (!this.validateAction(C,'copy\\cut')) return false;
$ENV.context.clipboard = C ;
b.clipboard = C;
b.clipdelta = 0;
return true;
end
override virtual method createLine(gmlclass, srcPlug, trgPlug)
try {
this.begin('connect shapes');
var newLink = this.base.createElement(gmlclass, 'elements', {source:srcPlug, target:trgPlug});
if (!newLink) throw new Error(-1, '#TEXT[XMSG_FAIL_CREATE_LINK]');
this.commit();
$ENV.context = newLink;
return newLink;
} catch(e) {
#LOG[4, 'Failed to connect shapes: '+e.description];
this.rollback();
}
end
override virtual method createShape(gmlclass, values, pos, targetGroup)
try {
this.begin('create shape');
var gmlcstor=CLASS(gmlclass), V={};
if (values) for (var k in values) V[k] = values[k];
if (pos) V['@pos'] = pos.x+' '+pos.y;
var newElem = null;
if (gmlcstor.isa('core.gml:Unit')) {
newElem = base.createUnit(gmlclass, null, V);
} else {
newElem = base.createElement(gmlclass, 'elements', V);
}
if (!newElem) throw new Error(-1, '');
var shape = this.allShapes[newElem.id];
if (pos && targetGroup) {
var trggrp = this.allGroups[targetGroup.id];
trggrp.base.attachElement(shape.base);
shape.moveto((pos.x-shape.ox)/shape.os, (pos.y-shape.oy)/shape.os);
shape.adjustWireframe();
this.selgroup = trggrp;
} else {
this.selgroup = this;
}
this.plowShape(shape);
this.repackSelection();
this.commit();
$ENV.context = newElem;
return newElem;
} catch (e) {
#LOG[4, 'Failed to create shape: '+e.description];
this.rollback();
}
end
override virtual method cutClipboard()
if (!this.isEditable) return;
if(!this.copyClipboard()) return;
this.deleteSelection();
end
override virtual method deleteSelection()
if (!this.isEditable || this.nselected == 0) return;
var S=this.selection;
//create array of to-be-deleted GML objects - we use it for delete validation
var elements = [];
for (var k in S) elements.push(this.base.elements[k]);
if (!$ENV.canDeleteStableIDs(elements, true, false)) // check if the objects deletion has translation/personalization implications
return; //they do ... and modeler chose to cancel the operation
try {
this.begin('delete shape(s)');
for (var k in S) {
//If an object is a usage and removed from the diagram, this function removes its associated diagram from the
//canvas diagram cache.
this.removeFromCanvasCache(k);
this.base.removeElement(k, 'elements');
}
this.clearSelection();
this.commit();
} catch(e) {
#LOG[4, 'Failed to delete shape(s): '+e.description];
this.rollback();
}
end
override virtual method drilldownSelection()
var usage = this.focus && this.focus.base;
if (!usage || !usage.isa('core.gml:Usage') || !usage.target) return;
try { $ENV.context = usage.target; } catch(e) {} // might happen for units which cannot be drilled into
end
override virtual method duplicateSelection()
if (!this.isEditable || this.nselected == 0) return;
var C=this.getSelectedObjects();
this.pasteElements(C, 10);
end
override virtual method endAnnotate(data)
if (!data || !data.value) return;
try {
this.begin('create annotation');
var note = this.base.createElement('core.gml:Note', 'elements', {notes:data.value, '@pos':data.pos.x+' '+data.pos.y, '@fillColor':'#FFFFE1', '@textColor':'#[BLK]'});
var shape = this.allShapes[note.id], u=#[SVG_SNAPUNIT];
shape.autoFit();
shape.moveby(FLOOR(shape.w/2,u), FLOOR(shape.h/2,u));
this.commit();
$ENV.context = note;
} catch (e) {
#LOG[4, 'Failed to create annotation: '+e.description];
this.rollback();
}
end
override virtual method endRename(data)
try {
this.begin('rename shape');
this.bufferedUpdate(data.graphic, data.attr, data.value);
if (data.graphic.isa('core.svg:Shape')) data.graphic.autoFit();
this.commit();
} catch(e) {
#LOG[4, 'Failed to rename shape: '+e.description];
this.rollback();
}
end
override virtual method moveSelection(offset, ptr)
this.supercall();
end
override virtual method pasteClipboard(pos, force)
force = INT(force);
var b=this.board;
if (!this.isEditable || !b.clipboard) return;
b.clipdelta = POS(b.clipdelta) + 10;
var evt = SVG.createModelEvent('canPasteElement');
evt.unit = this.base;
evt.elements = b.clipboard;
evt.cancel = false;
for ( var id in b.clipboard){
evt.object = b.clipboard[id];
$ENV.fireModelEvent(evt);
if(evt.cancel) {
return;
}
}
this.pasteElements(b.clipboard, b.clipdelta, force);
end
override virtual method plowDiagram()
this.supercall();
end
override virtual method regroupSelection(offset, srcgrp, trggrp, ptr)
try {
this.begin('regroup shape(s)', ptr);
var regroupedShapes={};
for (var k in this.selection) {
var shape=this.selection[k];
if (!shape.isa('core.svg:Shape')) continue;
if (shape.base.@protect & #[SVG_PROTECT_MOVE]) continue;
var ox=shape.ox, oy=shape.oy, os=shape.os;
var cx = ox+shape.cx*os+offset.x;
var cy = oy+shape.cy*os+offset.y;
if (trggrp != this) {
cx = (cx-trggrp.qx)/trggrp.qs;
cy = (cy-trggrp.qy)/trggrp.qs;
trggrp.base.attachElement(shape.base, {x:cx, y:cy});
} else if (srcgrp != this) {
srcgrp.base.detachElement(shape.base, {x:cx, y:cy});
}
regroupedShapes[k] = shape;
}
this.selgroup = trggrp;
this.plowShapesList(regroupedShapes);
this.repackSelection();
this.commit(ptr);
} catch(e) {
this.rollback();
#LOG[4, 'Failed to regroup shape(s): '+e.description];
}
end
override virtual method resizeSelection(size, pos, ptr)
this.supercall();
end
override virtual method rotateSelection(dir)
this.supercall();
end
//////////////////////////////////////////////////////////////////////////////////////
// UTILITIES
<@doc scope="private">
Pastes a given collection of elements into the diagram.
The collection of elements, all from same diagram, to be cloned. This collection should also contain all state members that should be cloned.
virtual method pasteElements(elements, offset, force)
if (!this.isEditable || !elements) return;
if (!this.validateAction(elements,'paste')) return ;
try {
this.begin('paste shape(s)');
this.begin('paste');
var copyList=$ENV.model.cloneElements(elements, force), plowList={}, selList=[];
for (var k in elements) {
if (k in this.allShapes) plowList[k] = this.allShapes[k];
}
//first insert all non-links and only then insert links.
for (var k in copyList) {
if (!copyList[k].isa('core.gml:Link'))
insertElem(this, copyList[k]);
}
for (var k in copyList) {
if (copyList[k].isa('core.gml:Link'))
insertElem(this, copyList[k]);
}
function insertElem(me, copy) {
copyId=copy.id;
if (!copy || copy.state || !me.base.insertElement(copy, 'elements')) return;
var pos=SPLIT(copy.@pos);
copy.setProperty('@pos', Math.round(INT(pos[0])+offset)+' '+Math.round(INT(pos[1])+offset));
selList.push(copyId);
}
this.commit();
this.plowShapesList(plowList);
this.commit(this.board.captureSnapshot());
this.selectByIdList(selList);
} catch(e) {
#LOG[4, 'Failed to paste shape(s): '+e.description];
this.rollback();
}
end
<@doc scope="private">
Validates whether a given collection of elements can be copied or pasted.
virtual method validateAction(elements, action)
for ( var i in elements ){
if (ISA(elements[i] ,'core.gml:ModuleUsage')){
#LOG[4, 'Failed to '+ action +' Modules(s):This action is not valid in this version. '];
return false;
}
}
return true ;
end