Commits

Anonymous committed 69619d0

Initial import from SourceForge

Comments (0)

Files changed (3)

src/designer/com/opensymphony/workflow/designer/WorkflowDesigner.java

+package com.opensymphony.workflow.designer;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.swing.*;
+
+import com.jgraph.event.GraphSelectionEvent;
+import com.jgraph.event.GraphSelectionListener;
+import com.jgraph.graph.GraphModel;
+import com.opensymphony.workflow.FactoryException;
+import com.opensymphony.workflow.config.WorkspaceManager;
+import com.opensymphony.workflow.designer.actions.*;
+import com.opensymphony.workflow.designer.editor.*;
+import com.opensymphony.workflow.designer.swing.CardPanel;
+import com.opensymphony.workflow.designer.swing.EmptyBorderSplitPane;
+import com.opensymphony.workflow.designer.swing.FramePanel;
+import com.opensymphony.workflow.loader.WorkflowDescriptor;
+import com.opensymphony.workflow.loader.Workspace;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Hani Suleiman (hani@formicary.net)
+ * Date: May 15, 2003
+ * Time: 8:36:20 PM
+ */
+public class WorkflowDesigner extends JFrame implements GraphSelectionListener
+{
+  private static final Log log = LogFactory.getLog(WorkflowDesigner.class);
+
+  public static final String WORKSPACE_SUFFIX = ".wsf";
+
+  private Navigator navigator;
+  private WorkspaceManager manager = new WorkspaceManager();
+  private JTabbedPane graphTabs = new JTabbedPane();
+  // Current WorkSpace File
+  private List graphs = new ArrayList();
+  private List mlayout = new ArrayList();
+  private JSplitPane mainSplitPane;
+  private EmptyBorderSplitPane leftSplitPane;
+  private CardPanel detailPanel = new CardPanel();
+  private FramePanel detailFramePanel;
+  public static WorkflowDesigner INSTANCE = null;
+
+  public WorkflowDesigner()
+  {
+    super("OSWorkflow Designer");
+    INSTANCE = this;
+    navigator = new Navigator(this);
+    setAppMenu();
+    detailFramePanel = new FramePanel("Details", false);
+    detailFramePanel.setContent(detailPanel);
+
+    FramePanel flowsPanel = new FramePanel("Workspace", false);
+    flowsPanel.setContent(new JScrollPane(navigator));
+    leftSplitPane = new EmptyBorderSplitPane(JSplitPane.VERTICAL_SPLIT, flowsPanel, detailFramePanel);
+    mainSplitPane = new EmptyBorderSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSplitPane, graphTabs);
+    mainSplitPane.setDividerLocation(Prefs.INSTANCE.getInt(Prefs.MAIN_DIVIDER_LOCATION, 150));
+    leftSplitPane.setDividerLocation(Prefs.INSTANCE.getInt(Prefs.DETAIL_DIVIDER_LOCATION, 150));
+    //Provide a preferred size for the split pane
+    String bounds = Prefs.INSTANCE.get(Prefs.DESIGNER_BOUNDS, "100, 100, 800, 600");
+    StringTokenizer tok = new StringTokenizer(bounds, ",");
+    int x = Integer.parseInt(tok.nextToken().trim());
+    int y = Integer.parseInt(tok.nextToken().trim());
+    int w = Integer.parseInt(tok.nextToken().trim());
+    int h = Integer.parseInt(tok.nextToken().trim());
+    setLocation(x, y);
+    getContentPane().add(mainSplitPane);
+    mainSplitPane.setPreferredSize(new Dimension(w, h));
+
+    addWindowListener(new WindowAdapter()
+    {
+      public void windowClosing(WindowEvent evt)
+      {
+        quit();
+      }
+    });
+    String lastOpened = Prefs.INSTANCE.get(Prefs.LAST_WORKSPACE, null);
+    if(lastOpened != null)
+    {
+      openWorkspace(new File(lastOpened));
+      String workflow = Prefs.INSTANCE.get(Prefs.WORKFLOW_CURRENT, null);
+      if(workflow != null)
+      {
+        navigator.selectWorkflow(workflow);
+      }
+    }
+  }
+
+  public WorkflowGraph getCurrentGraph()
+  {
+    int index = graphTabs.getSelectedIndex();
+    if(index == -1 || index >= graphs.size()) return null;
+    return (WorkflowGraph)graphs.get(index);
+  }
+
+  public void createGraph(String workflowName)
+  {
+    GraphModel model = new WorkflowGraphModel();
+    WorkflowGraph graph = null;
+    Layout layout = manager.getCurrentWorkspace().getLayout(workflowName);
+    boolean hasLayout = layout != null;
+    if(layout == null) layout = new Layout();
+    WorkflowDescriptor descriptor = null;
+    try
+    {
+      descriptor = manager.getCurrentWorkspace().getWorkflow(workflowName);
+    }
+    catch(FactoryException e)
+    {
+      log.error("Error creating graph:" + e.getMessage());
+      return;
+    }
+    mlayout.add(layout);
+    graph = new WorkflowGraph(model, descriptor, layout, !hasLayout);
+    if(System.getProperty("mrj.version") != null)
+    {
+      graph.setDoubleBuffered(false);
+    }
+    graph.addGraphSelectionListener(this);
+    graphs.add(graph);
+    graphTabs.add(workflowName, new JScrollPane(graph));
+    graphTabs.setSelectedIndex(graphTabs.getComponentCount() - 1);
+  }
+
+  public void quit()
+  {
+    Point location = getLocation();
+    Prefs.INSTANCE.putInt(Prefs.MAIN_DIVIDER_LOCATION, mainSplitPane.getDividerLocation());
+    Prefs.INSTANCE.putInt(Prefs.DETAIL_DIVIDER_LOCATION, leftSplitPane.getDividerLocation());
+    Prefs.INSTANCE.put(Prefs.DESIGNER_BOUNDS, location.x + "," + location.y + "," + mainSplitPane.getWidth() + "," + mainSplitPane.getHeight());
+    try
+    {
+      Prefs.INSTANCE.flush();
+    }
+    catch(Exception e)
+    {
+      log.error("Error saving prefs", e);
+    }
+    System.exit(0);
+  }
+
+  public void valueChanged(GraphSelectionEvent e)
+  {
+    if(e.getCell() != null && (e.getCell() instanceof WorkflowCell || e.getCell() instanceof WorkflowEdge))
+    {
+      showDetails(e.getCell());
+    }
+    else if(e.getCell() != null)
+    {
+      log.debug("unhandled selection:" + e.getCell().getClass());
+    }
+  }
+
+  public void showDetails(Object node)
+  {
+    String panelName = node.getClass().getName();
+    DetailPanel current = (DetailPanel)detailPanel.getVisibleCard();
+    if(current != null) current.closeView();
+    DetailPanel panel = (DetailPanel)detailPanel.showCard(panelName);
+    if(panel == null)
+    {
+      if(node instanceof StepCell)
+      {
+        panel = new StepEditor();
+      }
+      else if(node instanceof SplitCell)
+      {
+        panel = new SplitEditor();
+      }
+      else if(node instanceof JoinCell)
+      {
+        panel = new JoinEditor();
+      }
+      else if(node instanceof ResultEdge)
+      {
+        panel = new ResultEditor();
+      }
+      if(panel != null)
+      {
+        panel.setName(panelName);
+        detailPanel.showCard(panel);
+      }
+    }
+    if(panel != null)
+    {
+      if(node instanceof WorkflowCell)
+      {
+        panel.setCell((WorkflowCell)node);
+      }
+      else if(node instanceof WorkflowEdge)
+      {
+        panel.setEdge((WorkflowEdge)node);
+      }
+      String title = panel.getTitle();
+      detailFramePanel.setTitle("Details" + (title != null ? (" - " + title) : ""));
+    }
+    else
+    {
+      log.warn("no detail panel for " + node.getClass());
+    }
+  }
+
+  public void openWorkspace(File f)
+  {
+    if(f != null && f.exists())
+    {
+      try
+      {
+        Prefs.INSTANCE.put(Prefs.LAST_WORKSPACE, f.toString());
+        manager.loadWorkspace(f);
+        navigator.setWorkspace(manager.getCurrentWorkspace());
+      }
+      catch(Exception t)
+      {
+        log.error("Error opening workspace", t);
+      }
+    }
+  }
+
+  public void save(ActionEvent event)
+  {
+    int index = graphTabs.getSelectedIndex();
+    save(index);
+  }
+
+  public void save(int index)
+  {
+    Layout layout = (Layout)mlayout.get(index);
+    WorkflowGraphModel obj = (WorkflowGraphModel)((WorkflowGraph)graphs.get(index)).getModel();
+    layout.setActivity(obj.getActivitiesList());
+    String workflowName = graphTabs.getTitleAt(index);
+    manager.getCurrentWorkspace().setLayout(workflowName, layout);
+    try
+    {
+      manager.getCurrentWorkspace().saveWorkflow(workflowName, manager.getCurrentWorkspace().getWorkflow(workflowName), true);
+    }
+    catch(FactoryException e)
+    {
+      log.error("Error saving " + workflowName + ": " + e);
+    }
+  }
+
+  public void quit(ActionEvent event)
+  {
+    quit();
+  }
+
+  public void saveOpenGraphs()
+  {
+    for(int i = 0; i < graphTabs.getTabCount(); i++)
+    {
+      save(i);
+    }
+  }
+
+  public void saveWorkspace()
+  {
+    manager.saveWorkspace();
+  }
+
+  public void newWorkspace()
+  {
+    closeWorkspace();
+    Workspace workspace = new Workspace();
+    manager.setCurrentWorkspace(workspace);
+    navigator.setWorkspace(workspace);
+  }
+
+  public void closeWorkspace()
+  {
+    for(int i = 0; i < graphTabs.getComponentCount(); i++)
+    {
+      graphTabs.remove(i);
+    }
+    manager.setCurrentWorkspace(null);
+    navigator.setWorkspace(null);
+    Prefs.INSTANCE.remove(Prefs.LAST_WORKSPACE);
+    mlayout.clear();
+    graphs.clear();
+  }
+
+  public void newWorkflowCreated(String name)
+  {
+    navigator.addWorkflow(name);
+    navigator.selectWorkflow(name);
+  }
+
+  public Navigator navigator()
+  {
+    return navigator;
+  }
+
+  public void setAppMenu()
+  {
+    JMenuBar menuBar = new JMenuBar();
+    JMenu fileMenu = new JMenu("File");
+    JMenu itemNew = new JMenu("New");
+    NewWorkflow newWorkflow = new NewWorkflow();
+    manager.addWorkspaceListener(newWorkflow);
+    itemNew.add(new NewWorkspace());
+    itemNew.add(newWorkflow);
+    fileMenu.add(itemNew);
+
+    fileMenu.add(new OpenWorkspace());
+
+    CloseWorkspace close = new CloseWorkspace();
+    manager.addWorkspaceListener(close);
+    fileMenu.add(close);
+
+    ImportWorkflow importWorkflow = new ImportWorkflow();
+    manager.addWorkspaceListener(importWorkflow);
+    fileMenu.add(importWorkflow);
+    PNGExport export = new PNGExport();
+    manager.addWorkspaceListener(export);
+    fileMenu.add(export);
+
+    fileMenu.addSeparator();
+
+    SaveWorkspace save = new SaveWorkspace();
+    manager.addWorkspaceListener(save);
+    fileMenu.add(save);
+    fileMenu.addSeparator();
+    fileMenu.add(new Quit());
+    JMenu viewMenu = new JMenu("View");
+    AutoLayout auto = new AutoLayout(null);
+    manager.addWorkspaceListener(auto);
+    viewMenu.add(auto);
+    menuBar.add(fileMenu);
+    menuBar.add(viewMenu);
+    setJMenuBar(menuBar);
+  }
+
+  public void selectWorkflow(String workflowName)
+  {
+    for(int i = 0; i < graphTabs.getTabCount(); i++)
+    {
+      String name = graphTabs.getTitleAt(i);
+      if(name.equals(workflowName))
+      {
+        graphTabs.setSelectedIndex(i);
+        Prefs.INSTANCE.put(Prefs.WORKFLOW_CURRENT, workflowName);
+        return;
+      }
+    }
+    createGraph(workflowName);
+    Prefs.INSTANCE.put(Prefs.WORKFLOW_CURRENT, workflowName);
+  }
+
+  public static void main(String[] args)
+  {
+    String spec = System.getProperty("java.specification.version");
+    if(spec.startsWith("1.3") || spec.startsWith("1.2") || spec.startsWith("1.1"))
+    {
+      System.out.println("Workflow Designer requires JDK 1.4.0 or higher");
+      System.exit(1);
+    }
+    if(System.getProperty("os.name").startsWith("Windows"))
+    {
+      try
+      {
+        UIManager.setLookAndFeel((LookAndFeel)Class.forName("com.jgoodies.plaf.windows.ExtWindowsLookAndFeel", true, WorkflowDesigner.class.getClassLoader()).newInstance());
+      }
+      catch(Exception e)
+      {
+      }
+    }
+    //all other platforms except for OSX get the plastic LAF
+    else if(System.getProperty("mrj.version") == null)
+    {
+      try
+      {
+        UIManager.setLookAndFeel((LookAndFeel)Class.forName("com.jgoodies.plaf.plastic.PlasticXPLookAndFeel", true, WorkflowDesigner.class.getClassLoader()).newInstance());
+      }
+      catch(Exception e)
+      {
+      }
+    }
+    WorkflowDesigner d = new WorkflowDesigner();
+    d.pack();
+    d.show();
+  }
+}

