<@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