org.jbpm.designer.public.js.Plugins.bpelLayout.js Maven / Gradle / Ivy
/**
* Copyright (c) 2008
* Zhen Peng
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
if(!ORYX.Plugins)
ORYX.Plugins = new Object();
ORYX.Plugins.BPELLayouting = Clazz.extend({
facade: undefined,
isEnabled : undefined,
/**
* Constructor
* @param {Object} Facade: The Facade of the Editor
*/
construct: function(facade) {
this.facade = facade;
this.isEnabled = true;
this.facade.offer({
'name':ORYX.I18N.BPELSupport.enable,
'functionality': this.enableBpelLayout.bind(this),
'group': ORYX.I18N.BPELLayout.group,
'icon': ORYX.BASE_FILE_PATH + "images/bpel_layout_enable.png",
'description': ORYX.I18N.BPELLayout.enDesc,
'index': 0,
'minShape': 0,
'maxShape': 0,
'isEnabled': function(){ return !(this.isEnabled)}.bind(this)
});
this.facade.offer({
'name':ORYX.I18N.BPELSupport.disable,
'functionality': this.disableBpelLayout.bind(this),
'group': ORYX.I18N.BPELLayout.group,
'icon': ORYX.BASE_FILE_PATH + "images/bpel_layout_disable.png",
'description': ORYX.I18N.BPELLayout.disDesc,
'index': 1,
'minShape': 0,
'maxShape': 0,
'isEnabled': function(){ return this.isEnabled}.bind(this)
});
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT_BPEL, this.handleLayoutEvent.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL, this.handleLayoutVerticalEvent.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL, this.handleLayoutHorizontalEvent.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD, this.handleSingleChildLayoutEvent.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE, this.handleAutoResizeLayoutEvent.bind(this));
},
/**************************** plug-in control ****************************/
disableBpelLayout : function(){
this.isEnabled = false;
},
enableBpelLayout : function(){
this.isEnabled = true;
this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_LOADING_ENABLE,text: 'Auto Layouting...'});
//adjust all immediate child nodes(grand-children are adjusted recursively)
nodes = this.facade.getCanvas().getChildNodes();
for (var i = 0; i < nodes.size(); i++) {
node = nodes[i];
if (node.getStencil().id() == node.getStencil().namespace() + "process"){
this._adjust_node(node);
}
}
this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_LOADING_DISABLE});
},
_adjust_node : function (node){
// handle children first
// that means, the innermost children should be at first arranged,
var nodes = node.getChildNodes();
for (var i = 0; i < nodes.size(); i++) {
this._adjust_node(nodes[i]);
};
// handle the current node
this._handleLayoutEventAdapter (node);
//alert (node.getStencil().id());
},
_handleLayoutEventAdapter : function(node){
if (node.getStencil().id() == node.getStencil().namespace() + "process"
|| node.getStencil().id() == node.getStencil().namespace() + "invoke"
|| node.getStencil().id() == node.getStencil().namespace() + "scope"){
this._handleLayoutEvent (node);
} else if (node.getStencil().id() == node.getStencil().namespace() + "assign"
|| node.getStencil().id() == node.getStencil().namespace() + "eventHandlers"
|| node.getStencil().id() == node.getStencil().namespace() + "faultHandlers"
|| node.getStencil().id() == node.getStencil().namespace() + "compensationHandler"
|| node.getStencil().id() == node.getStencil().namespace() + "terminationHandler"){
this._handleLayoutVerticalEvent (node);
} else if (node.getStencil().id() == node.getStencil().namespace() + "if"
|| node.getStencil().id() == node.getStencil().namespace() + "sequence"
|| node.getStencil().id() == node.getStencil().namespace() + "pick"){
this._handleLayoutHorizontalEvent (node);
} else if (node.getStencil().id() == node.getStencil().namespace() + "onMessage"
|| node.getStencil().id() == node.getStencil().namespace() + "if_branch"
|| node.getStencil().id() == node.getStencil().namespace() + "else_branch"
|| node.getStencil().id() == node.getStencil().namespace() + "while"
|| node.getStencil().id() == node.getStencil().namespace() + "repeatUntil"
|| node.getStencil().id() == node.getStencil().namespace() + "forEach"
|| node.getStencil().id() == node.getStencil().namespace() + "onAlarm"
|| node.getStencil().id() == node.getStencil().namespace() + "onEvent"
|| node.getStencil().id() == node.getStencil().namespace() + "catch"
|| node.getStencil().id() == node.getStencil().namespace() + "catchAll"){
this._handleSingleChildLayoutEvent (node);
} else if (node.getStencil().id() == node.getStencil().namespace() + "flow"){
this._handleAutoResizeLayoutEvent (node);
} else {
// other shapes cannot contain any children shapes.
return;
}
},
/***************************** Event Handler *****************************/
handleLayoutEvent: function(event) {
this._handleLayoutEvent (event.shape);
},
handleLayoutVerticalEvent: function(event) {
this._handleLayoutVerticalEvent (event.shape);
},
handleLayoutHorizontalEvent: function(event) {
this._handleLayoutHorizontalEvent (event.shape);
},
handleSingleChildLayoutEvent: function(event) {
this._handleSingleChildLayoutEvent (event.shape);
},
handleAutoResizeLayoutEvent: function(event) {
this._handleAutoResizeLayoutEvent (event.shape);
},
/************************* Auto Layout Processes ****************************/
/**
* realize special BPEL layouting:
* main activity: placed left,
* Handler: placed right.
*/
_handleLayoutEvent: function(shape) {
if (this.isEnabled == false) {
return;
}
var elements = shape.getChildShapes(false);
// if Autolayout is not required, do nothing.
if (!this._requiredAutoLayout (shape)){
return;
};
// If there are no elements
if(!elements || elements.length == 0) {
this._resetBounds(shape);
this._update(shape);
return;
};
var eventHandlers = elements.find(function(node) {
return (node.getStencil().id() == node.getStencil().namespace() + "eventHandlers");
});
var faultHandlers = elements.find(function(node) {
return (node.getStencil().id() == node.getStencil().namespace() + "faultHandlers");
});
var compensationHandler = elements.find(function(node) {
return (node.getStencil().id() == node.getStencil().namespace() + "compensationHandler");
});
var terminationHandler = elements.find(function(node) {
return (node.getStencil().id() == node.getStencil().namespace() + "terminationHandler");
});
var otherElements = elements.findAll(function(node){
return (node !== eventHandlers && node !== faultHandlers
&& node !== compensationHandler && node !== terminationHandler)
});
var nextLeftBound = 30;
var nextUpperBound = 30;
// handle Activity
if (otherElements){
// Sort top-down
otherElements = otherElements.sortBy(function(element){
return element.bounds.upperLeft().y;
});
// move some certain elements to the last child position
// if it "true" returns, that means, the arrangement of elements
// is changed, we should sort all elements again
if (this._moveSomeElementToLastPosition(otherElements)){
// Sort again
otherElements = otherElements.sortBy(function(element){
return element.bounds.upperLeft().y;
});
}
var lastUpperYPosition = 0;
var elementWidth;
var maxElementWidth = 0;
// Arrange shapes like Layout-Vertical
otherElements.each (function(element){
var ul = element.bounds.upperLeft();
var oldUlY = ul.y;
ul.y = lastUpperYPosition + 30;
lastUpperYPosition = ul.y + element.bounds.height();
if (ul.y != oldUlY) {
element.bounds.moveTo(30, ul.y);
};
elementWidth = element.bounds.width();
if (elementWidth > maxElementWidth){
maxElementWidth = elementWidth;
}
});
nextLeftBound = 30 + maxElementWidth + 30;
}
var width;
var maxWidth = 0;
// handle EventHanlders
if (eventHandlers){
eventHandlers.bounds.moveTo(nextLeftBound, nextUpperBound);
nextUpperBound = eventHandlers.bounds.lowerRight().y + 10;
// record maximal width
width = this._getRightestBoundOfAllChildren(eventHandlers)+ 30;
if (width > maxWidth){
maxWidth = width;
}
}
// handle FaultHandlers
if (faultHandlers){
faultHandlers.bounds.moveTo(nextLeftBound, nextUpperBound);
nextUpperBound = faultHandlers.bounds.lowerRight().y + 10;
// record maximal width
width = this._getRightestBoundOfAllChildren(faultHandlers)+ 30;
if (width > maxWidth){
maxWidth = width;
}
}
// handle CompensationHandler
if (compensationHandler){
compensationHandler.bounds.moveTo(nextLeftBound, nextUpperBound);
nextUpperBound = compensationHandler.bounds.lowerRight().y + 10;
// record maximal width
width = this._getRightestBoundOfAllChildren(compensationHandler)+ 30;
if (width > maxWidth){
maxWidth = width;
}
}
// handle TerminationHandler
if (terminationHandler){
terminationHandler.bounds.moveTo(nextLeftBound, nextUpperBound);
// record maximal width
width = this._getRightestBoundOfAllChildren(terminationHandler)+ 30;
if (width > maxWidth){
maxWidth = width;
}
}
// resize all the handlers with the same width
if (width > 0){
var ul;
var lr;
if (eventHandlers){
width = eventHandlers.bounds.width();
if (width !== maxWidth){
ul = eventHandlers.bounds.upperLeft();
lr = eventHandlers.bounds.lowerRight();
eventHandlers.bounds.set(ul.x, ul.y, ul.x + maxWidth, lr.y);
//eventHandlers._changed();
}
}
if (faultHandlers){
width = faultHandlers.bounds.width();
if (width !== maxWidth){
ul = faultHandlers.bounds.upperLeft();
lr = faultHandlers.bounds.lowerRight();
faultHandlers.bounds.set(ul.x, ul.y, ul.x + maxWidth, lr.y);
//faultHandlers._changed();
}
}
if (compensationHandler){
width = compensationHandler.bounds.width();
if (width !== maxWidth){
ul = compensationHandler.bounds.upperLeft();
lr = compensationHandler.bounds.lowerRight();
compensationHandler.bounds.set(ul.x, ul.y, ul.x + maxWidth, lr.y);
//compensationHandler._changed();
}
}
if (terminationHandler){
width = terminationHandler.bounds.width();
if (width !== maxWidth){
ul = terminationHandler.bounds.upperLeft();
lr = terminationHandler.bounds.lowerRight();
terminationHandler.bounds.set(ul.x, ul.y, ul.x + maxWidth, lr.y);
//terminationHandler._changed();
}
}
}
this._autoResizeLayout(shape);
this._update(shape);
return;
},
_getRightestBoundOfAllChildren : function(shape){
var elements = shape.getChildShapes(false);
// If there are no elements
if(!elements || elements.length == 0) {
// 160 is the default width of hanlders
return 130;
};
// Sort left-right
elements = elements.sortBy(function(element){
return element.bounds.lowerRight().x;
});
return elements.last().bounds.lowerRight().x;
},
_handleLayoutVerticalEvent: function(shape) {
if (this.isEnabled == false) {
return;
}
var elements = shape.getChildShapes(false);
// if Autolayout is not required, do nothing.
if (!this._requiredAutoLayout (shape)){
return;
};
// If there are no elements
if(!elements || elements.length == 0) {
this._resetBounds(shape);
return;
};
// Sort top-down
elements = elements.sortBy(function(element){
return element.bounds.upperLeft().y;
});
// move some certain elements to the last child position
// if it "true" returns, that means, the arrangement of elements
// is changed, we should sort all elements again
if (this._moveSomeElementToLastPosition(elements)){
// Sort again
elements = elements.sortBy(function(element){
return element.bounds.upperLeft().y;
});
}
var lastUpperYPosition = 0;
// Arrange shapes
elements.each(function(element){
var ul = element.bounds.upperLeft();
var oldUlY = ul.y;
ul.y = lastUpperYPosition + 30;
lastUpperYPosition = ul.y + element.bounds.height();
if ((ul.y != oldUlY)) {
element.bounds.moveTo(30, ul.y);
}
});
this._autoResizeLayout(shape);
return;
},
_handleLayoutHorizontalEvent: function(shape) {
if (this.isEnabled == false) {
return;
}
var elements = shape.getChildShapes(false);
// if Autolayout is not required, do nothing.
if (!this._requiredAutoLayout (shape)){
return;
};
// If there are no elements
if(!elements || elements.length == 0) {
this._resetBounds(shape);
return;
};
// Sort left-right
elements = elements.sortBy(function(element){
return element.bounds.upperLeft().x;
});
// move some certain elements to the last child position
// if it "true" returns, that means, the arrangement of elements
// is changed, we should sort all elements again
if (this._moveSomeElementToLastPosition(elements)){
// Sort again
elements = elements.sortBy(function(element){
return element.bounds.upperLeft().x;
});
}
var lastLeftXPosition = 0;
// Arrange shapes on rows (align left)
elements.each(function(element){
var ul = element.bounds.upperLeft();
var oldUlX = ul.x;
ul.x = lastLeftXPosition + 30;
lastLeftXPosition = ul.x + element.bounds.width();
if ((ul.x != oldUlX)) {
element.bounds.moveTo(ul.x, 30);
}
});
this._autoResizeLayout(shape);
return;
},
_handleSingleChildLayoutEvent: function(shape) {
if (this.isEnabled == false) {
return;
}
var elements = shape.getChildShapes(false);
// if Autolayout is not required, do nothing.
if (!this._requiredAutoLayout (shape)){
return;
};
// If there are no elements
if(!elements || elements.length == 0) {
this._resetBounds(shape);
return;
};
elements.first().bounds.moveTo(30, 30);
this._autoResizeLayout(shape);
return;
},
_handleAutoResizeLayoutEvent: function(shape) {
if (this.isEnabled == false) {
return;
};
var elements = shape.getChildShapes(false);
// if Autolayout is not required, do nothing.
if (!this._requiredAutoLayout (shape)){
return;
};
elements.each(function(element){
var ul = element.bounds.upperLeft();
if ((ul.x < 30)) {
element.bounds.moveTo(30, ul.y);
ul = element.bounds.upperLeft();
}
if ((ul.y < 30)) {
element.bounds.moveTo(ul.x, 30);
}
});
this._autoResizeLayout(shape);
},
/**
* Resizes the shape to the bounds of the child shapes
*/
_autoResizeLayout: function(shape) {
var elements = shape.getChildShapes(false);
if (elements.length > 0) {
elements = elements.sortBy(function(element){
return element.bounds.lowerRight().x;
});
var rightBound = elements.last().bounds.lowerRight().x;
elements = elements.sortBy(function(element){
return element.bounds.lowerRight().y;
});
var lowerBound = elements.last().bounds.lowerRight().y;
var ul = shape.bounds.upperLeft();
var lr = shape.bounds.lowerRight();
//handle "flow" specially.
if (shape.getStencil().id() ==shape.getStencil().namespace() + "flow"){
if (lr.x < ul.x + rightBound + 30){
shape.bounds.set(ul.x, ul.y, ul.x + rightBound + 30, lr.y);
lr.x = ul.x + rightBound + 30;
//shape._changed();
};
if (lr.y < ul.y + lowerBound + 30){
shape.bounds.set(ul.x, ul.y, lr.x, ul.y + lowerBound + 30);
//shape._changed();
};
} else {
if (lr.x != ul.x + rightBound + 30 || lr.y != ul.y + lowerBound + 30){
shape.bounds.set(ul.x, ul.y, ul.x + rightBound + 30, ul.y + lowerBound + 30);
//shape._changed();
};
};
};
return;
},
_resetBounds: function (shape) {
// all the shapes without children will be reseted
var ul = shape.bounds.upperLeft();
var lr = shape.bounds.lowerRight();
if (shape.getStencil().id() == shape.getStencil().namespace() + "process"){
if (shape.getStencil().namespace() == "http://b3mn.org/stencilset/bpel#"){
if (lr.x != ul.x + 600 || lr.y != ul.y + 500){
shape.bounds.set(ul.x, ul.y, ul.x + 600, ul.y + 500);
//shape._changed();
};
} else if (shape.getStencil().namespace() == "http://b3mn.org/stencilset/bpel4chor#"){
if (lr.x != ul.x + 690 || lr.y != ul.y + 200){
shape.bounds.set(ul.x, ul.y, ul.x + 690, ul.y + 200);
//shape._changed();
};
} else {
return;
}
} else if (shape.getStencil().id() == shape.getStencil().namespace() + "flow"){
if (lr.x != ul.x + 290 || lr.y != ul.y + 250){
shape.bounds.set(ul.x, ul.y, ul.x + 290, ul.y + 250);
//shape._changed();
};
} else if (this._isHandlers(shape)){
if (lr.x != ul.x + 160 || lr.y != ul.y + 80){
shape.bounds.set(ul.x, ul.y, ul.x + 160, ul.y + 80);
//shape._changed();
};
} else {
if (lr.x != ul.x + 100 || lr.y != ul.y + 80){
shape.bounds.set(ul.x, ul.y, ul.x + 100, ul.y + 80);
//shape._changed();
};
};
},
_isHandlers: function (shape) {
if (shape.getStencil().id() == shape.getStencil().namespace() + "eventHandlers"){
return true;
};
if (shape.getStencil().id() == shape.getStencil().namespace() + "faultHandlers"){
return true;
};
if (shape.getStencil().id() == shape.getStencil().namespace() + "compensationHandler"){
return true;
};
if (shape.getStencil().id() == shape.getStencil().namespace() + "terminationHandler"){
return true;
};
return false;
},
_requiredAutoLayout: function(shape) {
var key = "oryx-autolayout";
var autolayout = shape.properties[key];
if (autolayout == null){
return true;
};
if (autolayout){
return true;
};
return false;
},
/**
* find a element with the role "lastChild", that means, this shape should be
* the last child of their parent, e.g.: "else" in "if-block". then move these elements
* to the last position of the set.
*
*
* @param {} elements : the set of all elements
* @pre all the elements in set are already once arranged, so we just put the
* "lastChild" after the current last one.
* @return if the arrangement of elements is changed.
*/
_moveSomeElementToLastPosition: function (elements){
var lastChild = elements.find(function(node) {
return (Array.indexOf(node.getStencil().roles(), node.getStencil().namespace() + "lastChild")>= 0);
});
// if there are not such element or it's already the last child,
// do nothing.
if (!lastChild || lastChild == elements.last()){
return false;
}
// move it after the current last child
ulOfCurrentLastChild = elements.last().bounds.upperLeft();
lastChild.bounds.moveTo(ulOfCurrentLastChild.x + 1, ulOfCurrentLastChild.y + 1);
return true;
},
_update : function(shape){
// update the canvas only if the current node is "process", with this we can
// make sure that, each time just once update after all the nodes are arranged
// and we must check, whether the node "process" changed is, if not, don't update,
// otherwise, an endless loop may occur, if there are more than three nesting level
// in a shape.
if (shape.getStencil().id() == shape.getStencil().namespace() + "process"
&& shape.isChanged){
// this.facade.getCanvas().update();
}
}
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy