feat(modeling): add data objects

Closes #344
This commit is contained in:
pedesen 2015-10-06 12:33:21 +02:00 committed by Ricardo Matias
parent 3f6a7d5621
commit 08c2ebc78f
19 changed files with 860 additions and 81 deletions

View File

@ -183,6 +183,20 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
});
}
if (is(bpmnElement, 'bpmn:DataObjectReference')) {
assign(actions, {
'connect': {
group: 'connect',
className: 'icon-connection-multi',
title: 'Connect using DataInputAssociation',
action: {
click: startConnect,
dragstart: startConnect
}
}
});
}
// Delete Element Entry
assign(actions, {
'delete': {

View File

@ -16,6 +16,7 @@ BpmnFactory.prototype._needsId = function(element) {
return element.$instanceOf('bpmn:RootElement') ||
element.$instanceOf('bpmn:FlowElement') ||
element.$instanceOf('bpmn:MessageFlow') ||
element.$instanceOf('bpmn:DataAssociation') ||
element.$instanceOf('bpmn:Artifact') ||
element.$instanceOf('bpmn:Participant') ||
element.$instanceOf('bpmn:Lane') ||

View File

@ -276,8 +276,28 @@ BpmnUpdater.prototype.updateParent = function(element, oldParent) {
this.updateFlowNodeRefs(businessObject, parentBusinessObject, oldParent && oldParent.businessObject);
}
if (is(element, 'bpmn:DataOutputAssociation')) {
if (element.source) {
parentBusinessObject = element.source.businessObject;
} else {
parentBusinessObject = null;
}
}
if (is(element, 'bpmn:DataInputAssociation')) {
if (element.target) {
parentBusinessObject = element.target.businessObject;
} else {
parentBusinessObject = null;
}
}
this.updateSemanticParent(businessObject, parentBusinessObject);
if (is(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
}
this.updateDiParent(businessObject.di, parentDi);
};
@ -462,6 +482,14 @@ BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent)
process.$parent = definitions;
}
}
} else
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
containment = 'dataOutputAssociations';
} else
if (is(businessObject, 'bpmn:DataInputAssociation')) {
containment = 'dataInputAssociations';
}
if (!containment) {
@ -500,28 +528,48 @@ BpmnUpdater.prototype.updateConnection = function(context) {
newSource = getBusinessObject(connection.source),
newTarget = getBusinessObject(connection.target);
var inverseSet = is(businessObject, 'bpmn:SequenceFlow');
if (!is(businessObject, 'bpmn:DataAssociation')) {
if (businessObject.sourceRef !== newSource) {
if (inverseSet) {
Collections.remove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject);
var inverseSet = is(businessObject, 'bpmn:SequenceFlow');
if (newSource && newSource.get('outgoing')) {
newSource.get('outgoing').push(businessObject);
if (businessObject.sourceRef !== newSource) {
if (inverseSet) {
Collections.remove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject);
if (newSource && newSource.get('outgoing')) {
newSource.get('outgoing').push(businessObject);
}
}
businessObject.sourceRef = newSource;
}
businessObject.sourceRef = newSource;
}
if (businessObject.targetRef !== newTarget) {
if (inverseSet) {
Collections.remove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject);
if (businessObject.targetRef !== newTarget) {
if (inverseSet) {
Collections.remove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject);
if (newTarget && newTarget.get('incoming')) {
newTarget.get('incoming').push(businessObject);
if (newTarget && newTarget.get('incoming')) {
newTarget.get('incoming').push(businessObject);
}
}
}
businessObject.targetRef = newTarget;
}
} else
if (is(businessObject, 'bpmn:DataInputAssociation')) {
// handle obnoxious isMany sourceRef
businessObject.get('sourceRef')[0] = newSource;
// targetRef = new parent
this.updateSemanticParent(businessObject, newTarget);
} else
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
// sourceRef = new parent
this.updateSemanticParent(businessObject, newSource);
// targetRef = new target
businessObject.targetRef = newTarget;
}

View File

@ -132,6 +132,10 @@ ElementFactory.prototype._getDefaultSize = function(semantic) {
return { width: 400, height: 100 };
}
if (semantic.$instanceOf('bpmn:DataObjectReference')) {
return { width: 36, height: 50 };
}
return { width: 100, height: 80 };
};

