package com.vci.client.workflow.editor;
|
|
import java.awt.BorderLayout;
|
import java.awt.event.ActionEvent;
|
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseMotionListener;
|
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelListener;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.util.List;
|
import java.util.Properties;
|
|
import javax.swing.AbstractAction;
|
import javax.swing.Action;
|
import javax.swing.BorderFactory;
|
import javax.swing.ImageIcon;
|
import javax.swing.JFrame;
|
import javax.swing.JLabel;
|
import javax.swing.JOptionPane;
|
import javax.swing.JPanel;
|
import javax.swing.JScrollPane;
|
import javax.swing.JSplitPane;
|
import javax.swing.SwingUtilities;
|
import javax.swing.UIManager;
|
|
import com.mxgraph.canvas.mxGraphics2DCanvas;
|
import com.mxgraph.layout.mxCircleLayout;
|
import com.mxgraph.layout.mxCompactTreeLayout;
|
import com.mxgraph.layout.mxEdgeLabelLayout;
|
import com.mxgraph.layout.mxIGraphLayout;
|
import com.mxgraph.layout.mxOrganicLayout;
|
import com.mxgraph.layout.mxParallelEdgeLayout;
|
import com.mxgraph.layout.mxPartitionLayout;
|
import com.mxgraph.layout.mxStackLayout;
|
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
|
import com.mxgraph.swing.mxGraphComponent;
|
import com.mxgraph.swing.mxGraphOutline;
|
import com.mxgraph.swing.handler.mxKeyboardHandler;
|
import com.mxgraph.swing.handler.mxRubberband;
|
import com.mxgraph.swing.util.mxMorphing;
|
import com.mxgraph.util.mxEvent;
|
import com.mxgraph.util.mxEventObject;
|
import com.mxgraph.util.mxEventSource.mxIEventListener;
|
import com.mxgraph.util.mxRectangle;
|
import com.mxgraph.util.mxResources;
|
import com.mxgraph.util.mxUndoManager;
|
import com.mxgraph.util.mxUndoableEdit;
|
import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
|
import com.mxgraph.view.mxGraph;
|
import com.vci.client.workflow.editor.shape.mxTaskShape;
|
import com.vci.client.workflow.editor.ui.FlowEditor;
|
import com.vci.client.workflow.editor.ui.TaskNewPanel;
|
import com.vci.client.workflow.template.object.ProcessCategoryObject;
|
import com.vci.client.workflow.template.object.ProcessDefinitionObject;
|
|
public abstract class BasicGraphEditor extends JPanel {
|
|
private static final long serialVersionUID = -2957233040496509650L;
|
|
/**
|
*
|
*/
|
protected mxGraphComponent graphComponent;
|
|
|
protected EditorPalette palette;
|
|
/**
|
*
|
*/
|
protected mxUndoManager undoManager;
|
|
/**
|
*
|
*/
|
protected JLabel statusBar;
|
|
/**
|
* Flag indicating whether the current graph has been modified
|
*/
|
protected boolean modified = false;
|
|
/**
|
*
|
*/
|
protected mxRubberband rubberband;
|
|
/**
|
*
|
*/
|
protected mxKeyboardHandler keyboardHandler;
|
|
private FlowEditor editor;
|
|
private Object deployPanel;
|
private String deployPanelFlag;
|
|
/**
|
*
|
*/
|
protected mxIEventListener undoHandler = new mxIEventListener() {
|
public void invoke(Object source, mxEventObject evt) {
|
undoManager.undoableEditHappened((mxUndoableEdit) evt
|
.getProperty("edit"));
|
}
|
};
|
|
/**
|
*
|
*/
|
protected mxIEventListener changeTracker = new mxIEventListener() {
|
public void invoke(Object source, mxEventObject evt) {
|
setModified(true);
|
}
|
};
|
|
/**
|
*
|
*/
|
public BasicGraphEditor(mxGraphComponent component)
|
{
|
mxGraphics2DCanvas.putShape("task", new mxTaskShape());
|
// Stores a reference to the graph and creates the command history
|
graphComponent = component;
|
final mxGraph graph = graphComponent.getGraph();
|
undoManager = createUndoManager();
|
|
// Do not change the scale and translation after files have been loaded
|
graph.setResetViewOnRootChange(false);
|
|
// Updates the modified flag if the graph model changes
|
graph.getModel().addListener(mxEvent.CHANGE, changeTracker);
|
|
// Adds the command history to the model and view
|
graph.getModel().addListener(mxEvent.UNDO, undoHandler);
|
graph.getView().addListener(mxEvent.UNDO, undoHandler);
|
|
// Keeps the selection in sync with the command history
|
mxIEventListener undoHandler = new mxIEventListener()
|
{
|
public void invoke(Object source, mxEventObject evt)
|
{
|
List<mxUndoableChange> changes = ((mxUndoableEdit) evt
|
.getProperty("edit")).getChanges();
|
graph.setSelectionCells(graph
|
.getSelectionCellsForChanges(changes));
|
}
|
};
|
|
undoManager.addListener(mxEvent.UNDO, undoHandler);
|
undoManager.addListener(mxEvent.REDO, undoHandler);
|
|
// Creates the outer split pane that contains the inner split pane and
|
// the graph component on the right side of the window
|
palette = getEditorPalette();
|
palette.setGraph(graphComponent.getGraph());
|
palette.setPreferredWidth(60);
|
|
final JScrollPane scrollPane = new JScrollPane(palette);
|
editor = new FlowEditor(this);
|
JSplitPane outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane, editor);
|
outer.setOneTouchExpandable(true);
|
outer.setDividerLocation(150);//原来是200
|
outer.setDividerSize(7);
|
|
// Creates the status bar
|
statusBar = createStatusBar();
|
|
// Display some useful information about repaint events
|
installRepaintListener();
|
|
// Puts everything together
|
setLayout(new BorderLayout());
|
add(outer, BorderLayout.CENTER);
|
add(statusBar, BorderLayout.SOUTH);
|
|
Properties properties = new Properties();
|
try {
|
ClassLoader cl = TaskNewPanel.class.getClassLoader();
|
InputStream in = cl.getResourceAsStream("flow-custom.properties");
|
properties.load(in);
|
deployPanelFlag = (String) properties.get("workflow.template");
|
if ("1".equals(deployPanelFlag)) {
|
//获取流程模板上的所有信息(修改流程模板)
|
deployPanel = new FlowDeployPanel(this);
|
} else if ("2".equals(deployPanelFlag)) {
|
//获取流程模板上的所有信息(修改流程模板)
|
deployPanel = new FlowDeployNewPanel(this);
|
}
|
} catch (IOException e) {
|
// TODO Auto-generated catch block
|
e.printStackTrace();
|
} catch (SecurityException e) {
|
// TODO Auto-generated catch block
|
e.printStackTrace();
|
} catch (IllegalArgumentException e) {
|
// TODO Auto-generated catch block
|
e.printStackTrace();
|
}
|
|
if ("1".equals(deployPanelFlag)) {
|
add((FlowDeployPanel)deployPanel, BorderLayout.NORTH);
|
} else if ("2".equals(deployPanelFlag)) {
|
add((FlowDeployNewPanel)deployPanel, BorderLayout.NORTH);
|
}
|
|
|
// Installs rubberband selection and handling for some special
|
// keystrokes such as F2, Control-C, -V, X, A etc.
|
installHandlers();
|
installListeners();
|
}
|
|
protected mxUndoManager createUndoManager() {
|
return new mxUndoManager();
|
}
|
|
/**
|
*
|
*/
|
protected void installHandlers()
|
{
|
rubberband = new mxRubberband(graphComponent);
|
keyboardHandler = new EditorKeyboardHandler(graphComponent);
|
}
|
|
/**
|
*
|
*/
|
protected JLabel createStatusBar()
|
{
|
JLabel statusBar = new JLabel(mxResources.get("ready"));
|
statusBar.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
|
|
return statusBar;
|
}
|
|
/**
|
*
|
*/
|
protected void installRepaintListener()
|
{
|
graphComponent.getGraph().addListener(mxEvent.REPAINT,
|
new mxIEventListener()
|
{
|
public void invoke(Object source, mxEventObject evt)
|
{
|
String buffer = (graphComponent.getTripleBuffer() != null) ? ""
|
: " (unbuffered)";
|
mxRectangle dirty = (mxRectangle) evt
|
.getProperty("region");
|
|
if (dirty == null)
|
{
|
status("Repaint all" + buffer);
|
}
|
else
|
{
|
status("Repaint: x=" + (int) (dirty.getX()) + " y="
|
+ (int) (dirty.getY()) + " w="
|
+ (int) (dirty.getWidth()) + " h="
|
+ (int) (dirty.getHeight()) + buffer);
|
}
|
}
|
});
|
}
|
|
public abstract EditorPalette getEditorPalette();
|
|
/**
|
*
|
*/
|
protected void mouseWheelMoved(MouseWheelEvent e) {
|
if (e.getWheelRotation() < 0) {
|
graphComponent.zoomIn();
|
} else {
|
graphComponent.zoomOut();
|
}
|
|
status(mxResources.get("scale") + ": "
|
+ (int) (100 * graphComponent.getGraph().getView().getScale())
|
+ "%");
|
}
|
|
protected void mouseLocationChanged(MouseEvent e) {
|
status(e.getX() + ", " + e.getY());
|
}
|
|
/**
|
*
|
*/
|
protected void installListeners()
|
{
|
// Installs mouse wheel listener for zooming
|
MouseWheelListener wheelTracker = new MouseWheelListener() {
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
if (e.getSource() instanceof mxGraphOutline
|
|| e.isControlDown()) {
|
BasicGraphEditor.this.mouseWheelMoved(e);
|
}
|
}
|
|
};
|
|
// Handles mouse wheel events in the outline and graph component
|
graphComponent.addMouseWheelListener(wheelTracker);
|
|
// Installs a mouse motion listener to display the mouse location
|
graphComponent.getGraphControl().addMouseMotionListener(
|
new MouseMotionListener()
|
{
|
|
/*
|
* (non-Javadoc)
|
* @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
|
*/
|
public void mouseDragged(MouseEvent e)
|
{
|
mouseLocationChanged(e);
|
}
|
|
/*
|
* (non-Javadoc)
|
* @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
|
*/
|
public void mouseMoved(MouseEvent e)
|
{
|
mouseDragged(e);
|
}
|
|
});
|
}
|
|
/**
|
*
|
* @param modified
|
*/
|
public void setModified(boolean modified) {
|
boolean oldValue = this.modified;
|
this.modified = modified;
|
|
firePropertyChange("modified", oldValue, modified);
|
|
}
|
|
/**
|
*
|
* @return whether or not the current graph has been modified
|
*/
|
public boolean isModified()
|
{
|
return modified;
|
}
|
|
/**
|
*
|
*/
|
public mxGraphComponent getGraphComponent()
|
{
|
return graphComponent;
|
}
|
|
/**
|
*
|
*/
|
public mxUndoManager getUndoManager()
|
{
|
return undoManager;
|
}
|
|
/**
|
*
|
* @param name
|
* @param action
|
* @return a new Action bound to the specified string name
|
*/
|
public Action bind(String name, final Action action)
|
{
|
return bind(name, action, null);
|
}
|
|
/**
|
*
|
* @param name
|
* @param action
|
* @return a new Action bound to the specified string name and icon
|
*/
|
@SuppressWarnings("serial")
|
public Action bind(String name, final Action action, String iconUrl)
|
{
|
ImageIcon imageIcon = null;
|
if(iconUrl != null)
|
{
|
imageIcon = new ImageIcon(
|
BasicGraphEditor.class.getResource(iconUrl));
|
}
|
|
|
AbstractAction abstractAction = new AbstractAction(name, imageIcon)
|
{
|
public void actionPerformed(ActionEvent e)
|
{
|
action.actionPerformed(new ActionEvent(getGraphComponent(), e
|
.getID(), e.getActionCommand()));
|
}
|
};
|
return abstractAction;
|
}
|
|
/**
|
*
|
* @param msg
|
*/
|
public void status(String msg)
|
{
|
statusBar.setText(msg);
|
}
|
|
/**
|
*
|
*/
|
public void exit()
|
{
|
JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
|
|
if (frame != null)
|
{
|
frame.dispose();
|
}
|
}
|
|
/**
|
*
|
*/
|
public void setLookAndFeel(String clazz)
|
{
|
JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
|
|
if (frame != null)
|
{
|
try
|
{
|
UIManager.setLookAndFeel(clazz);
|
SwingUtilities.updateComponentTreeUI(frame);
|
|
// Needs to assign the key bindings again
|
keyboardHandler = new EditorKeyboardHandler(graphComponent);
|
}
|
catch (Exception e1)
|
{
|
e1.printStackTrace();
|
}
|
}
|
}
|
|
/**
|
* Creates an action that executes the specified layout.
|
*
|
* @param key Key to be used for getting the label from mxResources and also
|
* to create the layout instance for the commercial graph editor example.
|
* @return an action that executes the specified layout
|
*/
|
@SuppressWarnings("serial")
|
public Action graphLayout(final String key, boolean animate)
|
{
|
final mxIGraphLayout layout = createLayout(key, animate);
|
|
if (layout != null)
|
{
|
return new AbstractAction(mxResources.get(key))
|
{
|
public void actionPerformed(ActionEvent e)
|
{
|
final mxGraph graph = graphComponent.getGraph();
|
Object cell = graph.getSelectionCell();
|
|
if (cell == null
|
|| graph.getModel().getChildCount(cell) == 0)
|
{
|
cell = graph.getDefaultParent();
|
}
|
|
graph.getModel().beginUpdate();
|
try
|
{
|
long t0 = System.currentTimeMillis();
|
layout.execute(cell);
|
status("Layout: " + (System.currentTimeMillis() - t0)
|
+ " ms");
|
}
|
finally
|
{
|
mxMorphing morph = new mxMorphing(graphComponent, 20,
|
1.2, 20);
|
|
morph.addListener(mxEvent.DONE, new mxIEventListener()
|
{
|
|
public void invoke(Object sender, mxEventObject evt)
|
{
|
graph.getModel().endUpdate();
|
}
|
|
});
|
|
morph.startAnimation();
|
}
|
|
}
|
|
};
|
}
|
else
|
{
|
return new AbstractAction(mxResources.get(key))
|
{
|
|
public void actionPerformed(ActionEvent e)
|
{
|
JOptionPane.showMessageDialog(graphComponent,
|
mxResources.get("noLayout"));
|
}
|
|
};
|
}
|
}
|
|
/**
|
* Creates a layout instance for the given identifier.
|
*/
|
protected mxIGraphLayout createLayout(String ident, boolean animate)
|
{
|
mxIGraphLayout layout = null;
|
|
if (ident != null)
|
{
|
mxGraph graph = graphComponent.getGraph();
|
|
if (ident.equals("verticalHierarchical"))
|
{
|
layout = new mxHierarchicalLayout(graph);
|
}
|
else if (ident.equals("horizontalHierarchical"))
|
{
|
layout = new mxHierarchicalLayout(graph, JLabel.WEST);
|
}
|
else if (ident.equals("verticalTree"))
|
{
|
layout = new mxCompactTreeLayout(graph, false);
|
}
|
else if (ident.equals("horizontalTree"))
|
{
|
layout = new mxCompactTreeLayout(graph, true);
|
}
|
else if (ident.equals("parallelEdges"))
|
{
|
layout = new mxParallelEdgeLayout(graph);
|
}
|
else if (ident.equals("placeEdgeLabels"))
|
{
|
layout = new mxEdgeLabelLayout(graph);
|
}
|
else if (ident.equals("organicLayout"))
|
{
|
layout = new mxOrganicLayout(graph);
|
}
|
if (ident.equals("verticalPartition"))
|
{
|
layout = new mxPartitionLayout(graph, false)
|
{
|
/**
|
* Overrides the empty implementation to return the size of the
|
* graph control.
|
*/
|
public mxRectangle getContainerSize()
|
{
|
return graphComponent.getLayoutAreaSize();
|
}
|
};
|
}
|
else if (ident.equals("horizontalPartition"))
|
{
|
layout = new mxPartitionLayout(graph, true)
|
{
|
/**
|
* Overrides the empty implementation to return the size of the
|
* graph control.
|
*/
|
public mxRectangle getContainerSize()
|
{
|
return graphComponent.getLayoutAreaSize();
|
}
|
};
|
}
|
else if (ident.equals("verticalStack"))
|
{
|
layout = new mxStackLayout(graph, false)
|
{
|
/**
|
* Overrides the empty implementation to return the size of the
|
* graph control.
|
*/
|
public mxRectangle getContainerSize()
|
{
|
return graphComponent.getLayoutAreaSize();
|
}
|
};
|
}
|
else if (ident.equals("horizontalStack"))
|
{
|
layout = new mxStackLayout(graph, true)
|
{
|
/**
|
* Overrides the empty implementation to return the size of the
|
* graph control.
|
*/
|
public mxRectangle getContainerSize()
|
{
|
return graphComponent.getLayoutAreaSize();
|
}
|
};
|
}
|
else if (ident.equals("circleLayout"))
|
{
|
layout = new mxCircleLayout(graph);
|
}
|
}
|
|
return layout;
|
}
|
|
public FlowEditor getEditor() {
|
return editor;
|
}
|
|
public Object getDeployPanel() {
|
return deployPanel;
|
}
|
|
public String getDeployPanelFlag() {
|
return deployPanelFlag;
|
}
|
|
public void setFlowCategory(ProcessCategoryObject flowCategory) {
|
if ("1".equals(deployPanelFlag)) {
|
((FlowDeployPanel)deployPanel).setFlowCategory(flowCategory);
|
} else if ("2".equals(deployPanelFlag)) {
|
((FlowDeployNewPanel)deployPanel).setFlowCategory(flowCategory);
|
}
|
}
|
|
public void setProcessDefinition(ProcessDefinitionObject selectedObj) throws Exception {
|
if ("1".equals(deployPanelFlag)) {
|
((FlowDeployPanel)deployPanel).setProcessDefinition(selectedObj);
|
} else if ("2".equals(deployPanelFlag)) {
|
((FlowDeployNewPanel)deployPanel).setProcessDefinition(selectedObj);
|
}
|
}
|
|
/**
|
* 模板导入时调用
|
* @param graphXml
|
* @param processXml
|
* @throws Exception
|
*/
|
public void setProcessDefinition(byte[] graphXml, byte[] processXml,ProcessDefinitionObject pd,byte[] objectXml ) throws Exception {
|
if ("1".equals(deployPanelFlag)) {
|
((FlowDeployPanel)deployPanel).setProcessDefinition(graphXml,processXml,pd,objectXml);
|
} else if ("2".equals(deployPanelFlag)) {
|
((FlowDeployNewPanel)deployPanel).setProcessDefinition(graphXml,processXml,pd,objectXml);
|
}
|
}
|
|
}
|