/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.gd.common.editor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.jbpm.gd.common.model.NamedElement;
import org.jbpm.gd.common.model.SemanticElement;
import org.jbpm.gd.common.notation.AbstractNodeContainer;
import org.jbpm.gd.common.notation.BendPoint;
import org.jbpm.gd.common.notation.Edge;
import org.jbpm.gd.common.notation.Node;
import org.jbpm.gd.common.notation.NodeContainer;
import org.jbpm.gd.common.notation.NotationElement;
import org.jbpm.gd.common.notation.NotationMapping;
import org.jbpm.gd.common.notation.RootContainer;
import org.jbpm.gd.jpdl.Logger;
public abstract class AbstractContentProvider implements ContentProvider{
protected abstract SemanticElement getEdgeSemanticElement(Node node, Element notationInfo, int index);
protected abstract SemanticElement getNodeSemanticElement(NodeContainer node, Element notationInfo, int index);
protected abstract void addNodes(NodeContainer nodeContainer, Element notationInfo);
protected abstract void addEdges(Node node, Element notationInfo);
protected abstract SemanticElement findDestination(Edge edge, Node source);
protected String getRootNotationInfoElement() {
return "<root-container/>";
}
protected String createInitialNotationInfo() {
StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("\n\n");
buffer.append(getRootNotationInfoElement());
return buffer.toString();
}
public String getNotationInfoFileName(String semanticInfoFileName) {
return ".gpd." + semanticInfoFileName;
}
public String getDiagramImageFileName(String semanticInfoFileName) {
String result;
int index = semanticInfoFileName.indexOf(".xml");
result = index > -1 ? semanticInfoFileName.substring(0, index) : semanticInfoFileName;
return result + ".jpg";
}
protected void processRootContainer(RootContainer rootContainer, Element notationInfo) {
addDimension(rootContainer, notationInfo);
addNodes(rootContainer, notationInfo);
postProcess(rootContainer);
}
protected void addNodes(NodeContainer nodeContainer, SemanticElement[] semanticElements, Element notationInfo) {
List notationInfoElements = notationInfo == null ? new ArrayList() : notationInfo.elements();
for (int i = 0; i < semanticElements.length; i++) {
Element notationInfoElement = null;
String nodeName = ((NamedElement)semanticElements[i]).getName();
for (int j = 0; j < notationInfoElements.size(); j++) {
Element element = (Element)notationInfoElements.get(j);
String elementName = element.attributeValue("name");
if ((elementName != null && elementName.equals(nodeName)) || (elementName == null && nodeName == null)) {
notationInfoElement = element;
}
}
// if (notationInfoElements.size() >= i + 1) {
// notationInfoElement = (Element)notationInfoElements.get(i);
// }
addNode(nodeContainer, semanticElements[i], notationInfoElement);
}
}
protected void addEdges(Node node, SemanticElement[] semanticElements, Element notationInfo) {
List notationInfoElements = notationInfo == null ? new ArrayList() : notationInfo.elements();
for (int i = 0; i < semanticElements.length; i++) {
Element notationInfoElement = null;
if (notationInfoElements.size() >= i + 1) {
notationInfoElement = (Element)notationInfoElements.get(i);
}
addEdge(node, semanticElements[i], notationInfoElement);
}
}
protected void addNode(NodeContainer nodeContainer, SemanticElement semanticElement, Element notationInfoElement) {
String notationElementId = NotationMapping.getNotationElementId(semanticElement.getElementId());
Node notationElement = (Node)nodeContainer.getFactory().create(notationElementId);
notationElement.setSemanticElement(semanticElement);
notationElement.register();
nodeContainer.addNode(notationElement);
semanticElement.addPropertyChangeListener(notationElement);
processNode(notationElement, notationInfoElement);
if (notationElement instanceof NodeContainer) {
addNodes((NodeContainer)notationElement, notationInfoElement);
}
}
protected void addEdge(Node node, SemanticElement semanticElement, Element notationInfoElement) {
NotationElement notationElement = node.getRegisteredNotationElementFor(semanticElement);
if (notationElement == null) {
String notationElementId = NotationMapping.getNotationElementId(semanticElement.getElementId());
notationElement = (NotationElement)node.getFactory().create(notationElementId);
notationElement.setSemanticElement(semanticElement);
notationElement.register();
node.addLeavingEdge((Edge)notationElement);
semanticElement.addPropertyChangeListener(notationElement);
}
processEdge((Edge)notationElement, notationInfoElement);
}
protected void addDimension(
RootContainer processDefinitionNotationElement,
Element processDiagramInfo) {
String width = processDiagramInfo.attributeValue("width");
String height = processDiagramInfo.attributeValue("height");
Dimension dimension = new Dimension(
width == null ? 0 : Integer.valueOf(width).intValue(),
height == null ? 0 : Integer.valueOf(height).intValue());
processDefinitionNotationElement.setDimension(dimension);
}
protected void processNode(Node node, Element notationInfoElement) {
addConstraint(node, notationInfoElement);
addEdges(node, notationInfoElement);
}
protected void processEdge(Edge edge, Element edgeInfo) {
processLabel(edge, edgeInfo);
addBendpoints(edge, edgeInfo);
}
protected void addBendpoints(Edge edge, Element edgeInfo) {
if (edgeInfo != null) {
List list = edgeInfo.elements("bendpoint");
for (int i = 0; i < list.size(); i++) {
addBendpoint(edge, (Element)list.get(i), i);
}
}
}
protected BendPoint addBendpoint(Edge edge, Element bendpointInfo, int index) {
BendPoint result = new BendPoint();
processBendpoint(result, bendpointInfo);
edge.addBendPoint(result);
return result;
}
protected void processBendpoint(BendPoint bendPoint, Element bendpointInfo) {
int w1 = Integer.valueOf(bendpointInfo.attributeValue("w1")).intValue();
int h1 = Integer.valueOf(bendpointInfo.attributeValue("h1")).intValue();
int w2 = Integer.valueOf(bendpointInfo.attributeValue("w2")).intValue();
int h2 = Integer.valueOf(bendpointInfo.attributeValue("h2")).intValue();
Dimension d1 = new Dimension(w1, h1);
Dimension d2 = new Dimension(w2, h2);
bendPoint.setRelativeDimensions(d1, d2);
}
private void processLabel(Edge edge, Element edgeInfo) {
Element label = null;
if (edgeInfo != null) {
label = edgeInfo.element("label");
}
if (label != null) {
Point offset = new Point();
offset.x = Integer.valueOf(label.attributeValue("x")).intValue();
offset.y = Integer.valueOf(label.attributeValue("y")).intValue();
edge.getLabel().setOffset(offset);
}
}
private void addConstraint(Node node, Element nodeInfo) {
Rectangle constraint = node.getConstraint().getCopy();
Dimension initialDimension = NotationMapping.getInitialDimension(node.getSemanticElement().getElementId());
if (initialDimension != null) {
constraint.setSize(initialDimension);
}
if (nodeInfo != null) {
constraint.x = Integer.valueOf(nodeInfo.attributeValue("x")).intValue();
constraint.y = Integer.valueOf(nodeInfo.attributeValue("y")).intValue();
constraint.width = Integer.valueOf(nodeInfo.attributeValue("width")).intValue();
constraint.height = Integer.valueOf(nodeInfo.attributeValue("height")).intValue();
}
node.setConstraint(constraint);
}
protected void postProcess(NodeContainer nodeContainer) {
List nodes = nodeContainer.getNodes();
for (int i = 0; i < nodes.size(); i++) {
Node node = (Node)nodes.get(i);
List edges = node.getLeavingEdges();
for (int j = 0; j < edges.size(); j++) {
Edge edge = (Edge)edges.get(j);
SemanticElement destination = findDestination(edge, node);
Node target = (Node)edge.getFactory().getRegisteredNotationElementFor(destination);
if (target != null && edge.getTarget() == null) {
target.addArrivingEdge(edge);
}
}
if (node instanceof NodeContainer) {
postProcess((NodeContainer)node);
}
}
}
public boolean saveToInput(
IEditorInput input,
RootContainer rootContainer) {
boolean result = true;
try {
IFile file = getNotationInfoFile(((IFileEditorInput)input).getFile());
InputStreamReader reader = new InputStreamReader(file.getContents());
Element notationInfo = new SAXReader().read(reader).getRootElement();
if (upToDateCheck(notationInfo)) {
getNotationInfoFile(((IFileEditorInput)input).getFile()).setContents(
new ByteArrayInputStream(toNotationInfoXml(rootContainer).getBytes()), true, true, null);
} else {
result = false;
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
protected String toNotationInfoXml(RootContainer rootContainer) {
StringWriter writer = new StringWriter();
write(rootContainer, writer);
return writer.toString();
}
protected void write(
RootContainer rootContainer, Writer writer) {
try {
Document document = DocumentHelper.createDocument();
Element root = document.addElement("root-container");
write(rootContainer, root);
XMLWriter xmlWriter = new XMLWriter(writer, OutputFormat.createPrettyPrint());
xmlWriter.write(document);
} catch (IOException e) {
e.printStackTrace(new PrintWriter(writer));
}
}
protected void write(
RootContainer rootContainer,
Element element) {
addAttribute(element, "name", ((NamedElement)rootContainer.getSemanticElement()).getName());
addAttribute(element, "width", Integer.toString(rootContainer.getDimension().width));
addAttribute(element, "height", Integer.toString(rootContainer.getDimension().height));
Iterator iter = rootContainer.getNodes().iterator();
while (iter.hasNext()) {
write((Node) iter.next(), element);
}
}
protected void write(Node node, Element element) {
Element newElement = null;
if (node instanceof AbstractNodeContainer) {
newElement = addElement(element, "node-container");
} else {
newElement = addElement(element, "node");
}
addAttribute(newElement, "name", ((NamedElement)node.getSemanticElement()).getName());
addAttribute(newElement, "x", String.valueOf(node.getConstraint().x));
addAttribute(newElement, "y", String.valueOf(node.getConstraint().y));
addAttribute(newElement, "width", String.valueOf(node.getConstraint().width));
addAttribute(newElement, "height", String.valueOf(node.getConstraint().height));
if (node instanceof AbstractNodeContainer) {
Iterator nodes = ((AbstractNodeContainer)node).getNodes().iterator();
while (nodes.hasNext()) {
write((Node)nodes.next(), newElement);
}
}
Iterator edges = node.getLeavingEdges().iterator();
while (edges.hasNext()) {
Edge edge = (Edge) edges.next();
write(edge, addElement(newElement, "edge"));
}
}
protected void write(Edge edge,
Element element) {
Point offset = edge.getLabel().getOffset();
if (offset != null) {
Element label = addElement(element, "label");
addAttribute(label, "x", String.valueOf(offset.x));
addAttribute(label, "y", String.valueOf(offset.y));
}
Iterator bendpoints = edge.getBendPoints().iterator();
while (bendpoints.hasNext()) {
write((BendPoint) bendpoints.next(), addElement(element, "bendpoint"));
}
}
protected void write(BendPoint bendpoint, Element bendpointElement) {
addAttribute(bendpointElement, "w1", String.valueOf(bendpoint
.getFirstRelativeDimension().width));
addAttribute(bendpointElement, "h1", String.valueOf(bendpoint
.getFirstRelativeDimension().height));
addAttribute(bendpointElement, "w2", String.valueOf(bendpoint
.getSecondRelativeDimension().width));
addAttribute(bendpointElement, "h2", String.valueOf(bendpoint
.getSecondRelativeDimension().height));
}
protected Element addElement(Element element, String elementName) {
Element newElement = element.addElement(elementName);
return newElement;
}
protected void addAttribute(Element e, String attributeName,
String value) {
if (value != null) {
e.addAttribute(attributeName, value);
}
}
private void createNotationInfoFile(IFile notationInfoFile) {
try {
notationInfoFile.create(new ByteArrayInputStream(createInitialNotationInfo().toString().getBytes()), true, null);
} catch (CoreException e) {
Logger.logError(e);
}
}
protected IFile getNotationInfoFile(IFile semanticInfoFile) {
IProject project = semanticInfoFile.getProject();
IPath semanticInfoPath = semanticInfoFile.getProjectRelativePath();
IPath notationInfoPath = semanticInfoPath.removeLastSegments(1).append(getNotationInfoFileName(semanticInfoFile.getName()));
IFile notationInfoFile = project.getFile(notationInfoPath);
if (!notationInfoFile.exists()) {
createNotationInfoFile(notationInfoFile);
}
return notationInfoFile;
}
public void addNotationInfo(RootContainer rootContainer, IEditorInput input) {
try {
IFile file = getNotationInfoFile(((FileEditorInput)input).getFile());
if (file.exists()) {
InputStreamReader reader = new InputStreamReader(file.getContents());
Element notationInfo = new SAXReader().read(reader).getRootElement();
boolean changed = convertCheck(notationInfo);
processRootContainer(rootContainer, notationInfo);
if (changed) {
file.setContents(new ByteArrayInputStream(toNotationInfoXml(rootContainer).getBytes()), true, true, null);
}
} else {
file.create(new ByteArrayInputStream(createInitialNotationInfo().toString().getBytes()), true, null);
}
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (CoreException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private boolean convertCheck(Element notationInfo) {
boolean changed = false;
if ("process-diagram".equals(notationInfo.getName()) || "pageflow-diagram".equals(notationInfo.getName())) {
MessageDialog dialog = new MessageDialog(
null,
"Convert To 3.1.x Format",
null,
"A file created with an older GPD version was detected. " +
"If you open this file it will be converted to the 3.1.x " +
"format and overwritten.\n" +
"Do you want to continue?",
MessageDialog.QUESTION,
new String[] {"Convert And Open", "Continue Without Converting"},
0);
if (dialog.open() == 0) {
convertToRootContainer(notationInfo);
changed = true;
}
}
return changed;
}
private boolean upToDateCheck(Element notationInfo) {
if ("process-diagram".equals(notationInfo.getName()) || "pageflow-diagram".equals(notationInfo.getName())) {
MessageDialog dialog = new MessageDialog(
null,
"GPD 3.0.x Format Detected",
null,
"The file you are trying to save contains GPD 3.0.x information." +
"Saving the file will result in an automatic conversion into the 3.1.x format." +
"It will be impossible to open it with the old GPD.\n" +
"Do you want to continue?",
MessageDialog.QUESTION,
new String[] {"Save And Convert", "Cancel"},
0);
return dialog.open() == 0;
}
return true;
}
private void convertToRootContainer(Element notationInfo) {
notationInfo.setName("root-container");
convertChildrenToEdge(notationInfo);
}
private void convertChildrenToEdge(Element element) {
List list = element.elements();
for (int i = 0; i < list.size(); i++) {
convertToEdge((Element)list.get(i));
}
}
private void convertToEdge(Element element) {
if ("transition".equals(element.getName())) {
element.setName("edge");
}
convertChildrenToEdge(element);
}
}