diff --git a/lib/features/modeling/BpmnUpdater.js b/lib/features/modeling/BpmnUpdater.js
index 54887592..e2b0536b 100644
--- a/lib/features/modeling/BpmnUpdater.js
+++ b/lib/features/modeling/BpmnUpdater.js
@@ -238,6 +238,41 @@ function getDefinitions(element) {
return element;
}
+BpmnUpdater.prototype.getLaneSet = function(container) {
+
+ var laneSet, laneSets;
+
+ // bpmn:Lane
+ if (is(container, 'bpmn:Lane')) {
+ laneSet = container.childLaneSet;
+
+ if (!laneSet) {
+ laneSet = this._bpmnFactory.create('bpmn:LaneSet');
+ container.childLaneSet = laneSet;
+ laneSet.$parent = container;
+ }
+
+ return laneSet;
+ }
+
+ // bpmn:Participant
+ if (is(container, 'bpmn:Participant')) {
+ container = container.processRef;
+ }
+
+ // bpmn:FlowElementsContainer
+ laneSets = container.get('laneSets');
+ laneSet = laneSets[0];
+
+ if (!laneSet) {
+ laneSet = this._bpmnFactory.create('bpmn:LaneSet');
+ laneSet.$parent = container;
+ laneSets.push(laneSet);
+ }
+
+ return laneSet;
+};
+
BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent) {
var containment;
@@ -246,10 +281,30 @@ BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent)
return;
}
+ if (is(businessObject, 'bpmn:Lane')) {
+
+ if (newParent) {
+ newParent = this.getLaneSet(newParent);
+ }
+
+ containment = 'lanes';
+ } else
+
if (is(businessObject, 'bpmn:FlowElement')) {
- if (newParent && is(newParent, 'bpmn:Participant')) {
- newParent = newParent.processRef;
+ if (newParent) {
+
+ if (is(newParent, 'bpmn:Participant')) {
+ newParent = newParent.processRef;
+ } else
+
+ if (is(newParent, 'bpmn:Lane')) {
+ do {
+ // unwrap Lane -> LaneSet -> (Lane | FlowElementsContainer)
+ newParent = newParent.$parent.$parent;
+ } while(is(newParent, 'bpmn:Lane'));
+
+ }
}
containment = 'flowElements';
diff --git a/test/spec/features/modeling/lanes/CreateLaneSpec.js b/test/spec/features/modeling/lanes/CreateLaneSpec.js
new file mode 100644
index 00000000..a462b432
--- /dev/null
+++ b/test/spec/features/modeling/lanes/CreateLaneSpec.js
@@ -0,0 +1,218 @@
+'use strict';
+
+var TestHelper = require('../../../../TestHelper');
+
+/* global bootstrapModeler, inject */
+
+
+var modelingModule = require('../../../../../lib/features/modeling'),
+ coreModule = require('../../../../../lib/core');
+
+
+describe('features/modeling - create lanes', function() {
+
+
+ describe('should add to participant', function() {
+
+ var diagramXML = require('./no-lane.bpmn');
+
+ var testModules = [ coreModule, modelingModule ];
+
+ beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
+
+
+ it('execute', inject(function(elementRegistry, modeling) {
+
+ // given
+ var participantShape = elementRegistry.get('Participant'),
+ participant = participantShape.businessObject,
+ bpmnProcess = participant.processRef;
+
+ // when
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, participantShape);
+
+ var lane = laneShape.businessObject;
+
+ // then
+ expect(laneShape).to.exist;
+ expect(lane).to.exist;
+
+
+ expect(bpmnProcess.laneSets).to.exist;
+
+ var laneSet = bpmnProcess.laneSets[0];
+
+ // expect correct bpmn containment for new laneSet
+ expect(laneSet.$parent).to.eql(bpmnProcess);
+
+ // expect correct bpmn containment for lane
+ expect(laneSet.lanes).to.contain(lane);
+ expect(lane.$parent).to.equal(laneSet);
+
+ // expect correct di wiring
+ expect(lane.di.$parent).to.eql(participant.di.$parent);
+ expect(lane.di.$parent.planeElement).to.include(lane.di);
+ }));
+
+
+ it('undo', inject(function(elementRegistry, commandStack, modeling) {
+
+ // given
+ var participantShape = elementRegistry.get('Participant'),
+ participant = participantShape.businessObject,
+ bpmnProcess = participant.processRef;
+
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, participantShape);
+
+ var lane = laneShape.businessObject;
+ var laneSet = lane.$parent;
+
+ // when
+ commandStack.undo();
+
+ // then
+ expect(lane.$parent).to.be.null;
+ expect(laneSet.lanes).not.to.contain(lane);
+
+ // lane sets remain initialized
+ expect(bpmnProcess.laneSets).to.exist;
+ expect(bpmnProcess.laneSets.length).to.eql(1);
+ }));
+
+
+ it('redo', inject(function(elementRegistry, commandStack, modeling) {
+
+ // given
+ var participantShape = elementRegistry.get('Participant'),
+ participant = participantShape.businessObject,
+ bpmnProcess = participant.processRef;
+
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, participantShape);
+
+ var lane = laneShape.businessObject;
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ expect(laneShape).to.exist;
+ expect(lane).to.exist;
+
+ expect(bpmnProcess.laneSets).to.exist;
+
+ var laneSet = bpmnProcess.laneSets[0];
+
+ // expect correct bpmn containment
+ expect(laneSet.lanes).to.contain(lane);
+ expect(lane.$parent).to.equal(laneSet);
+
+ // expect correct di wiring
+ expect(lane.di.$parent).to.eql(participant.di.$parent);
+ expect(lane.di.$parent.planeElement).to.include(lane.di);
+ }));
+
+ });
+
+
+ describe('should add to lane', function() {
+
+ var diagramXML = require('./nested-lane.bpmn');
+
+ var testModules = [ coreModule, modelingModule ];
+
+ beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
+
+
+ it('execute', inject(function(elementRegistry, modeling) {
+
+ // given
+ var parentLaneShape = elementRegistry.get('Lane'),
+ parentLane = parentLaneShape.businessObject;
+
+ // when
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, parentLaneShape);
+
+ var lane = laneShape.businessObject;
+
+ // then
+ expect(laneShape).to.exist;
+ expect(lane).to.exist;
+
+ var laneSet = parentLane.childLaneSet;
+
+ expect(laneSet).to.exist;
+
+ // expect correct bpmn containment for new laneSet
+ expect(laneSet.$parent).to.eql(parentLane);
+
+ // expect correct bpmn containment for lane
+ expect(laneSet.lanes).to.contain(lane);
+ expect(lane.$parent).to.equal(laneSet);
+
+ // expect correct di wiring
+ expect(lane.di.$parent).to.eql(parentLane.di.$parent);
+ expect(lane.di.$parent.planeElement).to.include(lane.di);
+ }));
+
+
+ it('undo', inject(function(elementRegistry, commandStack, modeling) {
+
+ // given
+ var parentLaneShape = elementRegistry.get('Lane'),
+ parentLane = parentLaneShape.businessObject;
+
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, parentLaneShape);
+
+ var lane = laneShape.businessObject;
+ var laneSet = lane.$parent;
+
+ // when
+ commandStack.undo();
+
+ // then
+ expect(lane.$parent).to.be.null;
+ expect(laneSet.lanes).not.to.contain(lane);
+
+ // childLaneSet sets remain initialized
+ expect(parentLane.childLaneSet).to.exist;
+ }));
+
+
+ it('redo', inject(function(elementRegistry, commandStack, modeling) {
+
+ // given
+ var parentLaneShape = elementRegistry.get('Lane'),
+ parentLane = parentLaneShape.businessObject;
+
+ var laneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, parentLaneShape);
+
+ var lane = laneShape.businessObject;
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ expect(laneShape).to.exist;
+ expect(lane).to.exist;
+
+ var laneSet = parentLane.childLaneSet;
+
+ expect(laneSet).to.exist;
+
+ // expect correct bpmn containment for new laneSet
+ expect(laneSet.$parent).to.eql(parentLane);
+
+ // expect correct bpmn containment for lane
+ expect(laneSet.lanes).to.contain(lane);
+ expect(lane.$parent).to.equal(laneSet);
+
+ // expect correct di wiring
+ expect(lane.di.$parent).to.eql(parentLane.di.$parent);
+ expect(lane.di.$parent.planeElement).to.include(lane.di);
+ }));
+
+ });
+
+});
diff --git a/test/spec/features/modeling/lanes/nested-lane.bpmn b/test/spec/features/modeling/lanes/nested-lane.bpmn
new file mode 100644
index 00000000..637eae8d
--- /dev/null
+++ b/test/spec/features/modeling/lanes/nested-lane.bpmn
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+ Boundary
+ Task_Boundary
+ Task
+
+
+
+
+
+ SequenceFlow_From_Boundary
+
+
+
+ SequenceFlow
+
+
+
+ SequenceFlow_From_Boundary
+ SequenceFlow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/spec/features/modeling/lanes/no-lane.bpmn b/test/spec/features/modeling/lanes/no-lane.bpmn
new file mode 100644
index 00000000..0e162735
--- /dev/null
+++ b/test/spec/features/modeling/lanes/no-lane.bpmn
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ SequenceFlow
+
+
+ SequenceFlow_From_Boundary
+
+
+ SequenceFlow_From_Boundary
+ SequenceFlow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file