From d520574d1ab53064fcb8c49845a86b075afff494 Mon Sep 17 00:00:00 2001 From: Nico Rehwaldt Date: Tue, 11 Aug 2015 11:53:24 +0200 Subject: [PATCH] feat(modeling): wire lanes in BPMN 2.0 xml Related to #316 --- lib/features/modeling/BpmnUpdater.js | 59 ++++- .../features/modeling/lanes/CreateLaneSpec.js | 218 ++++++++++++++++++ .../features/modeling/lanes/nested-lane.bpmn | 72 ++++++ .../spec/features/modeling/lanes/no-lane.bpmn | 55 +++++ 4 files changed, 402 insertions(+), 2 deletions(-) create mode 100644 test/spec/features/modeling/lanes/CreateLaneSpec.js create mode 100644 test/spec/features/modeling/lanes/nested-lane.bpmn create mode 100644 test/spec/features/modeling/lanes/no-lane.bpmn 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