src/designer/com/opensymphony/workflow/designer/WorkflowGraphModel.java

+/**
+ * Created on Feb 11, 2003
+ * Copyright (C) 2002  Aditisoft Inc
+ */
+package com.opensymphony.workflow.designer;
+
+import java.util.*;
+import javax.swing.undo.UndoableEdit;
+
+import com.jgraph.graph.*;
+import com.opensymphony.workflow.loader.*;
+
+public class WorkflowGraphModel extends DefaultGraphModel
+{
+  private Map stepCells = new HashMap();
+  private Map splitCells = new HashMap();
+  private Map joinCells = new HashMap();
+  private Map initialActions = new HashMap();
+  private ResultCellCollection resultCells = new ResultCellCollection();
+
+  public void insertInitialActions(List initialActions, InitialActionCell initialActionCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!this.initialActions.containsKey(initialActionCell.getKey()))
+    {
+      this.initialActions.put(initialActionCell.getKey(), initialActionCell);
+      for(int i = 0; i < initialActions.size(); i++)
+      {
+        ActionDescriptor action = (ActionDescriptor)initialActions.get(i);
+        List conResults = action.getConditionalResults();
+        recordResults(initialActionCell, conResults);
+        ResultDescriptor result = action.getUnconditionalResult();
+        recordResult(initialActionCell, result);
+        Object[] cells = new Object[]{initialActionCell};
+        // Insert into Model
+        insert(cells, attributes, null, pm, edits);
+      }
+    }
+
+  }
+
+  public void insertInitialsActions(List initialActions, InitialActionCell initialActionCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!this.initialActions.containsKey(initialActionCell.getKey()))
+    {
+      this.initialActions.put(initialActionCell.getKey(), initialActionCell);
+      for(int i = 0; i < initialActions.size(); i++)
+      {
+        //ActionDescriptor action = (ActionDescriptor)initialActions.get(i);
+        //List conResults = action.getConditionalResults();
+        /*				recordResults(initialActionCell, conResults);
+                ResultDescriptor result = action.getUnconditionalResult();
+                recordResult(initialActionCell, result);*/
+        Object[] cells = new Object[]{initialActionCell};
+        // Insert into Model
+        insert(cells, attributes, null, pm, edits);
+      }
+    }
+
+  }
+
+  public void insertStepCell(StepCell stepCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!stepCells.containsKey(stepCell.getKey()))
+    {
+      stepCells.put(stepCell.getKey(), stepCell);
+      Object[] cells = new Object[]{stepCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      recordResults(stepCell);
+      processStepEndPointResult(stepCell);
+      // stepCell.toString();
+    }
+  }
+
+  // by raj
+  public void insertStep(StepCell stepCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!stepCells.containsKey(stepCell.getKey()))
+    {
+      stepCells.put(stepCell.getKey(), stepCell);
+      Object[] cells = new Object[]{stepCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      // recordResults(stepCell);
+      // processStepEndPointResult(stepCell);
+      // stepCell.toString();
+    }
+  }
+
+  public void insertSplitCell(SplitCell splitCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!splitCells.containsKey(splitCell.getKey()))
+    {
+
+      splitCells.put(splitCell.getKey(), splitCell);
+      Object[] cells = new Object[]{splitCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      recordResults(splitCell);
+      processSplitEndPointResult(splitCell);
+    }
+  }
+
+  public void insertSplit(SplitCell splitCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!splitCells.containsKey(splitCell.getKey()))
+    {
+
+      splitCells.put(splitCell.getKey(), splitCell);
+      Object[] cells = new Object[]{splitCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      // recordResults(splitCell);
+      // processSplitEndPointResult(splitCell);
+    }
+  }
+
+  public void insertJoinCell(JoinCell joinCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!joinCells.containsKey(joinCell.getKey()))
+    {
+
+      joinCells.put(joinCell.getKey(), joinCell);
+      Object[] cells = new Object[]{joinCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      recordResults(joinCell);
+      processJoinEndPointResult(joinCell);
+    }
+  }
+
+  public void insertJoin(JoinCell joinCell, Map attributes, ParentMap pm, UndoableEdit[] edits)
+  {
+    if(!joinCells.containsKey(joinCell.getKey()))
+    {
+      joinCells.put(joinCell.getKey(), joinCell);
+      Object[] cells = new Object[]{joinCell};
+      // Insert into Model
+      insert(cells, attributes, null, pm, edits);
+      //		recordResults(joinCell);
+      //		processJoinEndPointResult(joinCell);
+    }
+  }
+
+  public void insertResultConnections()
+  {
+    Iterator steps = stepCells.values().iterator();
+    while(steps.hasNext())
+    {
+      StepCell stepCell = (StepCell)steps.next();
+      processStepEndPointResult(stepCell);
+    }
+    Iterator splits = splitCells.values().iterator();
+    while(splits.hasNext())
+    {
+      SplitCell splitCell = (SplitCell)splits.next();
+      processSplitEndPointResult(splitCell);
+    }
+    Iterator joins = joinCells.values().iterator();
+    while(joins.hasNext())
+    {
+      JoinCell joinCell = (JoinCell)joins.next();
+      processJoinEndPointResult(joinCell);
+    }
+  }
+
+  public void recordResults(JoinCell fromCell)
+  {
+    JoinDescriptor joinDescriptor = fromCell.getJoinDescriptor();
+    ResultDescriptor result = joinDescriptor.getResult();
+    recordResult(fromCell, result);
+  }
+
+  public void processJoinEndPointResult(JoinCell joinCell)
+  {
+    int joinId = joinCell.getJoinDescriptor().getId();
+    Iterator results = resultCells.getJoinEndPointResults(joinId).iterator();
+    while(results.hasNext())
+    {
+      ResultCell result = (ResultCell)results.next();
+      connectCells(result, joinCell);
+    }
+  }
+
+  public void processSplitEndPointResult(SplitCell splitCell)
+  {
+    int splitId = splitCell.getSplitDescriptor().getId();
+    Iterator results = resultCells.getSplitEndPointResults(splitId).iterator();
+    while(results.hasNext())
+    {
+      ResultCell result = (ResultCell)results.next();
+      connectCells(result, splitCell);
+    }
+
+  }
+
+  public void recordResults(SplitCell fromCell)
+  {
+    SplitDescriptor splitDescriptor = fromCell.getSplitDescriptor();
+    List results = splitDescriptor.getResults();
+    recordResults(fromCell, results);
+    //      for (int i = 0; i < actionList.size(); i++) {
+    //         ActionDescriptor action = (ActionDescriptor) actionList.get(i);
+    //         List conResults = action.getConditionalResults();
+    //         recordResults(fromCell, conResults);
+    //         ResultDescriptor result = action.getUnconditionalResult();
+    //         recordResult(fromCell, result);
+    //      }
+
+  }
+
+  /**
+   * Find Results that have StepCell's associated Step passed in as next Step. Connect all such cells
+   */
+  public void processStepEndPointResult(StepCell stepCell)
+  {
+    int stepId = stepCell.getDescriptor().getId();
+    Iterator results = resultCells.getStepEndPointResults(stepId).iterator();
+    while(results.hasNext())
+    {
+      ResultCell result = (ResultCell)results.next();
+      connectCells(result, stepCell);
+    }
+  }
+
+  /**
+   * Connects fromCell contained in resultCell to the toCell passed in.
+   */
+  public void connectCells(ResultCell resultCell, DefaultGraphCell toCell)
+  {
+    Map attributeMap = new HashMap();
+    DefaultPort fromPort = new DefaultPort();
+    resultCell.getFromCell().add(fromPort);
+    DefaultPort toPort = new DefaultPort();
+    toCell.add(toPort);
+    // Create Edge
+    ResultEdge edge = new ResultEdge();
+    edge.setDescriptor(resultCell.getDescriptor());
+    // Create Edge Attributes
+    Map edgeAttrib = GraphConstants.createMap();
+    // Set Arrow
+    int arrow = GraphConstants.ARROW_CLASSIC;
+    GraphConstants.setLineEnd(edgeAttrib, arrow);
+    GraphConstants.setEndFill(edgeAttrib, true);
+    // Connect Edge
+    ConnectionSet cs = new ConnectionSet(edge, fromPort, toPort);
+    Object[] cells = new Object[]{edge};
+    // Insert into Model
+    attributeMap.put(edge, edgeAttrib);
+    insert(cells, attributeMap, cs, null, null);
+  }
+
+  /**
+   *
+   * When a Step is inserted, introspect it. find all the actions and add them to the GraphModel.
+   * Introspect each action and record results.
+   *
+   */
+  public void recordResults(StepCell fromCell)
+  {
+    StepDescriptor stepDescriptor = fromCell.getDescriptor();
+    List actionList = stepDescriptor.getActions();
+    for(int i = 0; i < actionList.size(); i++)
+    {
+      ActionDescriptor action = (ActionDescriptor)actionList.get(i);
+      List conResults = action.getConditionalResults();
+      recordResults(fromCell, conResults);
+      ResultDescriptor result = action.getUnconditionalResult();
+      recordResult(fromCell, result);
+    }
+  }
+
+  private void recordResults(DefaultGraphCell fromCell, List results)
+  {
+    for(int i = 0; i < results.size(); i++)
+    {
+      ResultDescriptor result = (ResultDescriptor)results.get(i);
+      recordResult(fromCell, result);
+    }
+  }
+
+  private void recordResult(DefaultGraphCell fromCell, ResultDescriptor result)
+  {
+    String key = resultCells.getNextKey();
+    ResultCell newCell = new ResultCell(fromCell, result);
+    resultCells.put(key, newCell);
+  }
+
+  public Map getActivitiesList()
+  {
+    Map map = new HashMap();
+    map.putAll(initialActions);
+    map.putAll(stepCells);
+    map.putAll(splitCells);
+    map.putAll(joinCells);
+    return map;
+  }
+
+  public Map getStep()
+  {
+    return stepCells;
+  }
+
+  /**
+   * Method getSplit.
+   * @return Map
+   */
+  public Map getSplit()
+  {
+    return splitCells;
+  }
+
+  public Map getJoin()
+  {
+    return joinCells;
+  }
+
+  public Map getInitialsAction()
+  {
+    return initialActions;
+  }
+
+}

