451 lines
9.1 KiB
JavaScript
451 lines
9.1 KiB
JavaScript
|
/**
|
||
|
* Copyright (c) 2006-2015, JGraph Ltd
|
||
|
* Copyright (c) 2006-2015, Gaudenz Alder
|
||
|
*/
|
||
|
/**
|
||
|
* Class: mxSwimlaneManager
|
||
|
*
|
||
|
* Manager for swimlanes and nested swimlanes that sets the size of newly added
|
||
|
* swimlanes to that of their siblings, and propagates changes to the size of a
|
||
|
* swimlane to its siblings, if <siblings> is true, and its ancestors, if
|
||
|
* <bubbling> is true.
|
||
|
*
|
||
|
* Constructor: mxSwimlaneManager
|
||
|
*
|
||
|
* Constructs a new swimlane manager for the given graph.
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* graph - Reference to the enclosing graph.
|
||
|
*/
|
||
|
function mxSwimlaneManager(graph, horizontal, addEnabled, resizeEnabled)
|
||
|
{
|
||
|
this.horizontal = (horizontal != null) ? horizontal : true;
|
||
|
this.addEnabled = (addEnabled != null) ? addEnabled : true;
|
||
|
this.resizeEnabled = (resizeEnabled != null) ? resizeEnabled : true;
|
||
|
|
||
|
this.addHandler = mxUtils.bind(this, function(sender, evt)
|
||
|
{
|
||
|
if (this.isEnabled() && this.isAddEnabled())
|
||
|
{
|
||
|
this.cellsAdded(evt.getProperty('cells'));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.resizeHandler = mxUtils.bind(this, function(sender, evt)
|
||
|
{
|
||
|
if (this.isEnabled() && this.isResizeEnabled())
|
||
|
{
|
||
|
this.cellsResized(evt.getProperty('cells'));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.setGraph(graph);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Extends mxEventSource.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype = new mxEventSource();
|
||
|
mxSwimlaneManager.prototype.constructor = mxSwimlaneManager;
|
||
|
|
||
|
/**
|
||
|
* Variable: graph
|
||
|
*
|
||
|
* Reference to the enclosing <mxGraph>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.graph = null;
|
||
|
|
||
|
/**
|
||
|
* Variable: enabled
|
||
|
*
|
||
|
* Specifies if event handling is enabled. Default is true.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.enabled = true;
|
||
|
|
||
|
/**
|
||
|
* Variable: horizontal
|
||
|
*
|
||
|
* Specifies the orientation of the swimlanes. Default is true.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.horizontal = true;
|
||
|
|
||
|
/**
|
||
|
* Variable: addEnabled
|
||
|
*
|
||
|
* Specifies if newly added cells should be resized to match the size of their
|
||
|
* existing siblings. Default is true.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.addEnabled = true;
|
||
|
|
||
|
/**
|
||
|
* Variable: resizeEnabled
|
||
|
*
|
||
|
* Specifies if resizing of swimlanes should be handled. Default is true.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.resizeEnabled = true;
|
||
|
|
||
|
/**
|
||
|
* Variable: moveHandler
|
||
|
*
|
||
|
* Holds the function that handles the move event.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.addHandler = null;
|
||
|
|
||
|
/**
|
||
|
* Variable: moveHandler
|
||
|
*
|
||
|
* Holds the function that handles the move event.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.resizeHandler = null;
|
||
|
|
||
|
/**
|
||
|
* Function: isEnabled
|
||
|
*
|
||
|
* Returns true if events are handled. This implementation
|
||
|
* returns <enabled>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isEnabled = function()
|
||
|
{
|
||
|
return this.enabled;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: setEnabled
|
||
|
*
|
||
|
* Enables or disables event handling. This implementation
|
||
|
* updates <enabled>.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* enabled - Boolean that specifies the new enabled state.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.setEnabled = function(value)
|
||
|
{
|
||
|
this.enabled = value;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: isHorizontal
|
||
|
*
|
||
|
* Returns <horizontal>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isHorizontal = function()
|
||
|
{
|
||
|
return this.horizontal;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: setHorizontal
|
||
|
*
|
||
|
* Sets <horizontal>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.setHorizontal = function(value)
|
||
|
{
|
||
|
this.horizontal = value;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: isAddEnabled
|
||
|
*
|
||
|
* Returns <addEnabled>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isAddEnabled = function()
|
||
|
{
|
||
|
return this.addEnabled;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: setAddEnabled
|
||
|
*
|
||
|
* Sets <addEnabled>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.setAddEnabled = function(value)
|
||
|
{
|
||
|
this.addEnabled = value;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: isResizeEnabled
|
||
|
*
|
||
|
* Returns <resizeEnabled>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isResizeEnabled = function()
|
||
|
{
|
||
|
return this.resizeEnabled;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: setResizeEnabled
|
||
|
*
|
||
|
* Sets <resizeEnabled>.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.setResizeEnabled = function(value)
|
||
|
{
|
||
|
this.resizeEnabled = value;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: getGraph
|
||
|
*
|
||
|
* Returns the graph that this manager operates on.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.getGraph = function()
|
||
|
{
|
||
|
return this.graph;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: setGraph
|
||
|
*
|
||
|
* Sets the graph that the manager operates on.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.setGraph = function(graph)
|
||
|
{
|
||
|
if (this.graph != null)
|
||
|
{
|
||
|
this.graph.removeListener(this.addHandler);
|
||
|
this.graph.removeListener(this.resizeHandler);
|
||
|
}
|
||
|
|
||
|
this.graph = graph;
|
||
|
|
||
|
if (this.graph != null)
|
||
|
{
|
||
|
this.graph.addListener(mxEvent.ADD_CELLS, this.addHandler);
|
||
|
this.graph.addListener(mxEvent.CELLS_RESIZED, this.resizeHandler);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: isSwimlaneIgnored
|
||
|
*
|
||
|
* Returns true if the given swimlane should be ignored.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isSwimlaneIgnored = function(swimlane)
|
||
|
{
|
||
|
return !this.getGraph().isSwimlane(swimlane);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: isCellHorizontal
|
||
|
*
|
||
|
* Returns true if the given cell is horizontal. If the given cell is not a
|
||
|
* swimlane, then the global orientation is returned.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.isCellHorizontal = function(cell)
|
||
|
{
|
||
|
if (this.graph.isSwimlane(cell))
|
||
|
{
|
||
|
var style = this.graph.getCellStyle(cell);
|
||
|
|
||
|
return mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, 1) == 1;
|
||
|
}
|
||
|
|
||
|
return !this.isHorizontal();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: cellsAdded
|
||
|
*
|
||
|
* Called if any cells have been added.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* cell - Array of <mxCells> that have been added.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.cellsAdded = function(cells)
|
||
|
{
|
||
|
if (cells != null)
|
||
|
{
|
||
|
var model = this.getGraph().getModel();
|
||
|
|
||
|
model.beginUpdate();
|
||
|
try
|
||
|
{
|
||
|
for (var i = 0; i < cells.length; i++)
|
||
|
{
|
||
|
if (!this.isSwimlaneIgnored(cells[i]))
|
||
|
{
|
||
|
this.swimlaneAdded(cells[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
model.endUpdate();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: swimlaneAdded
|
||
|
*
|
||
|
* Updates the size of the given swimlane to match that of any existing
|
||
|
* siblings swimlanes.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* swimlane - <mxCell> that represents the new swimlane.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.swimlaneAdded = function(swimlane)
|
||
|
{
|
||
|
var model = this.getGraph().getModel();
|
||
|
var parent = model.getParent(swimlane);
|
||
|
var childCount = model.getChildCount(parent);
|
||
|
var geo = null;
|
||
|
|
||
|
// Finds the first valid sibling swimlane as reference
|
||
|
for (var i = 0; i < childCount; i++)
|
||
|
{
|
||
|
var child = model.getChildAt(parent, i);
|
||
|
|
||
|
if (child != swimlane && !this.isSwimlaneIgnored(child))
|
||
|
{
|
||
|
geo = model.getGeometry(child);
|
||
|
|
||
|
if (geo != null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Applies the size of the refernece to the newly added swimlane
|
||
|
if (geo != null)
|
||
|
{
|
||
|
var parentHorizontal = (parent != null) ? this.isCellHorizontal(parent) : this.horizontal;
|
||
|
this.resizeSwimlane(swimlane, geo.width, geo.height, parentHorizontal);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: cellsResized
|
||
|
*
|
||
|
* Called if any cells have been resizes. Calls <swimlaneResized> for all
|
||
|
* swimlanes where <isSwimlaneIgnored> returns false.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* cells - Array of <mxCells> whose size was changed.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.cellsResized = function(cells)
|
||
|
{
|
||
|
if (cells != null)
|
||
|
{
|
||
|
var model = this.getGraph().getModel();
|
||
|
|
||
|
model.beginUpdate();
|
||
|
try
|
||
|
{
|
||
|
// Finds the top-level swimlanes and adds offsets
|
||
|
for (var i = 0; i < cells.length; i++)
|
||
|
{
|
||
|
if (!this.isSwimlaneIgnored(cells[i]))
|
||
|
{
|
||
|
var geo = model.getGeometry(cells[i]);
|
||
|
|
||
|
if (geo != null)
|
||
|
{
|
||
|
var size = new mxRectangle(0, 0, geo.width, geo.height);
|
||
|
var top = cells[i];
|
||
|
var current = top;
|
||
|
|
||
|
while (current != null)
|
||
|
{
|
||
|
top = current;
|
||
|
current = model.getParent(current);
|
||
|
var tmp = (this.graph.isSwimlane(current)) ?
|
||
|
this.graph.getStartSize(current) :
|
||
|
new mxRectangle();
|
||
|
size.width += tmp.width;
|
||
|
size.height += tmp.height;
|
||
|
}
|
||
|
|
||
|
var parentHorizontal = (current != null) ? this.isCellHorizontal(current) : this.horizontal;
|
||
|
this.resizeSwimlane(top, size.width, size.height, parentHorizontal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
model.endUpdate();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: resizeSwimlane
|
||
|
*
|
||
|
* Called from <cellsResized> for all swimlanes that are not ignored to update
|
||
|
* the size of the siblings and the size of the parent swimlanes, recursively,
|
||
|
* if <bubbling> is true.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* swimlane - <mxCell> whose size has changed.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.resizeSwimlane = function(swimlane, w, h, parentHorizontal)
|
||
|
{
|
||
|
var model = this.getGraph().getModel();
|
||
|
|
||
|
model.beginUpdate();
|
||
|
try
|
||
|
{
|
||
|
var horizontal = this.isCellHorizontal(swimlane);
|
||
|
|
||
|
if (!this.isSwimlaneIgnored(swimlane))
|
||
|
{
|
||
|
var geo = model.getGeometry(swimlane);
|
||
|
|
||
|
if (geo != null)
|
||
|
{
|
||
|
if ((parentHorizontal && geo.height != h) || (!parentHorizontal && geo.width != w))
|
||
|
{
|
||
|
geo = geo.clone();
|
||
|
|
||
|
if (parentHorizontal)
|
||
|
{
|
||
|
geo.height = h;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
geo.width = w;
|
||
|
}
|
||
|
|
||
|
model.setGeometry(swimlane, geo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var tmp = (this.graph.isSwimlane(swimlane)) ?
|
||
|
this.graph.getStartSize(swimlane) :
|
||
|
new mxRectangle();
|
||
|
w -= tmp.width;
|
||
|
h -= tmp.height;
|
||
|
|
||
|
var childCount = model.getChildCount(swimlane);
|
||
|
|
||
|
for (var i = 0; i < childCount; i++)
|
||
|
{
|
||
|
var child = model.getChildAt(swimlane, i);
|
||
|
this.resizeSwimlane(child, w, h, horizontal);
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
model.endUpdate();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Function: destroy
|
||
|
*
|
||
|
* Removes all handlers from the <graph> and deletes the reference to it.
|
||
|
*/
|
||
|
mxSwimlaneManager.prototype.destroy = function()
|
||
|
{
|
||
|
this.setGraph(null);
|
||
|
};
|