View File

@ -52,20 +52,7 @@ Modeling.prototype.connect = function(source, target, attrs) {
var bpmnRules = this._bpmnRules;
if (!attrs) {
if (bpmnRules.canConnectMessageFlow(source, target)) {
attrs = {
type: 'bpmn:MessageFlow'
};
} else
if (bpmnRules.canConnectSequenceFlow(source, target)) {
attrs = {
type: 'bpmn:SequenceFlow'
};
} else {
attrs = {
type: 'bpmn:Association'
};
}
attrs = bpmnRules.canConnect(source, target) || { type: 'bpmn:Association' };
}
return this.createConnection(source, target, attrs, source.parent);

View File

@ -0,0 +1,37 @@
'use strict';
var inherits = require('inherits');
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
var is = require('../../../util/ModelUtil').is;
/**
* BPMN specific create data object behavior
*/
function CreateDataObjectBehavior(eventBus, bpmnFactory, moddle) {
CommandInterceptor.call(this, eventBus);
this.preExecute('shape.create', function(event) {
var context = event.context,
shape = context.shape;
if(is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
// create a DataObject every time a DataObjectReference is created
var dataObjectShape = bpmnFactory.create('bpmn:DataObject');
// set the reference to the DataObject
shape.businessObject.dataObjectRef = dataObjectShape;
}
});
}
CreateDataObjectBehavior.$inject = [ 'eventBus', 'bpmnFactory', 'moddle' ];
inherits(CreateDataObjectBehavior, CommandInterceptor);
module.exports = CreateDataObjectBehavior;

View File

@ -2,6 +2,7 @@ module.exports = {
__init__: [
'appendBehavior',
'createBoundaryEventBehavior',
'createDataObjectBehavior',
'createLaneBehavior',
'createOnFlowBehavior',
'createParticipantBehavior',
@ -12,6 +13,7 @@ module.exports = {
],
appendBehavior: [ 'type', require('./AppendBehavior') ],
createBoundaryEventBehavior: [ 'type', require('./CreateBoundaryEventBehavior') ],
createDataObjectBehavior: [ 'type', require('./CreateDataObjectBehavior') ],
createLaneBehavior: [ 'type', require('./CreateLaneBehavior') ],
createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ],
createParticipantBehavior: [ 'type', require('./CreateParticipantBehavior') ],

View File

@ -102,6 +102,9 @@ PaletteProvider.prototype.getPaletteEntries = function(element) {
'create.task': createAction(
'bpmn:Task', 'activity', 'icon-task'
),
'create.data-object': createAction(
'bpmn:DataObjectReference', 'data-object', 'icon-data-object'
),
'create.subprocess-expanded': createAction(
'bpmn:SubProcess', 'activity', 'icon-subprocess-expanded', 'Create expanded SubProcess',
{ isExpanded: true }

View File

@ -96,6 +96,8 @@ BpmnRules.prototype.canConnectMessageFlow = canConnectMessageFlow;
BpmnRules.prototype.canConnectSequenceFlow = canConnectSequenceFlow;
BpmnRules.prototype.canConnectDataAssociation = canConnectDataAssociation;
BpmnRules.prototype.canConnectAssociation = canConnectAssociation;
BpmnRules.prototype.canMove = canMove;
@ -268,14 +270,24 @@ function canConnect(source, target, connection) {
return false;
}
if (canConnectMessageFlow(source, target) ||
canConnectSequenceFlow(source, target)) {
return true;
if (canConnectMessageFlow(source, target) && !is(connection, 'bpmn:DataAssociation')) {
return { type: 'bpmn:MessageFlow' };
}
if (canConnectSequenceFlow(source, target) && !is(connection, 'bpmn:DataAssociation')) {
return { type: 'bpmn:SequenceFlow' };
}
if (is(connection, 'bpmn:Association')) {
return canConnectAssociation(source, target);
var dataAssociation = canConnectDataAssociation(source, target);
if (dataAssociation && (!connection || is(connection, 'bpmn:DataAssociation'))) {
return dataAssociation;
}
if (is(connection, 'bpmn:Association') && !is(connection, 'bpmn:DataAssociation')) {
if (canConnectAssociation(source, target)) {
return { type: 'bpmn:Association' };
}
}
return false;
@ -556,6 +568,18 @@ function canConnectSequenceFlow(source, target) {
!(is(source, 'bpmn:EventBasedGateway') && !isEventBasedTarget(target));
}
function canConnectDataAssociation(source, target) {
if (is(source, 'bpmn:DataObjectReference') && is(target, 'bpmn:Activity')) {
return { type: 'bpmn:DataInputAssociation' };
}
if (is(target, 'bpmn:DataObjectReference') && is(source, 'bpmn:Activity')) {
return { type: 'bpmn:DataOutputAssociation' };
}
return false;
}
function canInsert(shape, flow, position) {
// return true if we can drop on the

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:task id="Task_1" />
<bpmn:dataObjectReference id="DataObjectReference_1" dataObjectRef="DataObject_1" />
<bpmn:dataObject id="DataObject_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="173" y="75" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1_di" bpmnElement="DataObjectReference_1">
<dc:Bounds x="205" y="226" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="178" y="276" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:subProcess id="SubProcess_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="SubProcess_1_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="297" y="58" width="350" height="200" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:task id="Task_1">
<bpmn:dataOutputAssociation id="DataOutputAssociation_1">
<bpmn:targetRef>DataObjectReference_1</bpmn:targetRef>
</bpmn:dataOutputAssociation>
</bpmn:task>
<bpmn:dataObjectReference id="DataObjectReference_1" dataObjectRef="DataObject_1" />
<bpmn:dataObject id="DataObject_1" />
<bpmn:task id="Task_2">
<bpmn:dataInputAssociation id="DataInputAssociation_1">
<bpmn:sourceRef>DataObjectReference_1</bpmn:sourceRef>
</bpmn:dataInputAssociation>
</bpmn:task>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="149" y="76" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1_di" bpmnElement="DataObjectReference_1">
<dc:Bounds x="337" y="91" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="310" y="141" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_2_di" bpmnElement="Task_2">
<dc:Bounds x="466" y="76" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="DataOutputAssociation_1_di" bpmnElement="DataOutputAssociation_1">
<di:waypoint xsi:type="dc:Point" x="249" y="116" />
<di:waypoint xsi:type="dc:Point" x="337" y="116" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_1_di" bpmnElement="DataInputAssociation_1">
<di:waypoint xsi:type="dc:Point" x="373" y="116" />
<di:waypoint xsi:type="dc:Point" x="466" y="116" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,300 @@
'use strict';
var TestHelper = require('../../../../TestHelper');
/* global bootstrapModeler, inject */
var is = require('../../../../../lib/util/ModelUtil').is;
var modelingModule = require('../../../../../lib/features/modeling'),
coreModule = require('../../../../../lib/core');
describe('features/modeling/behavior - data objects -', function() {
var testModules = [ coreModule, modelingModule ];
var rootShape;
describe('DataObjectReference', function() {
var processDiagramXML = require('./CreateDataObjectBehavior.data-object-reference.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var subProcess1;
beforeEach(inject(function(canvas, elementRegistry) {
subProcess1 = elementRegistry.get('SubProcess_1');
rootShape = canvas.getRootElement();
}));
it('should create the corresponding DataObject', inject(function(modeling) {
// when
var dataObjectRefShape = modeling.createShape({ type: 'bpmn:DataObjectReference' },
{ x: 220, y: 220 }, rootShape);
var dataObject = dataObjectRefShape.businessObject.dataObjectRef;
// then
expect(dataObject).to.exist;
expect(is(dataObject, 'bpmn:DataObject')).to.be.true;
expect(dataObject.id).to.exist;
}));
it('should have the right parents', inject(function(modeling) {
// when
var dataObjectRefShape1 = modeling.createShape({ type: 'bpmn:DataObjectReference' },
{ x: 220, y: 220 }, rootShape);
var dataObjectRefShape2 = modeling.createShape({ type: 'bpmn:DataObjectReference' },
{ x: 380, y: 220 }, subProcess1);
var dataObject1 = dataObjectRefShape1.businessObject.dataObjectRef;
var dataObject2 = dataObjectRefShape2.businessObject.dataObjectRef;
// then
expect(dataObject1.$parent.id).to.equal(rootShape.id);
expect(dataObjectRefShape1.parent.id).to.equal(rootShape.id);
expect(dataObject2.$parent.id).to.equal(subProcess1.id);
expect(dataObjectRefShape2.parent.id).to.equal(subProcess1.id);
}));
});
describe('create', function() {
var processDiagramXML = require('./CreateDataObjectBehavior.create-data-association.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var dataObjectRefShape1,
taskShape;
beforeEach(inject(function(canvas, elementRegistry) {
rootShape = canvas.getRootElement();
dataObjectRefShape1 = elementRegistry.get('DataObjectReference_1');
taskShape = elementRegistry.get('Task_1');
}));
describe('dataOutputAssociation', function() {
it('should execute', inject(function(modeling) {
// when
var outputAssociation = modeling.connect(taskShape, dataObjectRefShape1);
var dataOutputAssociations = taskShape.businessObject.get('dataOutputAssociations');
// then
expect(dataOutputAssociations[0].$parent).to.equal(taskShape.businessObject);
expect(dataOutputAssociations).to.include(outputAssociation.businessObject);
expect(taskShape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.connect(taskShape, dataObjectRefShape1);
commandStack.undo();
// then
expect(taskShape.businessObject.get('dataOutputAssociations')).to.be.empty;
expect(taskShape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
it('should redo', inject(function(modeling, commandStack) {
// when
var outputAssociation = modeling.connect(taskShape, dataObjectRefShape1);
commandStack.undo();
commandStack.redo();
var dataOutputAssociations = taskShape.businessObject.get('dataOutputAssociations');
// then
expect(dataOutputAssociations[0].$parent).to.equal(taskShape.businessObject);
expect(dataOutputAssociations).to.include(outputAssociation.businessObject);
expect(taskShape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
});
describe('dataInputAssociation', function() {
it('should execute', inject(function(modeling) {
// when
var inputAssociation = modeling.connect(dataObjectRefShape1, taskShape);
var dataInputAssociations = taskShape.businessObject.get('dataInputAssociations');
// then
expect(dataInputAssociations[0].$parent).to.equal(taskShape.businessObject);
expect(dataInputAssociations).to.include(inputAssociation.businessObject);
expect(taskShape.businessObject.get('dataOutputAssociations')).to.be.empty;
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.connect(dataObjectRefShape1, taskShape);
commandStack.undo();
// then
expect(taskShape.businessObject.get('dataOutputAssociations')).to.be.empty;
expect(taskShape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
it('should redo', inject(function(modeling, commandStack) {
// when
var inputAssociation = modeling.connect(dataObjectRefShape1, taskShape);
commandStack.undo();
commandStack.redo();
var dataInputAssociations = taskShape.businessObject.get('dataInputAssociations');
// then
expect(dataInputAssociations[0].$parent).to.equal(taskShape.businessObject);
expect(dataInputAssociations).to.include(inputAssociation.businessObject);
expect(taskShape.businessObject.get('dataOutputAssociations')).to.be.empty;
}));
});
});
describe('remove', function() {
var processDiagramXML = require('./CreateDataObjectBehavior.remove-data-association.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var task1Shape,
task2Shape,
outputAssociation,
inputAssociation;
beforeEach(inject(function(canvas, elementRegistry) {
rootShape = canvas.getRootElement();
task1Shape = elementRegistry.get('Task_1');
task2Shape = elementRegistry.get('Task_2');
outputAssociation = elementRegistry.get('DataOutputAssociation_1');
inputAssociation = elementRegistry.get('DataInputAssociation_1');
}));
describe('DataOutputAssociation', function() {
it('should execute', inject(function(modeling) {
// when
modeling.removeConnection(outputAssociation);
// then
expect(task1Shape.businessObject.get('dataOutputAssociations')).to.be.empty;
expect(task1Shape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.removeConnection(outputAssociation);
commandStack.undo();
var dataOutputAssociations = task1Shape.businessObject.get('dataOutputAssociations');
// then
expect(dataOutputAssociations[0].$parent).to.equal(task1Shape.businessObject);
expect(dataOutputAssociations).to.be.include(outputAssociation.businessObject);
expect(task1Shape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
it('should redo', inject(function(modeling, commandStack) {
// when
modeling.removeConnection(outputAssociation);
commandStack.undo();
commandStack.redo();
// then
expect(task1Shape.businessObject.get('dataOutputAssociations')).to.be.empty;
expect(task1Shape.businessObject.get('dataInputAssociations')).to.be.empty;
}));
});
describe('dataInputAssociation', function() {
it('should execute', inject(function(modeling) {
// when
modeling.removeConnection(inputAssociation);
// then
expect(task2Shape.businessObject.get('dataInputAssociations')).to.be.empty;
expect(task2Shape.businessObject.get('dataOutputAssociations')).to.be.empty;
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.removeConnection(inputAssociation);
commandStack.undo();
var dataInputAssociations = task2Shape.businessObject.get('dataInputAssociations');
// then
expect(dataInputAssociations[0].$parent).to.equal(task2Shape.businessObject);
expect(dataInputAssociations).to.include(inputAssociation.businessObject);
expect(task2Shape.businessObject.get('dataOutputAssociations')).to.be.empty;
}));
it('should redo', inject(function(modeling, commandStack) {
// when
modeling.removeConnection(inputAssociation);
commandStack.undo();
commandStack.redo();
// then
expect(task2Shape.businessObject.get('dataInputAssociations')).to.be.empty;
expect(task2Shape.businessObject.get('dataOutputAssociations')).to.be.empty;
}));
});
});
describe('reconnect', function() {
});
});

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:task id="Task_1" name="Task 1">
<bpmn:dataOutputAssociation id="DataOutputAssociation_1">
<bpmn:targetRef>DataObjectReference_1</bpmn:targetRef>
</bpmn:dataOutputAssociation>
</bpmn:task>
<bpmn:task id="Task_2" name="Task 2">
<bpmn:dataInputAssociation id="DataInputAssociation_1">
<bpmn:sourceRef>DataObjectReference_1</bpmn:sourceRef>
</bpmn:dataInputAssociation>
</bpmn:task>
<bpmn:dataObjectReference id="DataObjectReference_1" dataObjectRef="DataObject_1" />
<bpmn:dataObject id="DataObject_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="141" y="62" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_2_di" bpmnElement="Task_2">
<dc:Bounds x="382" y="62" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1_di" bpmnElement="DataObjectReference_1">
<dc:Bounds x="291" y="200" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="264" y="250" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="DataInputAssociation_1_di" bpmnElement="DataInputAssociation_1">
<di:waypoint xsi:type="dc:Point" x="327" y="207" />
<di:waypoint xsi:type="dc:Point" x="392" y="142" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataOutputAssociation_1_di" bpmnElement="DataOutputAssociation_1">
<di:waypoint xsi:type="dc:Point" x="229" y="142" />
<di:waypoint xsi:type="dc:Point" x="291" y="206" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,120 @@
'use strict';
var TestHelper = require('../../../../TestHelper');
/* global bootstrapModeler, inject */
var modelingModule = require('../../../../../lib/features/modeling'),
coreModule = require('../../../../../lib/core');
describe('features/modeling - reconnect connection', function() {
var testModules = [ coreModule, modelingModule ];
var processDiagramXML = require('./ReconnectConnection.data-association.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var task1Shape,
task2Shape,
dataInputAssociation,
dataOutputAssociation,
newWaypoints;
beforeEach(inject(function(elementRegistry) {
task1Shape = elementRegistry.get('Task_1');
task2Shape = elementRegistry.get('Task_2');
dataInputAssociation = elementRegistry.get('DataInputAssociation_1');
dataOutputAssociation = elementRegistry.get('DataOutputAssociation_1');
}));
describe('reconnect DataOutputAssociations', function() {
beforeEach(function(){
newWaypoints = [{ x: task2Shape.x, y: task2Shape.y+30 }, dataOutputAssociation.waypoints[1]];
});
it('should execute', inject(function(modeling){
// when
modeling.reconnectStart(dataOutputAssociation, task2Shape, newWaypoints);
// then
expect(task1Shape.businessObject.dataOutputAssociations).to.be.empty;
expect(task2Shape.businessObject.dataOutputAssociations).to.include(dataOutputAssociation.businessObject);
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.reconnectStart(dataOutputAssociation, task2Shape, newWaypoints);
commandStack.undo();
// then
expect(task1Shape.businessObject.dataOutputAssociations).to.include(dataOutputAssociation.businessObject);
expect(task2Shape.businessObject.dataOutputAssociations).to.be.empty;
}));
it('should redo', inject(function(modeling, commandStack) {
// when
modeling.reconnectStart(dataOutputAssociation, task2Shape, newWaypoints);
commandStack.undo();
commandStack.redo();
// then
expect(task1Shape.businessObject.dataOutputAssociations).to.be.empty;
expect(task2Shape.businessObject.dataOutputAssociations).to.include(dataOutputAssociation.businessObject);
}));
});
describe('reconnect DataInputAssociations', function() {
beforeEach(function(){
newWaypoints = [dataInputAssociation.waypoints[0], { x: task1Shape.x, y: task1Shape.y-30 }];
});
it('should execute', inject(function(modeling){
// when
modeling.reconnectEnd(dataInputAssociation, task1Shape, newWaypoints);
// then
expect(task1Shape.businessObject.dataInputAssociations).to.include(dataInputAssociation.businessObject);
expect(task2Shape.businessObject.dataInputAssociations).to.be.empty;
}));
it('should undo', inject(function(modeling, commandStack) {
// when
modeling.reconnectEnd(dataInputAssociation, task1Shape, newWaypoints);
commandStack.undo();
// then
expect(task1Shape.businessObject.dataInputAssociations).to.be.empty;
expect(task2Shape.businessObject.dataInputAssociations).to.include(dataInputAssociation.businessObject);
}));
it('should redo', inject(function(modeling, commandStack) {
// when
modeling.reconnectEnd(dataInputAssociation, task1Shape, newWaypoints);
commandStack.undo();
commandStack.redo();
// then
expect(task1Shape.businessObject.dataInputAssociations).to.include(dataInputAssociation.businessObject);
expect(task2Shape.businessObject.dataInputAssociations).to.be.empty;
}));
});
});

View File

@ -27,7 +27,7 @@ describe('features/palette', function() {
var entries = domQuery.all('.entry', paletteElement);
// then
expect(entries.length).to.equal(10);
expect(entries.length).to.equal(11);
}));
});

View File

@ -18,6 +18,8 @@
<bpmn2:endEvent id="EndEvent_in_SubProcess" />
</bpmn2:subProcess>
<bpmn2:endEvent id="EndEvent_None" />
<bpmn2:dataObjectReference id="DataObjectReference" dataObjectRef="DataObject" />
<bpmn2:dataObject id="DataObject" />
<bpmn2:textAnnotation id="TextAnnotation" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="_BPMNDiagram_2">
@ -67,6 +69,12 @@
<dc:Bounds x="534" y="209" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_di" bpmnElement="DataObjectReference">
<dc:Bounds x="601" y="162" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="574" y="212" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View File

@ -29,7 +29,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'Task', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -39,7 +40,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'TextAnnotation', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -49,7 +51,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('Task', 'IntermediateThrowEvent_Link', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -59,7 +62,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('IntermediateThrowEvent_Link', 'EndEvent_None', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -69,7 +73,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'IntermediateCatchEvent_Link', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -79,7 +84,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('IntermediateCatchEvent_Link', 'Task', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -89,6 +95,71 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanDrop('TextAnnotation', 'Process', true);
}));
it('connect DataObjectReference -> StartEvent_None', inject(function() {
expectCanConnect('DataObjectReference', 'StartEvent_None', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect StartEvent_None -> DataObjectReference', inject(function() {
expectCanConnect('StartEvent_None', 'DataObjectReference', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));
it('connect Task -> DataObjectReference', inject(function() {
expectCanConnect('Task', 'DataObjectReference', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: { type: 'bpmn:DataOutputAssociation' }
});
}));
it('connect DataObjectReference -> Task', inject(function() {
expectCanConnect('DataObjectReference', 'Task', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: { type: 'bpmn:DataInputAssociation' }
});
}));
it('connect SubProcess -> DataObjectReference', inject(function() {
expectCanConnect('SubProcess', 'DataObjectReference', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: { type: 'bpmn:DataOutputAssociation' }
});
}));
it('connect DataObjectReference -> SubProcess', inject(function() {
expectCanConnect('DataObjectReference', 'SubProcess', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: { type: 'bpmn:DataInputAssociation' }
});
}));
});
@ -104,7 +175,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'Task', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -114,7 +186,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'ExclusiveGateway', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -124,7 +197,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'SubProcess', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -134,7 +208,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'BoundaryEvent_on_Task', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -144,7 +219,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'StartEvent_None', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -154,7 +230,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'BoundaryEvent_on_SubProcess', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -164,7 +241,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_nested', 'Task', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -174,7 +252,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_nested', 'EndEvent_nested', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -184,7 +263,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'BoundaryEvent_in_OtherProcess', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -194,7 +274,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('BoundaryEvent_on_SubProcess', 'Task_in_OtherProcess', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -204,7 +285,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('Task_in_OtherProcess', 'BoundaryEvent_on_SubProcess', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -223,7 +305,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent_Message', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -233,7 +316,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent_Message', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -243,7 +327,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent_Signal', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -253,7 +338,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent_Condition', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -263,7 +349,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent_Timer', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -273,7 +360,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateCatchEvent', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -283,7 +371,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'IntermediateThrowEvent_Message', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -293,7 +382,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'ReceiveTask', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -303,7 +393,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'Task_None', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -313,7 +404,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'ParallelGateway', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -323,7 +415,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EventBasedGateway', 'ParallelGateway', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -342,7 +435,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'IntermediateThrowEvent_Message', {
sequenceFlow: true,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -352,7 +446,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -362,7 +457,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'StartEvent_None', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -373,7 +469,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'StartEvent_Timer', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -384,7 +481,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'StartEvent_Message', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -395,7 +493,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EndEvent_None', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -405,7 +504,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EndEvent_Cancel', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -415,7 +515,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EndEvent_Message', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -425,7 +526,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'EndEvent_None', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -435,7 +537,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('IntermediateThrowEvent_Message', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -445,7 +548,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('IntermediateThrowEvent_None', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -455,7 +559,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('IntermediateThrowEvent_Signal', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -465,7 +570,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'IntermediateThrowEvent_Message', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));
@ -475,7 +581,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('Task_in_SubProcess', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -485,7 +592,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('EndEvent_None_in_SubProcess', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -495,7 +603,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('OtherParticipant', 'Task_in_SubProcess', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -505,7 +614,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('Participant', 'OtherParticipant', {
sequenceFlow: false,
messageFlow: true,
association: true
association: true,
dataAssociation: false
});
}));
@ -515,7 +625,8 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanConnect('StartEvent_None', 'TextAnnotation_OtherParticipant', {
sequenceFlow: false,
messageFlow: false,
association: true
association: true,
dataAssociation: false
});
}));

View File

@ -26,6 +26,10 @@ function expectCanConnect(source, target, rules) {
if ('association' in rules) {
results.association = bpmnRules.canConnectAssociation(source, target);
}
if ('dataAssociation' in rules) {
results.dataAssociation = bpmnRules.canConnectDataAssociation(source, target);
}
});
expect(results).to.eql(rules);
@ -75,4 +79,4 @@ function expectCanMove(elements, target, rules) {
expect(results).to.eql(rules);
}
module.exports.expectCanMove = expectCanMove;
module.exports.expectCanMove = expectCanMove;