/*
* $Id: JGraphAdapterModel.java,v 1.1.1.1 2005/08/06 05:26:45 gaudenz Exp $
*
* Copyright (c) 2001-2005, Gaudenz Alder
*
* See LICENSE file in distribution for licensing details of this source file
*/
package com.jgraph.example.adapter;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.undo.UndoableEdit;
import org.jgraph.graph.AttributeMap;
import org.jgraph.graph.ConnectionSet;
import org.jgraph.graph.DefaultGraphModel;
import org.jgraph.graph.ParentMap;
/**
* Maps from business objects to cells and manages prototypes to create new cells
* on the fly.
* Maps from userobjects to cells and manages cell prototypes.
*/
public class JGraphAdapterModel extends DefaultGraphModel {
public static final String VERSION = "@NAME@ (v@VERSION@)";
/**
* A store of the mapping between model cells and back-end objects
*/
protected Map mapping = new Hashtable();
/**
* The current back-end logic object
*/
protected JGraphAdapterBackend backend;
public JGraphAdapterModel() {
super();
}
/**
* @param roots
* @param attributes
*/
public JGraphAdapterModel(List roots, AttributeMap attributes) {
this(roots, attributes, null);
}
/**
* @param roots
* @param attributes
*/
public JGraphAdapterModel(List roots, AttributeMap attributes,
JGraphAdapterBackend backend) {
super(roots, attributes);
this.backend = backend;
}
public void addProperty(Object cell, Object key, Object value) {
if (key != null && value != null) {
Object userObj = getValue(cell);
JGraphBusinessObject bo = (JGraphBusinessObject) userObj;
bo.putProperty(key, value);
cellsChanged(new Object[] { cell });
}
}
protected Map handleAttributes(Map attributes) {
Map undo = super.handleAttributes(attributes);
if (attributes != null) {
if (undo == null)
undo = new Hashtable();
Iterator it = attributes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object cell = entry.getKey();
Map properties = (Map) entry.getValue();
if (cell instanceof JGraphBusinessObject) {
JGraphBusinessObject bo = (JGraphBusinessObject) cell;
Map deltaOld = new Hashtable();
Iterator it2 = properties.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry property = (Map.Entry) it2.next();
Object key = property.getKey();
Object oldValue = bo.putProperty(key, property
.getValue());
if (oldValue != null)
deltaOld.put(key, oldValue);
}
undo.put(cell, deltaOld);
}
}
}
return undo;
}
/**
* @return Returns the backend.
*/
public JGraphAdapterBackend getBackend() {
return backend;
}
/**
* @param backend
* The backend to set.
*/
public void setBackend(JGraphAdapterBackend backend) {
this.backend = backend;
}
/**
*
* @param obj
* @return the object that the specified object maps to
*/
public Object getMapping(Object obj) {
return mapping.get(obj);
}
/**
*
* @param obj
* @param cell
*/
protected void putMapping(Object obj, Object cell) {
mapping.put(obj, cell);
}
/**
*
* @param obj
*/
protected void removeMapping(Object obj) {
mapping.remove(obj);
}
/**
*
* @param child
* @return the user object associated with the parent of the specified child
*/
public Object getParentUserObject(Object child) {
return getValue(getParent(child));
}
/**
*
* @param edge
* @return the user object associated with the vertex connected to the source end of this edge
*/
public Object getSourceVertexUserObject(Object edge) {
Object cell = DefaultGraphModel.getSourceVertex(this, edge);
return getValue(cell);
}
/**
*
* @param edge
* @return the user object associated with the vertex connected to the target end of this edge
*/
public Object getTargetVertexUserObject(Object edge) {
Object cell = DefaultGraphModel.getTargetVertex(this, edge);
return getValue(cell);
}
/*
* (non-Javadoc)
*
* @see org.jgraph.graph.GraphModel#edit(java.util.Map,
* org.jgraph.graph.ConnectionSet, org.jgraph.graph.ParentMap,
* javax.swing.undo.UndoableEdit[])
*/
public void edit(Map attributes, ConnectionSet cs, ParentMap pm,
UndoableEdit[] edits) {
if ((attributes != null && !attributes.isEmpty())
|| (cs != null && !cs.isEmpty())) {
try {
// Call source / targetChanged
processConnectionSet(cs, true);
processParentMap(pm, true);
processNestedAttributes(attributes, true);
super.edit(attributes, cs, pm, edits);
} catch (Exception e) {
e.printStackTrace();
}
} else {
super.edit(attributes, cs, pm, edits);
}
}
protected Object cloneUserObject(Object userObject) {
if (userObject instanceof JGraphBusinessObject)
return ((JGraphBusinessObject) userObject).clone();
return super.cloneUserObject(userObject);
}
public Object valueForCellChanged(Object cell, Object newValue) {
Object userObject = getValue(cell);
if (userObject instanceof JGraphBusinessObject
&& newValue instanceof String) {
JGraphBusinessObject user = (JGraphBusinessObject) userObject;
Object oldLabel = user.getValue();
user.setValue(newValue);
return oldLabel;
} else
return super.valueForCellChanged(cell, newValue);
}
/*
* (non-Javadoc)
*
* @see org.jgraph.graph.GraphModel#insert(java.lang.Object[],
* java.util.Map, org.jgraph.graph.ConnectionSet,
* org.jgraph.graph.ParentMap, javax.swing.undo.UndoableEdit[])
*/
public void insert(Object[] cells, Map attributes, ConnectionSet cs,
ParentMap pm, UndoableEdit[] edits) {
if (cells != null || attributes != null || cs != null) {
try {
processInsert(cells, attributes, cs, pm, true);
super.insert(cells, attributes, cs, pm, edits);
} catch (Exception e) {
e.printStackTrace();
}
} else {
super.insert(cells, attributes, cs, pm, edits);
}
}
/*
* (non-Javadoc)
*
* @see org.jgraph.graph.GraphModel#remove(java.lang.Object[])
*/
public void remove(Object[] cells) {
if (cells != null) {
try {
processRemove(cells, true);
super.remove(cells);
} catch (Exception e) {
e.printStackTrace();
}
} else {
super.remove(cells);
}
}
/*
* (non-Javadoc)
*
* @see org.jgraph.graph.GraphModel#insert(java.lang.Object[],
* java.util.Map, org.jgraph.graph.ConnectionSet,
* org.jgraph.graph.ParentMap, javax.swing.undo.UndoableEdit[])
*/
public void processInsert(Object[] cells, Map attributes, ConnectionSet cs,
ParentMap pm, boolean validate) throws Exception {
if (cells != null || attributes != null || cs != null) {
if (cells != null) {
// Vertices in the first run (so they have an ID)
for (int i = 0; i < cells.length; i++) {
if (!isPort(cells[i])) {
if (!isEdge(cells[i])) {
fireVertexAdded(cells[i], validate);
if (!validate)
putMapping(getValue(cells[i]), cells[i]);
}
}
}
// Edges in the second run
for (int i = 0; i < cells.length; i++) {
if (!isPort(cells[i])) {
if (isEdge(cells[i]) && cs != null) {
fireEdgeAdded(cells[i],
cs.getPort(cells[i], false), cs.getPort(
cells[i], true), validate);
if (!validate)
putMapping(getValue(cells[i]), cells[i]);
}
}
}
}
processConnectionSet(cs, validate);
processParentMap(pm, validate);
processNestedAttributes(attributes, validate);
}
}
protected void processRemove(Object[] cells, boolean validate)
throws Exception {
if (cells != null) {
for (int i = 0; i < cells.length; i++) {
if (!isPort(cells[i])) {
fireCellRemoved(cells[i], validate);
if (!validate)
removeMapping(getValue(cells[i]));
}
}
}
}
/**
*
* @param cs
* @param validate
* @throws Exception
*/
protected void processConnectionSet(ConnectionSet cs, boolean validate)
throws Exception {
if (cs != null) {
Iterator it = cs.connections();
while (it.hasNext()) {
ConnectionSet.Connection conn = (ConnectionSet.Connection) it
.next();
Object edge = conn.getEdge();
if (contains(edge)) {
if (conn.isSource()) {
fireSourceChanged(edge, conn.getPort(), validate);
} else {
fireTargetChanged(edge, conn.getPort(), validate);
}
}
}
}
}
/**
*
* @param pm
* @param validate
* @throws Exception
*/
protected void processParentMap(ParentMap pm, boolean validate)
throws Exception {
if (pm != null) {
Iterator it = pm.entries();
while (it.hasNext()) {
ParentMap.Entry entry = (ParentMap.Entry) it.next();
Object parent = entry.getParent();
Object child = entry.getChild();
if (contains(child)) {
fireParentChanged(child, parent, validate);
}
}
}
}
/**
*
* @param nested
* @param validate
* @throws Exception
*/
protected void processNestedAttributes(Map nested, boolean validate)
throws Exception {
if (nested != null) {
Iterator it = nested.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object cell = entry.getKey();
if (!isPort(cell)) { // TODO: Remove isPort check
Map change = (Map) entry.getValue();
fireAttributesChanged(cell, change, validate);
}
}
}
}
// Override parent method to hook the backend into the execute method.
protected GraphModelEdit createEdit(Object[] inserted, Object[] removed,
Map attributes, ConnectionSet cs, ParentMap pm) {
return new BusinessModelEdit(inserted, removed, attributes, cs, pm);
}
public class BusinessModelEdit extends GraphModelEdit {
protected boolean inProgress = false;
/**
* @param inserted
* @param removed
* @param attributes
* @param connectionSet
* @param parentMap
*/
public BusinessModelEdit(Object[] inserted, Object[] removed,
Map attributes, ConnectionSet connectionSet, ParentMap parentMap) {
super(inserted, removed, attributes, connectionSet, parentMap);
}
/*
* (non-Javadoc)
*
* @see org.jgraph.event.GraphModelEvent.ExecutableGraphChange#execute()
*/
public void execute() {
super.execute();
try {
if (!inProgress) {
inProgress = true;
processRemove(insert, false);
processInsert(remove, previousAttributes,
previousConnectionSet, previousParentMap, false);
fireCommit();
}
} catch (Exception e) {
e.printStackTrace();
try {
fireRollback();
undo();
} catch (Exception e1) {
e1.printStackTrace();
}
} finally {
inProgress = false;
}
}
}
/**
*
* @throws Exception
*/
public void fireCommit() throws Exception {
if (backend != null)
backend.commit();
}
/**
*
* @throws Exception
*/
public void fireRollback() throws Exception {
if (backend != null)
backend.rollback();
}
/**
*
* @param vertex
* @param validate
* @throws Exception
*/
public void fireVertexAdded(Object vertex, boolean validate)
throws Exception {
if (backend != null)
backend.vertexAdded(this, vertex, validate);
}
/**
*
* @param edge
* @param source
* @param target
* @param validate
* @throws Exception
*/
public void fireEdgeAdded(Object edge, Object source, Object target,
boolean validate) throws Exception {
if (backend != null)
backend.edgeAdded(this, edge, source, target, validate);
}
/**
*
* @param object
* @param validate
* @throws Exception
*/
public void fireCellRemoved(Object object, boolean validate)
throws Exception {
if (backend != null)
backend.cellRemoved(this, object, validate);
}
/**
*
* @param child
* @param parent
* @param validate
* @throws Exception
*/
public void fireParentChanged(Object child, Object parent, boolean validate)
throws Exception {
if (backend != null)
backend.parentChanged(this, child, parent, validate);
}
/**
*
* @param edge
* @param source
* @param validate
* @throws Exception
*/
public void fireSourceChanged(Object edge, Object source, boolean validate)
throws Exception {
if (backend != null)
backend.sourceChanged(this, edge, source, validate);
}
/**
*
* @param edge
* @param target
* @param validate
* @throws Exception
*/
public void fireTargetChanged(Object edge, Object target, boolean validate)
throws Exception {
if (backend != null)
backend.targetChanged(this, edge, target, validate);
}
/**
*
* @param cell
* @param change
* @param validate
* @throws Exception
*/
public void fireAttributesChanged(Object cell, Map change, boolean validate)
throws Exception {
if (backend != null)
backend.attributesChanged(this, cell, change, validate);
}
}