summaryrefslogtreecommitdiff
path: root/src/js/model/mxGraphModel.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/model/mxGraphModel.js')
-rw-r--r--src/js/model/mxGraphModel.js2622
1 files changed, 0 insertions, 2622 deletions
diff --git a/src/js/model/mxGraphModel.js b/src/js/model/mxGraphModel.js
deleted file mode 100644
index c65c0e1..0000000
--- a/src/js/model/mxGraphModel.js
+++ /dev/null
@@ -1,2622 +0,0 @@
-/**
- * $Id: mxGraphModel.js,v 1.125 2012-04-16 10:48:43 david Exp $
- * Copyright (c) 2006-2010, JGraph Ltd
- */
-/**
- * Class: mxGraphModel
- *
- * Extends <mxEventSource> to implement a graph model. The graph model acts as
- * a wrapper around the cells which are in charge of storing the actual graph
- * datastructure. The model acts as a transactional wrapper with event
- * notification for all changes, whereas the cells contain the atomic
- * operations for updating the actual datastructure.
- *
- * Layers:
- *
- * The cell hierarchy in the model must have a top-level root cell which
- * contains the layers (typically one default layer), which in turn contain the
- * top-level cells of the layers. This means each cell is contained in a layer.
- * If no layers are required, then all new cells should be added to the default
- * layer.
- *
- * Layers are useful for hiding and showing groups of cells, or for placing
- * groups of cells on top of other cells in the display. To identify a layer,
- * the <isLayer> function is used. It returns true if the parent of the given
- * cell is the root of the model.
- *
- * Encoding the model:
- *
- * To encode a graph model, use the following code:
- *
- * (code)
- * var enc = new mxCodec();
- * var node = enc.encode(graph.getModel());
- * (end)
- *
- * This will create an XML node that contains all the model information.
- *
- * Encoding and decoding changes:
- *
- * For the encoding of changes, a graph model listener is required that encodes
- * each change from the given array of changes.
- *
- * (code)
- * model.addListener(mxEvent.CHANGE, function(sender, evt)
- * {
- * var changes = evt.getProperty('edit').changes;
- * var nodes = [];
- * var codec = new mxCodec();
- *
- * for (var i = 0; i < changes.length; i++)
- * {
- * nodes.push(codec.encode(changes[i]));
- * }
- * // do something with the nodes
- * });
- * (end)
- *
- * For the decoding and execution of changes, the codec needs a lookup function
- * that allows it to resolve cell IDs as follows:
- *
- * (code)
- * var codec = new mxCodec();
- * codec.lookup = function(id)
- * {
- * return model.getCell(id);
- * }
- * (end)
- *
- * For each encoded change (represented by a node), the following code can be
- * used to carry out the decoding and create a change object.
- *
- * (code)
- * var changes = [];
- * var change = codec.decode(node);
- * change.model = model;
- * change.execute();
- * changes.push(change);
- * (end)
- *
- * The changes can then be dispatched using the model as follows.
- *
- * (code)
- * var edit = new mxUndoableEdit(model, false);
- * edit.changes = changes;
- *
- * edit.notify = function()
- * {
- * edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
- * 'edit', edit, 'changes', edit.changes));
- * edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
- * 'edit', edit, 'changes', edit.changes));
- * }
- *
- * model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
- * model.fireEvent(new mxEventObject(mxEvent.CHANGE,
- * 'edit', edit, 'changes', changes));
- * (end)
- *
- * Event: mxEvent.CHANGE
- *
- * Fires when an undoable edit is dispatched. The <code>edit</code> property
- * contains the <mxUndoableEdit>. The <code>changes</code> property contains
- * the array of atomic changes inside the undoable edit. The changes property
- * is <strong>deprecated</strong>, please use edit.changes instead.
- *
- * Example:
- *
- * For finding newly inserted cells, the following code can be used:
- *
- * (code)
- * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
- * {
- * var changes = evt.getProperty('edit').changes;
- *
- * for (var i = 0; i < changes.length; i++)
- * {
- * var change = changes[i];
- *
- * if (change instanceof mxChildChange &&
- * change.change.previous == null)
- * {
- * graph.startEditingAtCell(change.child);
- * break;
- * }
- * }
- * });
- * (end)
- *
- *
- * Event: mxEvent.NOTIFY
- *
- * Same as <mxEvent.CHANGE>, this event can be used for classes that need to
- * implement a sync mechanism between this model and, say, a remote model. In
- * such a setup, only local changes should trigger a notify event and all
- * changes should trigger a change event.
- *
- * Event: mxEvent.EXECUTE
- *
- * Fires between begin- and endUpdate and after an atomic change was executed
- * in the model. The <code>change</code> property contains the atomic change
- * that was executed.
- *
- * Event: mxEvent.BEGIN_UPDATE
- *
- * Fires after the <updateLevel> was incremented in <beginUpdate>. This event
- * contains no properties.
- *
- * Event: mxEvent.END_UPDATE
- *
- * Fires after the <updateLevel> was decreased in <endUpdate> but before any
- * notification or change dispatching. The <code>edit</code> property contains
- * the <currentEdit>.
- *
- * Event: mxEvent.BEFORE_UNDO
- *
- * Fires before the change is dispatched after the update level has reached 0
- * in <endUpdate>. The <code>edit</code> property contains the <curreneEdit>.
- *
- * Event: mxEvent.UNDO
- *
- * Fires after the change was dispatched in <endUpdate>. The <code>edit</code>
- * property contains the <currentEdit>.
- *
- * Constructor: mxGraphModel
- *
- * Constructs a new graph model. If no root is specified then a new root
- * <mxCell> with a default layer is created.
- *
- * Parameters:
- *
- * root - <mxCell> that represents the root cell.
- */
-function mxGraphModel(root)
-{
- this.currentEdit = this.createUndoableEdit();
-
- if (root != null)
- {
- this.setRoot(root);
- }
- else
- {
- this.clear();
- }
-};
-
-/**
- * Extends mxEventSource.
- */
-mxGraphModel.prototype = new mxEventSource();
-mxGraphModel.prototype.constructor = mxGraphModel;
-
-/**
- * Variable: root
- *
- * Holds the root cell, which in turn contains the cells that represent the
- * layers of the diagram as child cells. That is, the actual elements of the
- * diagram are supposed to live in the third generation of cells and below.
- */
-mxGraphModel.prototype.root = null;
-
-/**
- * Variable: cells
- *
- * Maps from Ids to cells.
- */
-mxGraphModel.prototype.cells = null;
-
-/**
- * Variable: maintainEdgeParent
- *
- * Specifies if edges should automatically be moved into the nearest common
- * ancestor of their terminals. Default is true.
- */
-mxGraphModel.prototype.maintainEdgeParent = true;
-
-/**
- * Variable: createIds
- *
- * Specifies if the model should automatically create Ids for new cells.
- * Default is true.
- */
-mxGraphModel.prototype.createIds = true;
-
-/**
- * Variable: prefix
- *
- * Defines the prefix of new Ids. Default is an empty string.
- */
-mxGraphModel.prototype.prefix = '';
-
-/**
- * Variable: postfix
- *
- * Defines the postfix of new Ids. Default is an empty string.
- */
-mxGraphModel.prototype.postfix = '';
-
-/**
- * Variable: nextId
- *
- * Specifies the next Id to be created. Initial value is 0.
- */
-mxGraphModel.prototype.nextId = 0;
-
-/**
- * Variable: currentEdit
- *
- * Holds the changes for the current transaction. If the transaction is
- * closed then a new object is created for this variable using
- * <createUndoableEdit>.
- */
-mxGraphModel.prototype.currentEdit = null;
-
-/**
- * Variable: updateLevel
- *
- * Counter for the depth of nested transactions. Each call to <beginUpdate>
- * will increment this number and each call to <endUpdate> will decrement
- * it. When the counter reaches 0, the transaction is closed and the
- * respective events are fired. Initial value is 0.
- */
-mxGraphModel.prototype.updateLevel = 0;
-
-/**
- * Variable: endingUpdate
- *
- * True if the program flow is currently inside endUpdate.
- */
-mxGraphModel.prototype.endingUpdate = false;
-
-/**
- * Function: clear
- *
- * Sets a new root using <createRoot>.
- */
-mxGraphModel.prototype.clear = function()
-{
- this.setRoot(this.createRoot());
-};
-
-/**
- * Function: isCreateIds
- *
- * Returns <createIds>.
- */
-mxGraphModel.prototype.isCreateIds = function()
-{
- return this.createIds;
-};
-
-/**
- * Function: setCreateIds
- *
- * Sets <createIds>.
- */
-mxGraphModel.prototype.setCreateIds = function(value)
-{
- this.createIds = value;
-};
-
-/**
- * Function: createRoot
- *
- * Creates a new root cell with a default layer (child 0).
- */
-mxGraphModel.prototype.createRoot = function()
-{
- var cell = new mxCell();
- cell.insert(new mxCell());
-
- return cell;
-};
-
-/**
- * Function: getCell
- *
- * Returns the <mxCell> for the specified Id or null if no cell can be
- * found for the given Id.
- *
- * Parameters:
- *
- * id - A string representing the Id of the cell.
- */
-mxGraphModel.prototype.getCell = function(id)
-{
- return (this.cells != null) ? this.cells[id] : null;
-};
-
-/**
- * Function: filterCells
- *
- * Returns the cells from the given array where the fiven filter function
- * returns true.
- */
-mxGraphModel.prototype.filterCells = function(cells, filter)
-{
- var result = null;
-
- if (cells != null)
- {
- result = [];
-
- for (var i = 0; i < cells.length; i++)
- {
- if (filter(cells[i]))
- {
- result.push(cells[i]);
- }
- }
- }
-
- return result;
-};
-
-/**
- * Function: getDescendants
- *
- * Returns all descendants of the given cell and the cell itself in an array.
- *
- * Parameters:
- *
- * parent - <mxCell> whose descendants should be returned.
- */
-mxGraphModel.prototype.getDescendants = function(parent)
-{
- return this.filterDescendants(null, parent);
-};
-
-/**
- * Function: filterDescendants
- *
- * Visits all cells recursively and applies the specified filter function
- * to each cell. If the function returns true then the cell is added
- * to the resulting array. The parent and result paramters are optional.
- * If parent is not specified then the recursion starts at <root>.
- *
- * Example:
- * The following example extracts all vertices from a given model:
- * (code)
- * var filter = function(cell)
- * {
- * return model.isVertex(cell);
- * }
- * var vertices = model.filterDescendants(filter);
- * (code)
- *
- * Parameters:
- *
- * filter - JavaScript function that takes an <mxCell> as an argument
- * and returns a boolean.
- * parent - Optional <mxCell> that is used as the root of the recursion.
- */
-mxGraphModel.prototype.filterDescendants = function(filter, parent)
-{
- // Creates a new array for storing the result
- var result = [];
-
- // Recursion starts at the root of the model
- parent = parent || this.getRoot();
-
- // Checks if the filter returns true for the cell
- // and adds it to the result array
- if (filter == null || filter(parent))
- {
- result.push(parent);
- }
-
- // Visits the children of the cell
- var childCount = this.getChildCount(parent);
-
- for (var i = 0; i < childCount; i++)
- {
- var child = this.getChildAt(parent, i);
- result = result.concat(this.filterDescendants(filter, child));
- }
-
- return result;
-};
-
-/**
- * Function: getRoot
- *
- * Returns the root of the model or the topmost parent of the given cell.
- *
- * Parameters:
- *
- * cell - Optional <mxCell> that specifies the child.
- */
-mxGraphModel.prototype.getRoot = function(cell)
-{
- var root = cell || this.root;
-
- if (cell != null)
- {
- while (cell != null)
- {
- root = cell;
- cell = this.getParent(cell);
- }
- }
-
- return root;
-};
-
-/**
- * Function: setRoot
- *
- * Sets the <root> of the model using <mxRootChange> and adds the change to
- * the current transaction. This resets all datastructures in the model and
- * is the preferred way of clearing an existing model. Returns the new
- * root.
- *
- * Example:
- *
- * (code)
- * var root = new mxCell();
- * root.insert(new mxCell());
- * model.setRoot(root);
- * (end)
- *
- * Parameters:
- *
- * root - <mxCell> that specifies the new root.
- */
-mxGraphModel.prototype.setRoot = function(root)
-{
- this.execute(new mxRootChange(this, root));
-
- return root;
-};
-
-/**
- * Function: rootChanged
- *
- * Inner callback to change the root of the model and update the internal
- * datastructures, such as <cells> and <nextId>. Returns the previous root.
- *
- * Parameters:
- *
- * root - <mxCell> that specifies the new root.
- */
-mxGraphModel.prototype.rootChanged = function(root)
-{
- var oldRoot = this.root;
- this.root = root;
-
- // Resets counters and datastructures
- this.nextId = 0;
- this.cells = null;
- this.cellAdded(root);
-
- return oldRoot;
-};
-
-/**
- * Function: isRoot
- *
- * Returns true if the given cell is the root of the model and a non-null
- * value.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the possible root.
- */
-mxGraphModel.prototype.isRoot = function(cell)
-{
- return cell != null && this.root == cell;
-};
-
-/**
- * Function: isLayer
- *
- * Returns true if <isRoot> returns true for the parent of the given cell.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the possible layer.
- */
-mxGraphModel.prototype.isLayer = function(cell)
-{
- return this.isRoot(this.getParent(cell));
-};
-
-/**
- * Function: isAncestor
- *
- * Returns true if the given parent is an ancestor of the given child.
- *
- * Parameters:
- *
- * parent - <mxCell> that specifies the parent.
- * child - <mxCell> that specifies the child.
- */
-mxGraphModel.prototype.isAncestor = function(parent, child)
-{
- while (child != null && child != parent)
- {
- child = this.getParent(child);
- }
-
- return child == parent;
-};
-
-/**
- * Function: contains
- *
- * Returns true if the model contains the given <mxCell>.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell.
- */
-mxGraphModel.prototype.contains = function(cell)
-{
- return this.isAncestor(this.root, cell);
-};
-
-/**
- * Function: getParent
- *
- * Returns the parent of the given cell.
- *
- * Parameters:
- *
- * cell - <mxCell> whose parent should be returned.
- */
-mxGraphModel.prototype.getParent = function(cell)
-{
- return (cell != null) ? cell.getParent() : null;
-};
-
-/**
- * Function: add
- *
- * Adds the specified child to the parent at the given index using
- * <mxChildChange> and adds the change to the current transaction. If no
- * index is specified then the child is appended to the parent's array of
- * children. Returns the inserted child.
- *
- * Parameters:
- *
- * parent - <mxCell> that specifies the parent to contain the child.
- * child - <mxCell> that specifies the child to be inserted.
- * index - Optional integer that specifies the index of the child.
- */
-mxGraphModel.prototype.add = function(parent, child, index)
-{
- if (child != parent && parent != null && child != null)
- {
- // Appends the child if no index was specified
- if (index == null)
- {
- index = this.getChildCount(parent);
- }
-
- var parentChanged = parent != this.getParent(child);
- this.execute(new mxChildChange(this, parent, child, index));
-
- // Maintains the edges parents by moving the edges
- // into the nearest common ancestor of its
- // terminals
- if (this.maintainEdgeParent && parentChanged)
- {
- this.updateEdgeParents(child);
- }
- }
-
- return child;
-};
-
-/**
- * Function: cellAdded
- *
- * Inner callback to update <cells> when a cell has been added. This
- * implementation resolves collisions by creating new Ids. To change the
- * ID of a cell after it was inserted into the model, use the following
- * code:
- *
- * (code
- * delete model.cells[cell.getId()];
- * cell.setId(newId);
- * model.cells[cell.getId()] = cell;
- * (end)
- *
- * If the change of the ID should be part of the command history, then the
- * cell should be removed from the model and a clone with the new ID should
- * be reinserted into the model instead.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell that has been added.
- */
-mxGraphModel.prototype.cellAdded = function(cell)
-{
- if (cell != null)
- {
- // Creates an Id for the cell if not Id exists
- if (cell.getId() == null && this.createIds)
- {
- cell.setId(this.createId(cell));
- }
-
- if (cell.getId() != null)
- {
- var collision = this.getCell(cell.getId());
-
- if (collision != cell)
- {
- // Creates new Id for the cell
- // as long as there is a collision
- while (collision != null)
- {
- cell.setId(this.createId(cell));
- collision = this.getCell(cell.getId());
- }
-
- // Lazily creates the cells dictionary
- if (this.cells == null)
- {
- this.cells = new Object();
- }
-
- this.cells[cell.getId()] = cell;
- }
- }
-
- // Makes sure IDs of deleted cells are not reused
- if (mxUtils.isNumeric(cell.getId()))
- {
- this.nextId = Math.max(this.nextId, cell.getId());
- }
-
- // Recursively processes child cells
- var childCount = this.getChildCount(cell);
-
- for (var i=0; i<childCount; i++)
- {
- this.cellAdded(this.getChildAt(cell, i));
- }
- }
-};
-
-/**
- * Function: createId
- *
- * Hook method to create an Id for the specified cell. This implementation
- * concatenates <prefix>, id and <postfix> to create the Id and increments
- * <nextId>. The cell is ignored by this implementation, but can be used in
- * overridden methods to prefix the Ids with eg. the cell type.
- *
- * Parameters:
- *
- * cell - <mxCell> to create the Id for.
- */
-mxGraphModel.prototype.createId = function(cell)
-{
- var id = this.nextId;
- this.nextId++;
-
- return this.prefix + id + this.postfix;
-};
-
-/**
- * Function: updateEdgeParents
- *
- * Updates the parent for all edges that are connected to cell or one of
- * its descendants using <updateEdgeParent>.
- */
-mxGraphModel.prototype.updateEdgeParents = function(cell, root)
-{
- // Gets the topmost node of the hierarchy
- root = root || this.getRoot(cell);
-
- // Updates edges on children first
- var childCount = this.getChildCount(cell);
-
- for (var i = 0; i < childCount; i++)
- {
- var child = this.getChildAt(cell, i);
- this.updateEdgeParents(child, root);
- }
-
- // Updates the parents of all connected edges
- var edgeCount = this.getEdgeCount(cell);
- var edges = [];
-
- for (var i = 0; i < edgeCount; i++)
- {
- edges.push(this.getEdgeAt(cell, i));
- }
-
- for (var i = 0; i < edges.length; i++)
- {
- var edge = edges[i];
-
- // Updates edge parent if edge and child have
- // a common root node (does not need to be the
- // model root node)
- if (this.isAncestor(root, edge))
- {
- this.updateEdgeParent(edge, root);
- }
- }
-};
-
-/**
- * Function: updateEdgeParent
- *
- * Inner callback to update the parent of the specified <mxCell> to the
- * nearest-common-ancestor of its two terminals.
- *
- * Parameters:
- *
- * edge - <mxCell> that specifies the edge.
- * root - <mxCell> that represents the current root of the model.
- */
-mxGraphModel.prototype.updateEdgeParent = function(edge, root)
-{
- var source = this.getTerminal(edge, true);
- var target = this.getTerminal(edge, false);
- var cell = null;
-
- // Uses the first non-relative descendants of the source terminal
- while (source != null && !this.isEdge(source) &&
- source.geometry != null && source.geometry.relative)
- {
- source = this.getParent(source);
- }
-
- // Uses the first non-relative descendants of the target terminal
- while (target != null && !this.isEdge(target) &&
- target.geometry != null && target.geometry.relative)
- {
- target = this.getParent(target);
- }
-
- if (this.isAncestor(root, source) && this.isAncestor(root, target))
- {
- if (source == target)
- {
- cell = this.getParent(source);
- }
- else
- {
- cell = this.getNearestCommonAncestor(source, target);
- }
-
- if (cell != null && (this.getParent(cell) != this.root ||
- this.isAncestor(cell, edge)) && this.getParent(edge) != cell)
- {
- var geo = this.getGeometry(edge);
-
- if (geo != null)
- {
- var origin1 = this.getOrigin(this.getParent(edge));
- var origin2 = this.getOrigin(cell);
-
- var dx = origin2.x - origin1.x;
- var dy = origin2.y - origin1.y;
-
- geo = geo.clone();
- geo.translate(-dx, -dy);
- this.setGeometry(edge, geo);
- }
-
- this.add(cell, edge, this.getChildCount(cell));
- }
- }
-};
-
-/**
- * Function: getOrigin
- *
- * Returns the absolute, accumulated origin for the children inside the
- * given parent as an <mxPoint>.
- */
-mxGraphModel.prototype.getOrigin = function(cell)
-{
- var result = null;
-
- if (cell != null)
- {
- result = this.getOrigin(this.getParent(cell));
-
- if (!this.isEdge(cell))
- {
- var geo = this.getGeometry(cell);
-
- if (geo != null)
- {
- result.x += geo.x;
- result.y += geo.y;
- }
- }
- }
- else
- {
- result = new mxPoint();
- }
-
- return result;
-};
-
-/**
- * Function: getNearestCommonAncestor
- *
- * Returns the nearest common ancestor for the specified cells.
- *
- * Parameters:
- *
- * cell1 - <mxCell> that specifies the first cell in the tree.
- * cell2 - <mxCell> that specifies the second cell in the tree.
- */
-mxGraphModel.prototype.getNearestCommonAncestor = function(cell1, cell2)
-{
- if (cell1 != null && cell2 != null)
- {
- // Creates the cell path for the second cell
- var path = mxCellPath.create(cell2);
-
- if (path != null && path.length > 0)
- {
- // Bubbles through the ancestors of the first
- // cell to find the nearest common ancestor.
- var cell = cell1;
- var current = mxCellPath.create(cell);
-
- // Inverts arguments
- if (path.length < current.length)
- {
- cell = cell2;
- var tmp = current;
- current = path;
- path = tmp;
- }
-
- while (cell != null)
- {
- var parent = this.getParent(cell);
-
- // Checks if the cell path is equal to the beginning of the given cell path
- if (path.indexOf(current + mxCellPath.PATH_SEPARATOR) == 0 && parent != null)
- {
- return cell;
- }
-
- current = mxCellPath.getParentPath(current);
- cell = parent;
- }
- }
- }
-
- return null;
-};
-
-/**
- * Function: remove
- *
- * Removes the specified cell from the model using <mxChildChange> and adds
- * the change to the current transaction. This operation will remove the
- * cell and all of its children from the model. Returns the removed cell.
- *
- * Parameters:
- *
- * cell - <mxCell> that should be removed.
- */
-mxGraphModel.prototype.remove = function(cell)
-{
- if (cell == this.root)
- {
- this.setRoot(null);
- }
- else if (this.getParent(cell) != null)
- {
- this.execute(new mxChildChange(this, null, cell));
- }
-
- return cell;
-};
-
-/**
- * Function: cellRemoved
- *
- * Inner callback to update <cells> when a cell has been removed.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell that has been removed.
- */
-mxGraphModel.prototype.cellRemoved = function(cell)
-{
- if (cell != null && this.cells != null)
- {
- // Recursively processes child cells
- var childCount = this.getChildCount(cell);
-
- for (var i = childCount - 1; i >= 0; i--)
- {
- this.cellRemoved(this.getChildAt(cell, i));
- }
-
- // Removes the dictionary entry for the cell
- if (this.cells != null && cell.getId() != null)
- {
- delete this.cells[cell.getId()];
- }
- }
-};
-
-/**
- * Function: parentForCellChanged
- *
- * Inner callback to update the parent of a cell using <mxCell.insert>
- * on the parent and return the previous parent.
- *
- * Parameters:
- *
- * cell - <mxCell> to update the parent for.
- * parent - <mxCell> that specifies the new parent of the cell.
- * index - Optional integer that defines the index of the child
- * in the parent's child array.
- */
-mxGraphModel.prototype.parentForCellChanged = function(cell, parent, index)
-{
- var previous = this.getParent(cell);
-
- if (parent != null)
- {
- if (parent != previous || previous.getIndex(cell) != index)
- {
- parent.insert(cell, index);
- }
- }
- else if (previous != null)
- {
- var oldIndex = previous.getIndex(cell);
- previous.remove(oldIndex);
- }
-
- // Checks if the previous parent was already in the
- // model and avoids calling cellAdded if it was.
- if (!this.contains(previous) && parent != null)
- {
- this.cellAdded(cell);
- }
- else if (parent == null)
- {
- this.cellRemoved(cell);
- }
-
- return previous;
-};
-
-/**
- * Function: getChildCount
- *
- * Returns the number of children in the given cell.
- *
- * Parameters:
- *
- * cell - <mxCell> whose number of children should be returned.
- */
-mxGraphModel.prototype.getChildCount = function(cell)
-{
- return (cell != null) ? cell.getChildCount() : 0;
-};
-
-/**
- * Function: getChildAt
- *
- * Returns the child of the given <mxCell> at the given index.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the parent.
- * index - Integer that specifies the index of the child to be returned.
- */
-mxGraphModel.prototype.getChildAt = function(cell, index)
-{
- return (cell != null) ? cell.getChildAt(index) : null;
-};
-
-/**
- * Function: getChildren
- *
- * Returns all children of the given <mxCell> as an array of <mxCells>. The
- * return value should be only be read.
- *
- * Parameters:
- *
- * cell - <mxCell> the represents the parent.
- */
-mxGraphModel.prototype.getChildren = function(cell)
-{
- return (cell != null) ? cell.children : null;
-};
-
-/**
- * Function: getChildVertices
- *
- * Returns the child vertices of the given parent.
- *
- * Parameters:
- *
- * cell - <mxCell> whose child vertices should be returned.
- */
-mxGraphModel.prototype.getChildVertices = function(parent)
-{
- return this.getChildCells(parent, true, false);
-};
-
-/**
- * Function: getChildEdges
- *
- * Returns the child edges of the given parent.
- *
- * Parameters:
- *
- * cell - <mxCell> whose child edges should be returned.
- */
-mxGraphModel.prototype.getChildEdges = function(parent)
-{
- return this.getChildCells(parent, false, true);
-};
-
-/**
- * Function: getChildCells
- *
- * Returns the children of the given cell that are vertices and/or edges
- * depending on the arguments.
- *
- * Parameters:
- *
- * cell - <mxCell> the represents the parent.
- * vertices - Boolean indicating if child vertices should be returned.
- * Default is false.
- * edges - Boolean indicating if child edges should be returned.
- * Default is false.
- */
-mxGraphModel.prototype.getChildCells = function(parent, vertices, edges)
-{
- vertices = (vertices != null) ? vertices : false;
- edges = (edges != null) ? edges : false;
-
- var childCount = this.getChildCount(parent);
- var result = [];
-
- for (var i = 0; i < childCount; i++)
- {
- var child = this.getChildAt(parent, i);
-
- if ((!edges && !vertices) || (edges && this.isEdge(child)) ||
- (vertices && this.isVertex(child)))
- {
- result.push(child);
- }
- }
-
- return result;
-};
-
-/**
- * Function: getTerminal
- *
- * Returns the source or target <mxCell> of the given edge depending on the
- * value of the boolean parameter.
- *
- * Parameters:
- *
- * edge - <mxCell> that specifies the edge.
- * isSource - Boolean indicating which end of the edge should be returned.
- */
-mxGraphModel.prototype.getTerminal = function(edge, isSource)
-{
- return (edge != null) ? edge.getTerminal(isSource) : null;
-};
-
-/**
- * Function: setTerminal
- *
- * Sets the source or target terminal of the given <mxCell> using
- * <mxTerminalChange> and adds the change to the current transaction.
- * This implementation updates the parent of the edge using <updateEdgeParent>
- * if required.
- *
- * Parameters:
- *
- * edge - <mxCell> that specifies the edge.
- * terminal - <mxCell> that specifies the new terminal.
- * isSource - Boolean indicating if the terminal is the new source or
- * target terminal of the edge.
- */
-mxGraphModel.prototype.setTerminal = function(edge, terminal, isSource)
-{
- var terminalChanged = terminal != this.getTerminal(edge, isSource);
- this.execute(new mxTerminalChange(this, edge, terminal, isSource));
-
- if (this.maintainEdgeParent && terminalChanged)
- {
- this.updateEdgeParent(edge, this.getRoot());
- }
-
- return terminal;
-};
-
-/**
- * Function: setTerminals
- *
- * Sets the source and target <mxCell> of the given <mxCell> in a single
- * transaction using <setTerminal> for each end of the edge.
- *
- * Parameters:
- *
- * edge - <mxCell> that specifies the edge.
- * source - <mxCell> that specifies the new source terminal.
- * target - <mxCell> that specifies the new target terminal.
- */
-mxGraphModel.prototype.setTerminals = function(edge, source, target)
-{
- this.beginUpdate();
- try
- {
- this.setTerminal(edge, source, true);
- this.setTerminal(edge, target, false);
- }
- finally
- {
- this.endUpdate();
- }
-};
-
-/**
- * Function: terminalForCellChanged
- *
- * Inner helper function to update the terminal of the edge using
- * <mxCell.insertEdge> and return the previous terminal.
- *
- * Parameters:
- *
- * edge - <mxCell> that specifies the edge to be updated.
- * terminal - <mxCell> that specifies the new terminal.
- * isSource - Boolean indicating if the terminal is the new source or
- * target terminal of the edge.
- */
-mxGraphModel.prototype.terminalForCellChanged = function(edge, terminal, isSource)
-{
- var previous = this.getTerminal(edge, isSource);
-
- if (terminal != null)
- {
- terminal.insertEdge(edge, isSource);
- }
- else if (previous != null)
- {
- previous.removeEdge(edge, isSource);
- }
-
- return previous;
-};
-
-/**
- * Function: getEdgeCount
- *
- * Returns the number of distinct edges connected to the given cell.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the vertex.
- */
-mxGraphModel.prototype.getEdgeCount = function(cell)
-{
- return (cell != null) ? cell.getEdgeCount() : 0;
-};
-
-/**
- * Function: getEdgeAt
- *
- * Returns the edge of cell at the given index.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the vertex.
- * index - Integer that specifies the index of the edge
- * to return.
- */
-mxGraphModel.prototype.getEdgeAt = function(cell, index)
-{
- return (cell != null) ? cell.getEdgeAt(index) : null;
-};
-
-/**
- * Function: getDirectedEdgeCount
- *
- * Returns the number of incoming or outgoing edges, ignoring the given
- * edge.
- *
- * Parameters:
- *
- * cell - <mxCell> whose edge count should be returned.
- * outgoing - Boolean that specifies if the number of outgoing or
- * incoming edges should be returned.
- * ignoredEdge - <mxCell> that represents an edge to be ignored.
- */
-mxGraphModel.prototype.getDirectedEdgeCount = function(cell, outgoing, ignoredEdge)
-{
- var count = 0;
- var edgeCount = this.getEdgeCount(cell);
-
- for (var i = 0; i < edgeCount; i++)
- {
- var edge = this.getEdgeAt(cell, i);
-
- if (edge != ignoredEdge && this.getTerminal(edge, outgoing) == cell)
- {
- count++;
- }
- }
-
- return count;
-};
-
-/**
- * Function: getConnections
- *
- * Returns all edges of the given cell without loops.
- *
- * Parameters:
- *
- * cell - <mxCell> whose edges should be returned.
- *
- */
-mxGraphModel.prototype.getConnections = function(cell)
-{
- return this.getEdges(cell, true, true, false);
-};
-
-/**
- * Function: getIncomingEdges
- *
- * Returns the incoming edges of the given cell without loops.
- *
- * Parameters:
- *
- * cell - <mxCell> whose incoming edges should be returned.
- *
- */
-mxGraphModel.prototype.getIncomingEdges = function(cell)
-{
- return this.getEdges(cell, true, false, false);
-};
-
-/**
- * Function: getOutgoingEdges
- *
- * Returns the outgoing edges of the given cell without loops.
- *
- * Parameters:
- *
- * cell - <mxCell> whose outgoing edges should be returned.
- *
- */
-mxGraphModel.prototype.getOutgoingEdges = function(cell)
-{
- return this.getEdges(cell, false, true, false);
-};
-
-/**
- * Function: getEdges
- *
- * Returns all distinct edges connected to this cell as a new array of
- * <mxCells>. If at least one of incoming or outgoing is true, then loops
- * are ignored, otherwise if both are false, then all edges connected to
- * the given cell are returned including loops.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell.
- * incoming - Optional boolean that specifies if incoming edges should be
- * returned. Default is true.
- * outgoing - Optional boolean that specifies if outgoing edges should be
- * returned. Default is true.
- * includeLoops - Optional boolean that specifies if loops should be returned.
- * Default is true.
- */
-mxGraphModel.prototype.getEdges = function(cell, incoming, outgoing, includeLoops)
-{
- incoming = (incoming != null) ? incoming : true;
- outgoing = (outgoing != null) ? outgoing : true;
- includeLoops = (includeLoops != null) ? includeLoops : true;
-
- var edgeCount = this.getEdgeCount(cell);
- var result = [];
-
- for (var i = 0; i < edgeCount; i++)
- {
- var edge = this.getEdgeAt(cell, i);
- var source = this.getTerminal(edge, true);
- var target = this.getTerminal(edge, false);
-
- if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) ||
- (outgoing && source == cell))))
- {
- result.push(edge);
- }
- }
-
- return result;
-};
-
-/**
- * Function: getEdgesBetween
- *
- * Returns all edges between the given source and target pair. If directed
- * is true, then only edges from the source to the target are returned,
- * otherwise, all edges between the two cells are returned.
- *
- * Parameters:
- *
- * source - <mxCell> that defines the source terminal of the edge to be
- * returned.
- * target - <mxCell> that defines the target terminal of the edge to be
- * returned.
- * directed - Optional boolean that specifies if the direction of the
- * edge should be taken into account. Default is false.
- */
-mxGraphModel.prototype.getEdgesBetween = function(source, target, directed)
-{
- directed = (directed != null) ? directed : false;
-
- var tmp1 = this.getEdgeCount(source);
- var tmp2 = this.getEdgeCount(target);
-
- // Assumes the source has less connected edges
- var terminal = source;
- var edgeCount = tmp1;
-
- // Uses the smaller array of connected edges
- // for searching the edge
- if (tmp2 < tmp1)
- {
- edgeCount = tmp2;
- terminal = target;
- }
-
- var result = [];
-
- // Checks if the edge is connected to the correct
- // cell and returns the first match
- for (var i = 0; i < edgeCount; i++)
- {
- var edge = this.getEdgeAt(terminal, i);
- var src = this.getTerminal(edge, true);
- var trg = this.getTerminal(edge, false);
- var directedMatch = (src == source) && (trg == target);
- var oppositeMatch = (trg == source) && (src == target);
-
- if (directedMatch || (!directed && oppositeMatch))
- {
- result.push(edge);
- }
- }
-
- return result;
-};
-
-/**
- * Function: getOpposites
- *
- * Returns all opposite vertices wrt terminal for the given edges, only
- * returning sources and/or targets as specified. The result is returned
- * as an array of <mxCells>.
- *
- * Parameters:
- *
- * edges - Array of <mxCells> that contain the edges to be examined.
- * terminal - <mxCell> that specifies the known end of the edges.
- * sources - Boolean that specifies if source terminals should be contained
- * in the result. Default is true.
- * targets - Boolean that specifies if target terminals should be contained
- * in the result. Default is true.
- */
-mxGraphModel.prototype.getOpposites = function(edges, terminal, sources, targets)
-{
- sources = (sources != null) ? sources : true;
- targets = (targets != null) ? targets : true;
-
- var terminals = [];
-
- if (edges != null)
- {
- for (var i = 0; i < edges.length; i++)
- {
- var source = this.getTerminal(edges[i], true);
- var target = this.getTerminal(edges[i], false);
-
- // Checks if the terminal is the source of
- // the edge and if the target should be
- // stored in the result
- if (source == terminal && target != null && target != terminal && targets)
- {
- terminals.push(target);
- }
-
- // Checks if the terminal is the taget of
- // the edge and if the source should be
- // stored in the result
- else if (target == terminal && source != null && source != terminal && sources)
- {
- terminals.push(source);
- }
- }
- }
-
- return terminals;
-};
-
-/**
- * Function: getTopmostCells
- *
- * Returns the topmost cells of the hierarchy in an array that contains no
- * descendants for each <mxCell> that it contains. Duplicates should be
- * removed in the cells array to improve performance.
- *
- * Parameters:
- *
- * cells - Array of <mxCells> whose topmost ancestors should be returned.
- */
-mxGraphModel.prototype.getTopmostCells = function(cells)
-{
- var tmp = [];
-
- for (var i = 0; i < cells.length; i++)
- {
- var cell = cells[i];
- var topmost = true;
- var parent = this.getParent(cell);
-
- while (parent != null)
- {
- if (mxUtils.indexOf(cells, parent) >= 0)
- {
- topmost = false;
- break;
- }
-
- parent = this.getParent(parent);
- }
-
- if (topmost)
- {
- tmp.push(cell);
- }
- }
-
- return tmp;
-};
-
-/**
- * Function: isVertex
- *
- * Returns true if the given cell is a vertex.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the possible vertex.
- */
-mxGraphModel.prototype.isVertex = function(cell)
-{
- return (cell != null) ? cell.isVertex() : false;
-};
-
-/**
- * Function: isEdge
- *
- * Returns true if the given cell is an edge.
- *
- * Parameters:
- *
- * cell - <mxCell> that represents the possible edge.
- */
-mxGraphModel.prototype.isEdge = function(cell)
-{
- return (cell != null) ? cell.isEdge() : false;
-};
-
-/**
- * Function: isConnectable
- *
- * Returns true if the given <mxCell> is connectable. If <edgesConnectable>
- * is false, then this function returns false for all edges else it returns
- * the return value of <mxCell.isConnectable>.
- *
- * Parameters:
- *
- * cell - <mxCell> whose connectable state should be returned.
- */
-mxGraphModel.prototype.isConnectable = function(cell)
-{
- return (cell != null) ? cell.isConnectable() : false;
-};
-
-/**
- * Function: getValue
- *
- * Returns the user object of the given <mxCell> using <mxCell.getValue>.
- *
- * Parameters:
- *
- * cell - <mxCell> whose user object should be returned.
- */
-mxGraphModel.prototype.getValue = function(cell)
-{
- return (cell != null) ? cell.getValue() : null;
-};
-
-/**
- * Function: setValue
- *
- * Sets the user object of then given <mxCell> using <mxValueChange>
- * and adds the change to the current transaction.
- *
- * Parameters:
- *
- * cell - <mxCell> whose user object should be changed.
- * value - Object that defines the new user object.
- */
-mxGraphModel.prototype.setValue = function(cell, value)
-{
- this.execute(new mxValueChange(this, cell, value));
-
- return value;
-};
-
-/**
- * Function: valueForCellChanged
- *
- * Inner callback to update the user object of the given <mxCell>
- * using <mxCell.valueChanged> and return the previous value,
- * that is, the return value of <mxCell.valueChanged>.
- *
- * To change a specific attribute in an XML node, the following code can be
- * used.
- *
- * (code)
- * graph.getModel().valueForCellChanged = function(cell, value)
- * {
- * var previous = cell.value.getAttribute('label');
- * cell.value.setAttribute('label', value);
- *
- * return previous;
- * };
- * (end)
- */
-mxGraphModel.prototype.valueForCellChanged = function(cell, value)
-{
- return cell.valueChanged(value);
-};
-
-/**
- * Function: getGeometry
- *
- * Returns the <mxGeometry> of the given <mxCell>.
- *
- * Parameters:
- *
- * cell - <mxCell> whose geometry should be returned.
- */
-mxGraphModel.prototype.getGeometry = function(cell, geometry)
-{
- return (cell != null) ? cell.getGeometry() : null;
-};
-
-/**
- * Function: setGeometry
- *
- * Sets the <mxGeometry> of the given <mxCell>. The actual update
- * of the cell is carried out in <geometryForCellChanged>. The
- * <mxGeometryChange> action is used to encapsulate the change.
- *
- * Parameters:
- *
- * cell - <mxCell> whose geometry should be changed.
- * geometry - <mxGeometry> that defines the new geometry.
- */
-mxGraphModel.prototype.setGeometry = function(cell, geometry)
-{
- if (geometry != this.getGeometry(cell))
- {
- this.execute(new mxGeometryChange(this, cell, geometry));
- }
-
- return geometry;
-};
-
-/**
- * Function: geometryForCellChanged
- *
- * Inner callback to update the <mxGeometry> of the given <mxCell> using
- * <mxCell.setGeometry> and return the previous <mxGeometry>.
- */
-mxGraphModel.prototype.geometryForCellChanged = function(cell, geometry)
-{
- var previous = this.getGeometry(cell);
- cell.setGeometry(geometry);
-
- return previous;
-};
-
-/**
- * Function: getStyle
- *
- * Returns the style of the given <mxCell>.
- *
- * Parameters:
- *
- * cell - <mxCell> whose style should be returned.
- */
-mxGraphModel.prototype.getStyle = function(cell)
-{
- return (cell != null) ? cell.getStyle() : null;
-};
-
-/**
- * Function: setStyle
- *
- * Sets the style of the given <mxCell> using <mxStyleChange> and
- * adds the change to the current transaction.
- *
- * Parameters:
- *
- * cell - <mxCell> whose style should be changed.
- * style - String of the form [stylename;|key=value;] to specify
- * the new cell style.
- */
-mxGraphModel.prototype.setStyle = function(cell, style)
-{
- if (style != this.getStyle(cell))
- {
- this.execute(new mxStyleChange(this, cell, style));
- }
-
- return style;
-};
-
-/**
- * Function: styleForCellChanged
- *
- * Inner callback to update the style of the given <mxCell>
- * using <mxCell.setStyle> and return the previous style.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell to be updated.
- * style - String of the form [stylename;|key=value;] to specify
- * the new cell style.
- */
-mxGraphModel.prototype.styleForCellChanged = function(cell, style)
-{
- var previous = this.getStyle(cell);
- cell.setStyle(style);
-
- return previous;
-};
-
-/**
- * Function: isCollapsed
- *
- * Returns true if the given <mxCell> is collapsed.
- *
- * Parameters:
- *
- * cell - <mxCell> whose collapsed state should be returned.
- */
-mxGraphModel.prototype.isCollapsed = function(cell)
-{
- return (cell != null) ? cell.isCollapsed() : false;
-};
-
-/**
- * Function: setCollapsed
- *
- * Sets the collapsed state of the given <mxCell> using <mxCollapseChange>
- * and adds the change to the current transaction.
- *
- * Parameters:
- *
- * cell - <mxCell> whose collapsed state should be changed.
- * collapsed - Boolean that specifies the new collpased state.
- */
-mxGraphModel.prototype.setCollapsed = function(cell, collapsed)
-{
- if (collapsed != this.isCollapsed(cell))
- {
- this.execute(new mxCollapseChange(this, cell, collapsed));
- }
-
- return collapsed;
-};
-
-/**
- * Function: collapsedStateForCellChanged
- *
- * Inner callback to update the collapsed state of the
- * given <mxCell> using <mxCell.setCollapsed> and return
- * the previous collapsed state.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell to be updated.
- * collapsed - Boolean that specifies the new collpased state.
- */
-mxGraphModel.prototype.collapsedStateForCellChanged = function(cell, collapsed)
-{
- var previous = this.isCollapsed(cell);
- cell.setCollapsed(collapsed);
-
- return previous;
-};
-
-/**
- * Function: isVisible
- *
- * Returns true if the given <mxCell> is visible.
- *
- * Parameters:
- *
- * cell - <mxCell> whose visible state should be returned.
- */
-mxGraphModel.prototype.isVisible = function(cell)
-{
- return (cell != null) ? cell.isVisible() : false;
-};
-
-/**
- * Function: setVisible
- *
- * Sets the visible state of the given <mxCell> using <mxVisibleChange> and
- * adds the change to the current transaction.
- *
- * Parameters:
- *
- * cell - <mxCell> whose visible state should be changed.
- * visible - Boolean that specifies the new visible state.
- */
-mxGraphModel.prototype.setVisible = function(cell, visible)
-{
- if (visible != this.isVisible(cell))
- {
- this.execute(new mxVisibleChange(this, cell, visible));
- }
-
- return visible;
-};
-
-/**
- * Function: visibleStateForCellChanged
- *
- * Inner callback to update the visible state of the
- * given <mxCell> using <mxCell.setCollapsed> and return
- * the previous visible state.
- *
- * Parameters:
- *
- * cell - <mxCell> that specifies the cell to be updated.
- * visible - Boolean that specifies the new visible state.
- */
-mxGraphModel.prototype.visibleStateForCellChanged = function(cell, visible)
-{
- var previous = this.isVisible(cell);
- cell.setVisible(visible);
-
- return previous;
-};
-
-/**
- * Function: execute
- *
- * Executes the given edit and fires events if required. The edit object
- * requires an execute function which is invoked. The edit is added to the
- * <currentEdit> between <beginUpdate> and <endUpdate> calls, so that
- * events will be fired if this execute is an individual transaction, that
- * is, if no previous <beginUpdate> calls have been made without calling
- * <endUpdate>. This implementation fires an <execute> event before
- * executing the given change.
- *
- * Parameters:
- *
- * change - Object that described the change.
- */
-mxGraphModel.prototype.execute = function(change)
-{
- change.execute();
- this.beginUpdate();
- this.currentEdit.add(change);
- this.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change));
- this.endUpdate();
-};
-
-/**
- * Function: beginUpdate
- *
- * Increments the <updateLevel> by one. The event notification
- * is queued until <updateLevel> reaches 0 by use of
- * <endUpdate>.
- *
- * All changes on <mxGraphModel> are transactional,
- * that is, they are executed in a single undoable change
- * on the model (without transaction isolation).
- * Therefore, if you want to combine any
- * number of changes into a single undoable change,
- * you should group any two or more API calls that
- * modify the graph model between <beginUpdate>
- * and <endUpdate> calls as shown here:
- *
- * (code)
- * var model = graph.getModel();
- * var parent = graph.getDefaultParent();
- * var index = model.getChildCount(parent);
- * model.beginUpdate();
- * try
- * {
- * model.add(parent, v1, index);
- * model.add(parent, v2, index+1);
- * }
- * finally
- * {
- * model.endUpdate();
- * }
- * (end)
- *
- * Of course there is a shortcut for appending a
- * sequence of cells into the default parent:
- *
- * (code)
- * graph.addCells([v1, v2]).
- * (end)
- */
-mxGraphModel.prototype.beginUpdate = function()
-{
- this.updateLevel++;
- this.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE));
-};
-
-/**
- * Function: endUpdate
- *
- * Decrements the <updateLevel> by one and fires an <undo>
- * event if the <updateLevel> reaches 0. This function
- * indirectly fires a <change> event by invoking the notify
- * function on the <currentEdit> und then creates a new
- * <currentEdit> using <createUndoableEdit>.
- *
- * The <undo> event is fired only once per edit, whereas
- * the <change> event is fired whenever the notify
- * function is invoked, that is, on undo and redo of
- * the edit.
- */
-mxGraphModel.prototype.endUpdate = function()
-{
- this.updateLevel--;
-
- if (!this.endingUpdate)
- {
- this.endingUpdate = this.updateLevel == 0;
- this.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit));
-
- try
- {
- if (this.endingUpdate && !this.currentEdit.isEmpty())
- {
- this.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit));
- var tmp = this.currentEdit;
- this.currentEdit = this.createUndoableEdit();
- tmp.notify();
- this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp));
- }
- }
- finally
- {
- this.endingUpdate = false;
- }
- }
-};
-
-/**
- * Function: createUndoableEdit
- *
- * Creates a new <mxUndoableEdit> that implements the
- * notify function to fire a <change> and <notify> event
- * through the <mxUndoableEdit>'s source.
- */
-mxGraphModel.prototype.createUndoableEdit = function()
-{
- var edit = new mxUndoableEdit(this, true);
-
- edit.notify = function()
- {
- // LATER: Remove changes property (deprecated)
- edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
- 'edit', edit, 'changes', edit.changes));
- edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
- 'edit', edit, 'changes', edit.changes));
- };
-
- return edit;
-};
-
-/**
- * Function: mergeChildren
- *
- * Merges the children of the given cell into the given target cell inside
- * this model. All cells are cloned unless there is a corresponding cell in
- * the model with the same id, in which case the source cell is ignored and
- * all edges are connected to the corresponding cell in this model. Edges
- * are considered to have no identity and are always cloned unless the
- * cloneAllEdges flag is set to false, in which case edges with the same
- * id in the target model are reconnected to reflect the terminals of the
- * source edges.
- */
-mxGraphModel.prototype.mergeChildren = function(from, to, cloneAllEdges)
-{
- cloneAllEdges = (cloneAllEdges != null) ? cloneAllEdges : true;
-
- this.beginUpdate();
- try
- {
- var mapping = new Object();
- this.mergeChildrenImpl(from, to, cloneAllEdges, mapping);
-
- // Post-processes all edges in the mapping and
- // reconnects the terminals to the corresponding
- // cells in the target model
- for (var key in mapping)
- {
- var cell = mapping[key];
- var terminal = this.getTerminal(cell, true);
-
- if (terminal != null)
- {
- terminal = mapping[mxCellPath.create(terminal)];
- this.setTerminal(cell, terminal, true);
- }
-
- terminal = this.getTerminal(cell, false);
-
- if (terminal != null)
- {
- terminal = mapping[mxCellPath.create(terminal)];
- this.setTerminal(cell, terminal, false);
- }
- }
- }
- finally
- {
- this.endUpdate();
- }
-};
-
-/**
- * Function: mergeChildren
- *
- * Clones the children of the source cell into the given target cell in
- * this model and adds an entry to the mapping that maps from the source
- * cell to the target cell with the same id or the clone of the source cell
- * that was inserted into this model.
- */
-mxGraphModel.prototype.mergeChildrenImpl = function(from, to, cloneAllEdges, mapping)
-{
- this.beginUpdate();
- try
- {
- var childCount = from.getChildCount();
-
- for (var i = 0; i < childCount; i++)
- {
- var cell = from.getChildAt(i);
-
- if (typeof(cell.getId) == 'function')
- {
- var id = cell.getId();
- var target = (id != null && (!this.isEdge(cell) || !cloneAllEdges)) ?
- this.getCell(id) : null;
-
- // Clones and adds the child if no cell exists for the id
- if (target == null)
- {
- var clone = cell.clone();
- clone.setId(id);
-
- // Sets the terminals from the original cell to the clone
- // because the lookup uses strings not cells in JS
- clone.setTerminal(cell.getTerminal(true), true);
- clone.setTerminal(cell.getTerminal(false), false);
-
- // Do *NOT* use model.add as this will move the edge away
- // from the parent in updateEdgeParent if maintainEdgeParent
- // is enabled in the target model
- target = to.insert(clone);
- this.cellAdded(target);
- }
-
- // Stores the mapping for later reconnecting edges
- mapping[mxCellPath.create(cell)] = target;
-
- // Recurses
- this.mergeChildrenImpl(cell, target, cloneAllEdges, mapping);
- }
- }
- }
- finally
- {
- this.endUpdate();
- }
-};
-
-/**
- * Function: getParents
- *
- * Returns an array that represents the set (no duplicates) of all parents
- * for the given array of cells.
- *
- * Parameters:
- *
- * cells - Array of cells whose parents should be returned.
- */
-mxGraphModel.prototype.getParents = function(cells)
-{
- var parents = [];
-
- if (cells != null)
- {
- var hash = new Object();
-
- for (var i = 0; i < cells.length; i++)
- {
- var parent = this.getParent(cells[i]);
-
- if (parent != null)
- {
- var id = mxCellPath.create(parent);
-
- if (hash[id] == null)
- {
- hash[id] = parent;
- parents.push(parent);
- }
- }
- }
- }
-
- return parents;
-};
-
-//
-// Cell Cloning
-//
-
-/**
- * Function: cloneCell
- *
- * Returns a deep clone of the given <mxCell> (including
- * the children) which is created using <cloneCells>.
- *
- * Parameters:
- *
- * cell - <mxCell> to be cloned.
- */
-mxGraphModel.prototype.cloneCell = function(cell)
-{
- if (cell != null)
- {
- return this.cloneCells([cell], true)[0];
- }
-
- return null;
-};
-
-/**
- * Function: cloneCells
- *
- * Returns an array of clones for the given array of <mxCells>.
- * Depending on the value of includeChildren, a deep clone is created for
- * each cell. Connections are restored based if the corresponding
- * cell is contained in the passed in array.
- *
- * Parameters:
- *
- * cells - Array of <mxCell> to be cloned.
- * includeChildren - Boolean indicating if the cells should be cloned
- * with all descendants.
- */
-mxGraphModel.prototype.cloneCells = function(cells, includeChildren)
-{
- var mapping = new Object();
- var clones = [];
-
- for (var i = 0; i < cells.length; i++)
- {
- if (cells[i] != null)
- {
- clones.push(this.cloneCellImpl(cells[i], mapping, includeChildren));
- }
- else
- {
- clones.push(null);
- }
- }
-
- for (var i = 0; i < clones.length; i++)
- {
- if (clones[i] != null)
- {
- this.restoreClone(clones[i], cells[i], mapping);
- }
- }
-
- return clones;
-};
-
-/**
- * Function: cloneCellImpl
- *
- * Inner helper method for cloning cells recursively.
- */
-mxGraphModel.prototype.cloneCellImpl = function(cell, mapping, includeChildren)
-{
- var clone = this.cellCloned(cell);
-
- // Stores the clone in the lookup under the
- // cell path for the original cell
- mapping[mxObjectIdentity.get(cell)] = clone;
-
- if (includeChildren)
- {
- var childCount = this.getChildCount(cell);
-
- for (var i = 0; i < childCount; i++)
- {
- var cloneChild = this.cloneCellImpl(
- this.getChildAt(cell, i), mapping, true);
- clone.insert(cloneChild);
- }
- }
-
- return clone;
-};
-
-/**
- * Function: cellCloned
- *
- * Hook for cloning the cell. This returns cell.clone() or
- * any possible exceptions.
- */
-mxGraphModel.prototype.cellCloned = function(cell)
-{
- return cell.clone();
-};
-
-/**
- * Function: restoreClone
- *
- * Inner helper method for restoring the connections in
- * a network of cloned cells.
- */
-mxGraphModel.prototype.restoreClone = function(clone, cell, mapping)
-{
- var source = this.getTerminal(cell, true);
-
- if (source != null)
- {
- var tmp = mapping[mxObjectIdentity.get(source)];
-
- if (tmp != null)
- {
- tmp.insertEdge(clone, true);
- }
- }
-
- var target = this.getTerminal(cell, false);
-
- if (target != null)
- {
- var tmp = mapping[mxObjectIdentity.get(target)];
-
- if (tmp != null)
- {
- tmp.insertEdge(clone, false);
- }
- }
-
- var childCount = this.getChildCount(clone);
-
- for (var i = 0; i < childCount; i++)
- {
- this.restoreClone(this.getChildAt(clone, i),
- this.getChildAt(cell, i), mapping);
- }
-};
-
-//
-// Atomic changes
-//
-
-/**
- * Class: mxRootChange
- *
- * Action to change the root in a model.
- *
- * Constructor: mxRootChange
- *
- * Constructs a change of the root in the
- * specified model.
- */
-function mxRootChange(model, root)
-{
- this.model = model;
- this.root = root;
- this.previous = root;
-};
-
-/**
- * Function: execute
- *
- * Carries out a change of the root using
- * <mxGraphModel.rootChanged>.
- */
-mxRootChange.prototype.execute = function()
-{
- this.root = this.previous;
- this.previous = this.model.rootChanged(this.previous);
-};
-
-/**
- * Class: mxChildChange
- *
- * Action to add or remove a child in a model.
- *
- * Constructor: mxChildChange
- *
- * Constructs a change of a child in the
- * specified model.
- */
-function mxChildChange(model, parent, child, index)
-{
- this.model = model;
- this.parent = parent;
- this.previous = parent;
- this.child = child;
- this.index = index;
- this.previousIndex = index;
-};
-
-/**
- * Function: execute
- *
- * Changes the parent of <child> using
- * <mxGraphModel.parentForCellChanged> and
- * removes or restores the cell's
- * connections.
- */
-mxChildChange.prototype.execute = function()
-{
- var tmp = this.model.getParent(this.child);
- var tmp2 = (tmp != null) ? tmp.getIndex(this.child) : 0;
-
- if (this.previous == null)
- {
- this.connect(this.child, false);
- }
-
- tmp = this.model.parentForCellChanged(
- this.child, this.previous, this.previousIndex);
-
- if (this.previous != null)
- {
- this.connect(this.child, true);
- }
-
- this.parent = this.previous;
- this.previous = tmp;
- this.index = this.previousIndex;
- this.previousIndex = tmp2;
-};
-
-/**
- * Function: disconnect
- *
- * Disconnects the given cell recursively from its
- * terminals and stores the previous terminal in the
- * cell's terminals.
- */
-mxChildChange.prototype.connect = function(cell, isConnect)
-{
- isConnect = (isConnect != null) ? isConnect : true;
-
- var source = cell.getTerminal(true);
- var target = cell.getTerminal(false);
-
- if (source != null)
- {
- if (isConnect)
- {
- this.model.terminalForCellChanged(cell, source, true);
- }
- else
- {
- this.model.terminalForCellChanged(cell, null, true);
- }
- }
-
- if (target != null)
- {
- if (isConnect)
- {
- this.model.terminalForCellChanged(cell, target, false);
- }
- else
- {
- this.model.terminalForCellChanged(cell, null, false);
- }
- }
-
- cell.setTerminal(source, true);
- cell.setTerminal(target, false);
-
- var childCount = this.model.getChildCount(cell);
-
- for (var i=0; i<childCount; i++)
- {
- this.connect(this.model.getChildAt(cell, i), isConnect);
- }
-};
-
-/**
- * Class: mxTerminalChange
- *
- * Action to change a terminal in a model.
- *
- * Constructor: mxTerminalChange
- *
- * Constructs a change of a terminal in the
- * specified model.
- */
-function mxTerminalChange(model, cell, terminal, source)
-{
- this.model = model;
- this.cell = cell;
- this.terminal = terminal;
- this.previous = terminal;
- this.source = source;
-};
-
-/**
- * Function: execute
- *
- * Changes the terminal of <cell> to <previous> using
- * <mxGraphModel.terminalForCellChanged>.
- */
-mxTerminalChange.prototype.execute = function()
-{
- this.terminal = this.previous;
- this.previous = this.model.terminalForCellChanged(
- this.cell, this.previous, this.source);
-};
-
-/**
- * Class: mxValueChange
- *
- * Action to change a user object in a model.
- *
- * Constructor: mxValueChange
- *
- * Constructs a change of a user object in the
- * specified model.
- */
-function mxValueChange(model, cell, value)
-{
- this.model = model;
- this.cell = cell;
- this.value = value;
- this.previous = value;
-};
-
-/**
- * Function: execute
- *
- * Changes the value of <cell> to <previous> using
- * <mxGraphModel.valueForCellChanged>.
- */
-mxValueChange.prototype.execute = function()
-{
- this.value = this.previous;
- this.previous = this.model.valueForCellChanged(
- this.cell, this.previous);
-};
-
-/**
- * Class: mxStyleChange
- *
- * Action to change a cell's style in a model.
- *
- * Constructor: mxStyleChange
- *
- * Constructs a change of a style in the
- * specified model.
- */
-function mxStyleChange(model, cell, style)
-{
- this.model = model;
- this.cell = cell;
- this.style = style;
- this.previous = style;
-};
-
-/**
- * Function: execute
- *
- * Changes the style of <cell> to <previous> using
- * <mxGraphModel.styleForCellChanged>.
- */
-mxStyleChange.prototype.execute = function()
-{
- this.style = this.previous;
- this.previous = this.model.styleForCellChanged(
- this.cell, this.previous);
-};
-
-/**
- * Class: mxGeometryChange
- *
- * Action to change a cell's geometry in a model.
- *
- * Constructor: mxGeometryChange
- *
- * Constructs a change of a geometry in the
- * specified model.
- */
-function mxGeometryChange(model, cell, geometry)
-{
- this.model = model;
- this.cell = cell;
- this.geometry = geometry;
- this.previous = geometry;
-};
-
-/**
- * Function: execute
- *
- * Changes the geometry of <cell> ro <previous> using
- * <mxGraphModel.geometryForCellChanged>.
- */
-mxGeometryChange.prototype.execute = function()
-{
- this.geometry = this.previous;
- this.previous = this.model.geometryForCellChanged(
- this.cell, this.previous);
-};
-
-/**
- * Class: mxCollapseChange
- *
- * Action to change a cell's collapsed state in a model.
- *
- * Constructor: mxCollapseChange
- *
- * Constructs a change of a collapsed state in the
- * specified model.
- */
-function mxCollapseChange(model, cell, collapsed)
-{
- this.model = model;
- this.cell = cell;
- this.collapsed = collapsed;
- this.previous = collapsed;
-};
-
-/**
- * Function: execute
- *
- * Changes the collapsed state of <cell> to <previous> using
- * <mxGraphModel.collapsedStateForCellChanged>.
- */
-mxCollapseChange.prototype.execute = function()
-{
- this.collapsed = this.previous;
- this.previous = this.model.collapsedStateForCellChanged(
- this.cell, this.previous);
-};
-
-/**
- * Class: mxVisibleChange
- *
- * Action to change a cell's visible state in a model.
- *
- * Constructor: mxVisibleChange
- *
- * Constructs a change of a visible state in the
- * specified model.
- */
-function mxVisibleChange(model, cell, visible)
-{
- this.model = model;
- this.cell = cell;
- this.visible = visible;
- this.previous = visible;
-};
-
-/**
- * Function: execute
- *
- * Changes the visible state of <cell> to <previous> using
- * <mxGraphModel.visibleStateForCellChanged>.
- */
-mxVisibleChange.prototype.execute = function()
-{
- this.visible = this.previous;
- this.previous = this.model.visibleStateForCellChanged(
- this.cell, this.previous);
-};
-
-/**
- * Class: mxCellAttributeChange
- *
- * Action to change the attribute of a cell's user object.
- * There is no method on the graph model that uses this
- * action. To use the action, you can use the code shown
- * in the example below.
- *
- * Example:
- *
- * To change the attributeName in the cell's user object
- * to attributeValue, use the following code:
- *
- * (code)
- * model.beginUpdate();
- * try
- * {
- * var edit = new mxCellAttributeChange(
- * cell, attributeName, attributeValue);
- * model.execute(edit);
- * }
- * finally
- * {
- * model.endUpdate();
- * }
- * (end)
- *
- * Constructor: mxCellAttributeChange
- *
- * Constructs a change of a attribute of the DOM node
- * stored as the value of the given <mxCell>.
- */
-function mxCellAttributeChange(cell, attribute, value)
-{
- this.cell = cell;
- this.attribute = attribute;
- this.value = value;
- this.previous = value;
-};
-
-/**
- * Function: execute
- *
- * Changes the attribute of the cell's user object by
- * using <mxCell.setAttribute>.
- */
-mxCellAttributeChange.prototype.execute = function()
-{
- var tmp = this.cell.getAttribute(this.attribute);
-
- if (this.previous == null)
- {
- this.cell.value.removeAttribute(this.attribute);
- }
- else
- {
- this.cell.setAttribute(this.attribute, this.previous);
- }
-
- this.previous = tmp;
-};