src/designer/com/opensymphony/workflow/designer/swing/CardPanel.java

+package com.opensymphony.workflow.designer.swing;
+
+/*
+ * Copyright (c) Sun Microsystems.
+ */
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * A simpler alternative to a JPanel with a CardLayout.  The AWT CardLayout
+ * layout manager can be inconvenient to use because the special "stack of
+ * cards" operations it supports require a cast to use.  For example to show
+ * the card named "myCard" given a JPanel with a CardLayout one would write:
+ * <pre>
+ * ((CardLayout)(myJPanel.getLayout())).show(myJPanel, "myCard");
+ * </pre>
+ * This doesn't work well with Swing - all of the CardLayout display
+ * operations, like <code>show</code> call validate directly.  Swing supports
+ * automatic validation (see JComponent.revalidate()); this direct call to
+ * validate is inefficient.
+ * <p>
+ * The CardPane JPanel subclass is intended to support a layout with a modest
+ * number of cards, on the order of 100 or less.  A cards name is it's
+ * component name, as in java.awt.Component.getName(), which is set when the
+ * component is added to the CardPanel:
+ * <pre>
+ * myCardPanel.add(myChild, "MyChildName");
+ * myChild.getName() <i>=> "MyChildName"</i>
+ * </pre>
+ * As with CardLayout, the first child added to a CardPanel is made visible
+ * and there's only one child visible at a time.  The <code>showCard</code>
+ * method accepts either a childs name or the child itself:
+ * <pre>
+ * myCardPanel.show("MyChildName");
+ * myCardPanel.show(myChild);
+ * </pre>
+ * <p>
+ * The CardPanel class doesn't support the vgap/hgap CardLayout properties
+ * since one can add a Border, see JComponent.setBorder().
+ *
+ * @author Sun Microsystems
+ */
+
+public class CardPanel extends JPanel
+{
+
+  private static class Layout implements LayoutManager
+  {
+    /**
+     * Set the childs name (if non-null) and and make it visible
+     * iff it's the only CardPanel child.
+     * @see java.awt.Component#setName
+     */
+    public void addLayoutComponent(String name, Component child)
+    {
+      if(name != null)
+      {
+        child.setName(name);
+      }
+      child.setVisible(child.getParent().getComponentCount() == 1);
+    }
+
+    /**
+     * If this child was visible, then make the first remaining
+     * child visible.
+     */
+    public void removeLayoutComponent(Component child)
+    {
+      if(child.isVisible())
+      {
+        Container parent = child.getParent();
+        if(parent.getComponentCount() > 0)
+        {
+          parent.getComponent(0).setVisible(true);
+        }
+      }
+    }
+
+    /**
+     * @return the maximum preferred width/height + the parents insets
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+      int nChildren = parent.getComponentCount();
+      Insets insets = parent.getInsets();
+      int width = insets.left + insets.right;
+      int height = insets.top + insets.bottom;
+      for(int i = 0; i < nChildren; i++)
+      {
+        Dimension d = parent.getComponent(i).getPreferredSize();
+        if(d.width > width)
+        {
+          width = d.width;
+        }
+        if(d.height > height)
+        {
+          height = d.height;
+        }
+      }
+      System.out.println("preferredLayoutSize()=" + width + " " + height);
+      return new Dimension(width, height);
+    }
+
+    /**
+     * @return the maximum minimum width/height + the parents insets
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+      int nChildren = parent.getComponentCount();
+      Insets insets = parent.getInsets();
+      int width = insets.left + insets.right;
+      int height = insets.top + insets.bottom;
+      for(int i = 0; i < nChildren; i++)
+      {
+        if(!parent.getComponent(i).isVisible()) continue;
+        Dimension d = parent.getComponent(i).getMinimumSize();
+        if(d.width > width)
+        {
+          width = d.width;
+        }
+        if(d.height > height)
+        {
+          height = d.height;
+        }
+      }
+      //return new Dimension(width, height);
+      return new Dimension(100, height);
+    }
+
+    public void layoutContainer(Container parent)
+    {
+      int nChildren = parent.getComponentCount();
+      Insets insets = parent.getInsets();
+      for(int i = 0; i < nChildren; i++)
+      {
+        Component child = parent.getComponent(i);
+        if(child.isVisible())
+        {
+          Rectangle r = parent.getBounds();
+          int width = r.width - insets.left + insets.right;
+          int height = r.height - insets.top + insets.bottom;
+          child.setBounds(insets.left, insets.top, width, height);
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Creates a CardPanel.  Children, called "cards" in this API, should be
+   * added with add().  The first child we be made visible, subsequent
+   * children will be hidden.  To show a card, use one of the show*Card
+   * methods.
+   */
+  public CardPanel()
+  {
+    super(new Layout());
+  }
+
+  /**
+   * Hide the currently visible child  "card" and show the
+   * specified card.  If the specified card isn't a child
+   * of the CardPanel then we add it here.
+   */
+  public Component getVisibleCard()
+  {
+    int index = getVisibleChildIndex();
+    return index != -1 ? getComponent(index) : null;
+  }
+
+  /**
+   * Return the index of the first (and one would hope - only)
+   * visible child.  If a visible child can't be found,
+   * perhaps the caller has inexlicably hidden all of the
+   * children, then return -1.
+   */
+  public int getVisibleChildIndex()
+  {
+    int nChildren = getComponentCount();
+    for(int i = 0; i < nChildren; i++)
+    {
+      Component child = getComponent(i);
+      if(child.isVisible())
+      {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Return the name of the visible child.
+   */
+  public String getVisibleChildName()
+  {
+    int i = getVisibleChildIndex();
+    return -1 == i ? null : getComponent(i).getName();
+  }
+
+  /**
+   * Hide the currently visible child  "card" and show the
+   * specified card.  If the specified card isn't a child
+   * of the CardPanel then we add it here.
+   */
+  public void showCard(Component card)
+  {
+    if(card.getParent() != this)
+    {
+      add(card);
+    }
+    Component visibleComponent = getVisibleCard();
+    if(visibleComponent == card)
+      return;
+    visibleComponent.setVisible(false);
+    card.setVisible(true);
+    revalidate();
+    repaint();
+  }
+
+  /**
+   * Show the card with the specified name.
+   * @see java.awt.Component#getName
+   */
+  public Component showCard(String name)
+  {
+    if(getVisibleCard()!=null && name.equals(getVisibleCard().getName())) return getVisibleCard();
+    int nChildren = getComponentCount();
+    for(int i = 0; i < nChildren; i++)
+    {
+      Component child = getComponent(i);
+      if(child.getName().equals(name) && !child.isVisible())
+      {
+        showCard(child);
+        return child;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Show the first card that was added to this CardPanel.
+   */
+  public void showFirstCard()
+  {
+    if(getComponentCount() <= 0)
+    {
+      return;
+    }
+    showCard(getComponent(0));
+  }
+
+  /**
+   * Show the last card that was added to this CardPanel.
+   */
+  public void showLastCard()
+  {
+    if(getComponentCount() <= 0)
+    {
+      return;
+    }
+    showCard(getComponent(getComponentCount() - 1));
+  }
+
+  /**
+   * Show the card that was added to this CardPanel after the currently
+   * visible card.  If the currently visible card was added last, then
+   * show the first card.
+   */
+  public void showNextCard()
+  {
+    if(getComponentCount() <= 0)
+    {
+      return;
+    }
+    int index = getVisibleChildIndex();
+    if(index == -1)
+    {
+      showCard(getComponent(0));
+    }
+    else if(index == (getComponentCount() - 1))
+    {
+      showCard(getComponent(0));
+    }
+    else
+    {
+      showCard(getComponent(index + 1));
+    }
+  }
+
+  /**
+   * Show the card that was added to this CardPanel before the currently
+   * visible card.  If the currently visible card was added first, then
+   * show the last card.
+   */
+  public void showPreviousCard()
+  {
+    if(getComponentCount() <= 0)
+    {
+      return;
+    }
+    int index = getVisibleChildIndex();
+    if(index == -1)
+    {
+      showCard(getComponent(0));
+    }
+    else if(index == 0)
+    {
+      showCard(getComponent(getComponentCount() - 1));
+    }
+    else
+    {
+      showCard(getComponent(index - 1));
+    }
+  }
+
+}