2014-06-30 15:01:00 +00:00
|
|
|
'use strict';
|
|
|
|
|
2015-02-02 13:46:21 +00:00
|
|
|
var assign = require('lodash/object/assign'),
|
|
|
|
map = require('lodash/collection/map');
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2015-04-27 14:50:09 +00:00
|
|
|
var LabelUtil = require('../util/LabelUtil');
|
2014-07-23 16:53:33 +00:00
|
|
|
|
2015-07-15 06:50:21 +00:00
|
|
|
var is = require('../util/ModelUtil').is;
|
|
|
|
|
2014-07-23 16:53:33 +00:00
|
|
|
var hasExternalLabel = LabelUtil.hasExternalLabel,
|
|
|
|
getExternalLabelBounds = LabelUtil.getExternalLabelBounds,
|
2015-04-27 14:50:09 +00:00
|
|
|
isExpanded = require('../util/DiUtil').isExpanded,
|
2014-10-31 14:05:16 +00:00
|
|
|
elementToString = require('./Util').elementToString;
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-23 16:53:33 +00:00
|
|
|
|
|
|
|
function elementData(semantic, attrs) {
|
2015-02-02 13:46:21 +00:00
|
|
|
return assign({
|
2014-07-23 16:53:33 +00:00
|
|
|
id: semantic.id,
|
|
|
|
type: semantic.$type,
|
|
|
|
businessObject: semantic
|
|
|
|
}, attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
function collectWaypoints(waypoints) {
|
2015-02-02 13:46:21 +00:00
|
|
|
return map(waypoints, function(p) {
|
2014-07-23 16:53:33 +00:00
|
|
|
return { x: p.x, y: p.y };
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-07-15 06:50:21 +00:00
|
|
|
function notYetDrawn(semantic, refSemantic, property) {
|
|
|
|
return new Error(
|
|
|
|
'element ' + elementToString(refSemantic) + ' referenced by ' +
|
|
|
|
elementToString(semantic) + '#' + property + ' not yet drawn');
|
|
|
|
}
|
2014-07-23 16:53:33 +00:00
|
|
|
|
2014-06-30 15:01:00 +00:00
|
|
|
/**
|
|
|
|
* An importer that adds bpmn elements to the canvas
|
|
|
|
*
|
|
|
|
* @param {EventBus} eventBus
|
|
|
|
* @param {Canvas} canvas
|
2014-07-23 16:53:33 +00:00
|
|
|
* @param {ElementFactory} elementFactory
|
|
|
|
* @param {ElementRegistry} elementRegistry
|
2014-06-30 15:01:00 +00:00
|
|
|
*/
|
2014-07-23 16:53:33 +00:00
|
|
|
function BpmnImporter(eventBus, canvas, elementFactory, elementRegistry) {
|
2014-06-30 15:01:00 +00:00
|
|
|
this._eventBus = eventBus;
|
|
|
|
this._canvas = canvas;
|
2014-07-18 12:39:15 +00:00
|
|
|
|
|
|
|
this._elementFactory = elementFactory;
|
2014-07-23 16:53:33 +00:00
|
|
|
this._elementRegistry = elementRegistry;
|
2014-06-30 15:01:00 +00:00
|
|
|
}
|
|
|
|
|
2014-07-23 16:53:33 +00:00
|
|
|
BpmnImporter.$inject = [ 'eventBus', 'canvas', 'elementFactory', 'elementRegistry' ];
|
|
|
|
|
|
|
|
module.exports = BpmnImporter;
|
2014-06-30 15:01:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-07-16 14:15:23 +00:00
|
|
|
* Add bpmn element (semantic) to the canvas onto the
|
|
|
|
* specified parent shape.
|
2014-06-30 15:01:00 +00:00
|
|
|
*/
|
2014-07-18 12:39:15 +00:00
|
|
|
BpmnImporter.prototype.add = function(semantic, parentElement) {
|
|
|
|
|
|
|
|
var di = semantic.di,
|
|
|
|
element;
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-23 16:53:33 +00:00
|
|
|
// ROOT ELEMENT
|
2014-07-01 09:33:28 +00:00
|
|
|
// handle the special case that we deal with a
|
|
|
|
// invisible root element (process or collaboration)
|
|
|
|
if (di.$instanceOf('bpmndi:BPMNPlane')) {
|
|
|
|
|
2014-07-16 14:15:23 +00:00
|
|
|
// add a virtual element (not being drawn)
|
2014-07-23 16:53:33 +00:00
|
|
|
element = this._elementFactory.createRoot(elementData(semantic));
|
2014-11-26 10:49:14 +00:00
|
|
|
|
|
|
|
this._canvas.setRootElement(element);
|
2014-07-18 12:39:15 +00:00
|
|
|
}
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
// SHAPE
|
|
|
|
else if (di.$instanceOf('bpmndi:BPMNShape')) {
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
var collapsed = !isExpanded(semantic);
|
|
|
|
var hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-23 16:53:33 +00:00
|
|
|
var bounds = semantic.di.bounds;
|
|
|
|
|
|
|
|
element = this._elementFactory.createShape(elementData(semantic, {
|
2014-07-18 12:39:15 +00:00
|
|
|
collapsed: collapsed,
|
2014-07-23 16:53:33 +00:00
|
|
|
hidden: hidden,
|
2014-12-22 10:44:44 +00:00
|
|
|
x: Math.round(bounds.x),
|
|
|
|
y: Math.round(bounds.y),
|
|
|
|
width: Math.round(bounds.width),
|
|
|
|
height: Math.round(bounds.height)
|
2014-07-23 16:53:33 +00:00
|
|
|
}));
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2015-07-15 06:50:21 +00:00
|
|
|
if (is(semantic, 'bpmn:BoundaryEvent')) {
|
|
|
|
this._attachBoundary(semantic, element);
|
|
|
|
}
|
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
this._canvas.addShape(element, parentElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CONNECTION
|
2014-07-23 16:53:33 +00:00
|
|
|
else if (di.$instanceOf('bpmndi:BPMNEdge')) {
|
|
|
|
|
|
|
|
var source = this._getSource(semantic),
|
|
|
|
target = this._getTarget(semantic);
|
|
|
|
|
|
|
|
element = this._elementFactory.createConnection(elementData(semantic, {
|
|
|
|
source: source,
|
|
|
|
target: target,
|
|
|
|
waypoints: collectWaypoints(semantic.di.waypoint)
|
|
|
|
}));
|
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
this._canvas.addConnection(element, parentElement);
|
2014-07-23 16:53:33 +00:00
|
|
|
} else {
|
2014-10-31 14:05:16 +00:00
|
|
|
throw new Error('unknown di ' + elementToString(di) + ' for element ' + elementToString(semantic));
|
2014-06-30 15:01:00 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
// (optional) LABEL
|
|
|
|
if (hasExternalLabel(semantic)) {
|
|
|
|
this.addLabel(semantic, element);
|
2014-07-16 14:15:23 +00:00
|
|
|
}
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-11-17 16:36:22 +00:00
|
|
|
|
2014-07-16 14:15:23 +00:00
|
|
|
this._eventBus.fire('bpmnElement.added', { element: element });
|
2014-06-30 15:01:00 +00:00
|
|
|
|
2014-07-16 14:15:23 +00:00
|
|
|
return element;
|
2014-06-30 15:01:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-07-15 06:50:21 +00:00
|
|
|
/**
|
|
|
|
* Attach the boundary element to the given host
|
|
|
|
*
|
|
|
|
* @param {ModdleElement} boundarySemantic
|
|
|
|
* @param {djs.model.Base} boundaryElement
|
|
|
|
*/
|
|
|
|
BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
|
|
|
|
|
|
|
|
var hostSemantic = boundarySemantic.attachedToRef;
|
|
|
|
|
|
|
|
if (!hostSemantic) {
|
|
|
|
throw new Error('missing ' + elementToString(boundarySemantic) + '#attachedToRef');
|
|
|
|
}
|
|
|
|
|
|
|
|
var host = this._elementRegistry.get(hostSemantic.id),
|
|
|
|
attachers = host && host.attachers;
|
|
|
|
|
|
|
|
if (!host) {
|
|
|
|
throw notYetDrawn(boundarySemantic, hostSemantic, 'attachedToRef');
|
|
|
|
}
|
|
|
|
|
|
|
|
// wire element.host <> host.attachers
|
|
|
|
boundaryElement.host = host;
|
|
|
|
|
|
|
|
if (!attachers) {
|
|
|
|
host.attachers = attachers = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attachers.indexOf(boundaryElement) === -1) {
|
|
|
|
attachers.push(boundaryElement);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
/**
|
|
|
|
* add label for an element
|
|
|
|
*/
|
2014-10-31 14:05:16 +00:00
|
|
|
BpmnImporter.prototype.addLabel = function(semantic, element) {
|
2014-07-23 16:53:33 +00:00
|
|
|
var bounds = getExternalLabelBounds(semantic, element);
|
|
|
|
|
|
|
|
var label = this._elementFactory.createLabel(elementData(semantic, {
|
|
|
|
id: semantic.id + '_label',
|
|
|
|
labelTarget: element,
|
|
|
|
type: 'label',
|
2014-09-09 13:20:30 +00:00
|
|
|
hidden: element.hidden,
|
2014-12-22 10:44:44 +00:00
|
|
|
x: Math.round(bounds.x),
|
|
|
|
y: Math.round(bounds.y),
|
|
|
|
width: Math.round(bounds.width),
|
|
|
|
height: Math.round(bounds.height)
|
2014-07-23 16:53:33 +00:00
|
|
|
}));
|
|
|
|
|
2014-07-18 12:39:15 +00:00
|
|
|
return this._canvas.addShape(label, element.parent);
|
|
|
|
};
|
|
|
|
|
2014-10-31 14:05:16 +00:00
|
|
|
/**
|
|
|
|
* Return the drawn connection end based on the given side.
|
|
|
|
*
|
|
|
|
* @throws {Error} if the end is not yet drawn
|
|
|
|
*/
|
|
|
|
BpmnImporter.prototype._getEnd = function(semantic, side) {
|
2014-07-23 16:53:33 +00:00
|
|
|
|
|
|
|
var element,
|
2014-10-31 14:05:16 +00:00
|
|
|
refSemantic,
|
|
|
|
type = semantic.$type;
|
|
|
|
|
|
|
|
refSemantic = semantic[side + 'Ref'];
|
2014-07-23 16:53:33 +00:00
|
|
|
|
|
|
|
// handle mysterious isMany DataAssociation#sourceRef
|
2014-10-31 14:05:16 +00:00
|
|
|
if (side === 'source' && type === 'bpmn:DataInputAssociation') {
|
|
|
|
refSemantic = refSemantic && refSemantic[0];
|
2014-07-23 16:53:33 +00:00
|
|
|
}
|
|
|
|
|
2014-10-31 14:05:16 +00:00
|
|
|
// fix source / target for DataInputAssociation / DataOutputAssociation
|
|
|
|
if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
|
|
|
|
side === 'target' && type === 'bpmn:DataInputAssociation') {
|
|
|
|
|
|
|
|
refSemantic = semantic.$parent;
|
2014-07-23 16:53:33 +00:00
|
|
|
}
|
|
|
|
|
2014-10-31 14:05:16 +00:00
|
|
|
element = refSemantic && this._getElement(refSemantic);
|
2014-07-23 16:53:33 +00:00
|
|
|
|
|
|
|
if (element) {
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
2014-10-31 14:05:16 +00:00
|
|
|
if (refSemantic) {
|
2015-07-15 06:50:21 +00:00
|
|
|
throw notYetDrawn(semantic, refSemantic, side + 'Ref');
|
2014-10-31 14:05:16 +00:00
|
|
|
} else {
|
|
|
|
throw new Error(elementToString(semantic) + '#' + side + 'Ref not specified');
|
|
|
|
}
|
2014-07-23 16:53:33 +00:00
|
|
|
};
|
|
|
|
|
2014-10-31 14:05:16 +00:00
|
|
|
BpmnImporter.prototype._getSource = function(semantic) {
|
|
|
|
return this._getEnd(semantic, 'source');
|
|
|
|
};
|
2014-07-23 16:53:33 +00:00
|
|
|
|
|
|
|
BpmnImporter.prototype._getTarget = function(semantic) {
|
2014-10-31 14:05:16 +00:00
|
|
|
return this._getEnd(semantic, 'target');
|
2014-07-23 16:53:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
BpmnImporter.prototype._getElement = function(semantic) {
|
2014-11-17 16:36:22 +00:00
|
|
|
return this._elementRegistry.get(semantic.id);
|
2014-12-22 10:44:44 +00:00
|
|
|
};
|