summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/c2kernel/gui/Console.java290
-rw-r--r--src/main/java/com/c2kernel/gui/DomainKeyConsumer.java16
-rw-r--r--src/main/java/com/c2kernel/gui/DomainKeyListener.java27
-rw-r--r--src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java183
-rw-r--r--src/main/java/com/c2kernel/gui/EntityDetails.java228
-rw-r--r--src/main/java/com/c2kernel/gui/EntityFinder.java217
-rw-r--r--src/main/java/com/c2kernel/gui/EntityTabManager.java86
-rw-r--r--src/main/java/com/c2kernel/gui/LoginBox.java327
-rw-r--r--src/main/java/com/c2kernel/gui/Main.java40
-rw-r--r--src/main/java/com/c2kernel/gui/MainFrame.java309
-rw-r--r--src/main/java/com/c2kernel/gui/MenuBuilder.java281
-rw-r--r--src/main/java/com/c2kernel/gui/TreeBrowser.java213
-rw-r--r--src/main/java/com/c2kernel/gui/collection/AggregationMemberRenderer.java125
-rw-r--r--src/main/java/com/c2kernel/gui/collection/CollectionFrame.java41
-rw-r--r--src/main/java/com/c2kernel/gui/collection/PropertyPanel.java37
-rw-r--r--src/main/java/com/c2kernel/gui/collection/SelectedMemberPanel.java164
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/AutoScrollController.java41
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/DeletionController.java92
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/EdgeConstructionController.java253
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/MultiSelectionDragController.java571
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/StartVertexController.java79
-rw-r--r--src/main/java/com/c2kernel/gui/graph/controller/VertexConstructionController.java47
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/DefaultDirectedEdgeRenderer.java75
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/DefaultVertexRenderer.java60
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/DirectedEdgeRenderer.java11
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/EditorModeListener.java8
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/EditorPanel.java104
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/EditorToolBar.java346
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/GraphPanel.java272
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/PropertyTable.java40
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/PropertyTableModel.java135
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/SelectedVertexPanel.java27
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/VertexPropertyPanel.java259
-rw-r--r--src/main/java/com/c2kernel/gui/graph/view/VertexRenderer.java11
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/ActivitySlotDefRenderer.java71
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/CompActDefOutcomeHandler.java232
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/ElemActDefOutcomeHandler.java161
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/SplitJoinDefRenderer.java138
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/WfDefGraphPanel.java59
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/WfDirectedEdgeDefRenderer.java134
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/desc/WfVertexDefRenderer.java30
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/ActivityRenderer.java117
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/FindActDefPanel.java72
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/SplitJoinRenderer.java142
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/TransitionPanel.java187
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/WfDirectedEdgeRenderer.java130
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/WfGraphPanel.java59
-rw-r--r--src/main/java/com/c2kernel/gui/lifecycle/instance/WfVertexRenderer.java23
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java51
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java70
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/CollectionPane.java109
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java174
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java197
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java208
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/HistoryPane.java270
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java96
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/JobListPane.java312
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java200
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java515
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java286
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java90
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java192
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java49
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java34
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java55
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java296
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java35
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/execution/Executor.java22
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java34
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java112
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java11
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java11
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java11
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java16
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java11
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java160
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java14
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java252
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java395
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java33
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java332
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java142
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java55
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java141
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java218
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java370
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java283
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java12
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java173
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java113
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java75
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java144
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java122
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java112
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java120
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java31
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java40
-rw-r--r--src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java257
-rw-r--r--src/main/java/com/c2kernel/gui/tree/Node.java232
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeAgent.java33
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeCollection.java68
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeContext.java65
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeEntity.java82
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeItem.java112
-rw-r--r--src/main/java/com/c2kernel/gui/tree/NodeSubscriber.java13
105 files changed, 14236 insertions, 0 deletions
diff --git a/src/main/java/com/c2kernel/gui/Console.java b/src/main/java/com/c2kernel/gui/Console.java
new file mode 100644
index 0000000..3427f82
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/Console.java
@@ -0,0 +1,290 @@
+package com.c2kernel.gui;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.util.Properties;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+/**************************************************************************
+ *
+ * $Revision: 1.10 $
+ * $Date: 2005/10/05 07:39:37 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class Console extends JFrame {
+ JTextArea output;
+ JScrollPane scroll;
+ JTextField input;
+ JButton sendButton;
+ JButton toFileButton;
+ FileWriter logFile;
+ ConsoleConnection connection;
+ JFileChooser scriptLoader = new JFileChooser();
+ static int bufferSize = Integer.parseInt(Gateway.getProperty("Console.bufferSize", "200"));
+
+ public Console(String host, int port) {
+ super("Cristal Console - "+host);
+ GridBagLayout gridbag = new GridBagLayout();
+ getContentPane().setLayout(gridbag);
+ output = new JTextArea("Type 'help' for help. . .\n");
+ output.setEditable(false);
+ input = new JTextField();
+ setSize(400, 600);
+ sendButton = new JButton("Send");
+ sendButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ submit();
+ }
+ });
+ JButton clearButton = new JButton("Clear");
+ clearButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ synchronized (output) {
+ output.setText("");
+ }
+ }
+ });
+ toFileButton = new JButton("Save");
+ toFileButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (logFile == null) {
+ int returnValue = scriptLoader.showSaveDialog(null);
+ switch (returnValue)
+ {
+ case JFileChooser.APPROVE_OPTION :
+ try {
+ logFile = new FileWriter(scriptLoader.getSelectedFile());
+ print ("Starting writing log to "+scriptLoader.getSelectedFile().getAbsolutePath());
+ } catch (Exception ex) {
+ print(ex.getClass().getName()+": "+ex.getMessage());
+ Logger.error(ex);
+ }
+ toFileButton.setText("Stop");
+ case JFileChooser.CANCEL_OPTION :
+ case JFileChooser.ERROR_OPTION :
+ default :
+ }
+ }
+ else {
+ try {
+ logFile.close();
+ } catch (Exception ex) {
+ logFile = null;
+ print(ex.getClass().getName()+": "+ex.getMessage());
+ }
+ logFile = null;
+ toFileButton.setText("Save");
+ }
+ }
+ });
+
+
+ input.addKeyListener(new EnterListener(this));
+
+ scroll = new JScrollPane(output);
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx=0; c.gridy=0;
+ c.fill=GridBagConstraints.BOTH;
+ c.weightx=1.0;c.weighty=1.0;
+ gridbag.setConstraints(scroll, c);
+ getContentPane().add(scroll);
+
+ Box inputBox = Box.createHorizontalBox();
+ inputBox.add(input);
+ inputBox.add(Box.createHorizontalStrut(5));
+ inputBox.add(sendButton);
+ inputBox.add(clearButton);
+ inputBox.add(toFileButton);
+ c.gridy=1; c.fill=GridBagConstraints.HORIZONTAL;
+ c.weighty=0;
+ gridbag.setConstraints(inputBox, c);
+ getContentPane().add(inputBox);
+
+ try {
+ // TODO: merge module script utilities together and prepend with namespace
+ Properties utilProps = FileStringUtility.loadConfigFile( Resource.findTextResource("ScriptUtils.conf") );
+
+ Box utilBox = Box.createHorizontalBox();
+ for (Object name2 : utilProps.keySet()) {
+ String name = (String) name2;
+ String value = utilProps.getProperty(name);
+ JButton newUtil = new JButton(name);
+ newUtil.setActionCommand(value);
+ newUtil.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ processUtil(e.getActionCommand());
+ }
+ });
+ utilBox.add(newUtil);
+ utilBox.add(Box.createHorizontalStrut(5));
+ }
+
+ c.gridy++;
+ gridbag.setConstraints(utilBox, c);
+ getContentPane().add(utilBox);
+ } catch (Exception ex) { // no domain utils
+ }
+
+
+ validate();
+ connection = new ConsoleConnection(host, port, this);
+ new Thread(connection).start();
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ if (connection!=null) connection.shutdown();
+ dispose();
+ }
+ });
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible) input.requestFocus();
+ }
+
+ public void processUtil(String command) {
+ int replace;
+ String text = input.getText();
+ while ((replace = command.indexOf("%s")) > -1) {
+ command = command.substring(0, replace)+text+command.substring(replace+2);
+ }
+ connection.sendCommand(command);
+ }
+
+ public void submit() {
+ connection.sendCommand(input.getText());
+ input.setText("");
+ }
+
+ public void print(String line) {
+ synchronized (output) {
+ String currentText = output.getText()+line+"\n";
+ while (output.getLineCount() > bufferSize) {
+ currentText = currentText.substring(currentText.indexOf("\n")+1);
+ output.setText(currentText);
+ }
+ output.setText(currentText);
+ output.setCaretPosition(output.getText().length());
+ if (logFile != null) try {
+ logFile.write(line+"\n");
+ } catch (IOException ex) {
+ logFile = null;
+ print("Error writing to file.");
+ }
+ }
+ }
+
+ @Override
+ public void disable() {
+ synchronized (output) {
+ output.append("Lost connection");
+ }
+ output.setEnabled(false);
+ input.setEnabled(false);
+ sendButton.setEnabled(false);
+ }
+
+ private class EnterListener extends KeyAdapter
+ {
+ Console parent;
+ public EnterListener(Console parent) {
+ this.parent = parent;
+ }
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode()==10) {
+ parent.submit();
+ }
+ }
+ };
+
+ private class ConsoleConnection implements Runnable {
+ String host; int port; Console parent; boolean keepConnected = true;
+ Socket conn; PrintWriter consoleOutput; BufferedReader consoleInput;
+
+
+ public ConsoleConnection(String host, int port, Console parent) {
+ Thread.currentThread().setName("Console Client to "+host+":"+port);
+ this.host = host;
+ this.port = port;
+ this.parent = parent;
+ }
+
+ @Override
+ public void run() {
+ connect();
+ while (keepConnected) {
+ try {
+ String line = consoleInput.readLine();
+ if (line == null) {
+ parent.disable();
+ keepConnected = false;
+ }
+ else
+ parent.print(line);
+ } catch (InterruptedIOException ex) { // timeout - ignore
+ } catch (IOException ex) { // error reading
+ parent.disable();
+ keepConnected = false;
+ }
+ }
+
+ try {
+ conn.close();
+ } catch (IOException ex) { }
+ }
+
+ public void sendCommand(String command) {
+ consoleOutput.println(command);
+ }
+
+ public void shutdown() {
+ keepConnected = false;
+ }
+
+ public void connect() {
+ parent.print("Connecting to "+host+":"+port);
+ try {
+ conn = new Socket(host, port);
+ conn.setKeepAlive(true);
+ conn.setSoTimeout(500);
+ consoleOutput = new PrintWriter(conn.getOutputStream(), true);
+ consoleInput = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ } catch (Exception ex) {
+
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java b/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java
new file mode 100644
index 0000000..18847cc
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java
@@ -0,0 +1,16 @@
+package com.c2kernel.gui;
+
+import com.c2kernel.lookup.DomainPath;
+
+/**
+ * Things that can be told when a barcode etc is entered
+ * @version $Revision: 1.2 $ $Date: 2003/03/13 16:42:38 $
+ * @author $Author: abranson $
+ */
+
+public interface DomainKeyConsumer {
+ public void push(DomainPath key);
+
+ public void push(String name);
+
+}
diff --git a/src/main/java/com/c2kernel/gui/DomainKeyListener.java b/src/main/java/com/c2kernel/gui/DomainKeyListener.java
new file mode 100644
index 0000000..df18e72
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/DomainKeyListener.java
@@ -0,0 +1,27 @@
+package com.c2kernel.gui;
+
+import java.io.IOException;
+
+import javax.swing.ImageIcon;
+
+/**
+ * Interface for external key input classes (e.g. barcode scanner)
+ * @version $Revision: 1.5 $ $Date: 2004/10/20 14:10:21 $
+ * @author $Author: abranson $
+ */
+
+public interface DomainKeyListener {
+ public void init();
+
+ public boolean enable() throws IOException;
+
+ public void setConsumer(EntityFinder consumer);
+
+ public void disable();
+
+ // return 25x25 icon for enable/disable button
+ public ImageIcon getIcon();
+
+ // tooltip for the button
+ public String getDescription();
+}
diff --git a/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java b/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java
new file mode 100644
index 0000000..006284a
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java
@@ -0,0 +1,183 @@
+package com.c2kernel.gui;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+
+import com.c2kernel.gui.tree.Node;
+import com.c2kernel.gui.tree.NodeItem;
+import com.c2kernel.gui.tree.NodeSubscriber;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+/**
+ * Installed as the user object on a single child node of a new node known to be composite.
+ * <p>Shows 'Loading . . .' when the branch is opened, but a TreeExpansionListener attempts to fire this thread off in the first child node.
+ * <br>When started, this thread will retrieve all of the real child nodes and add them to its parent while removing itself (hopefully for garbage collection)
+ *
+ * @version $Revision: 1.24 $ $Date: 2004/12/15 12:12:06 $
+ * @author $Author: abranson $
+ */
+
+public class DynamicTreeBuilder implements NodeSubscriber {
+ private DefaultTreeModel treeModel;
+ private final DefaultMutableTreeNode parent;
+ public short state = IDLE;
+ public static final short IDLE = 0;
+ public static final short LOADING = 1;
+ public static final short PARTIAL = 2;
+ public static final short FINISHED = 3;
+ private final DefaultMutableTreeNode loading;
+ private static ImageIcon loadIcon = Resource.findImage("loading.gif");
+ private static ImageIcon pauseIcon = Resource.findImage("reload.gif");
+
+ /**
+ * The newly created DynamicTreeBuilder records its parent node - the one for which it will build child nodes for.
+ * @param nodeClicked The Parent Tree Node that will be populated.
+ * @see NodeItem
+ * @see TreeDisplay*/
+ public DynamicTreeBuilder(DefaultMutableTreeNode parent) {
+ this.parent = parent;
+ loading = new DefaultMutableTreeNode(this);
+ }
+
+ /**
+ * Before the tree builder can execute, it needs to be given references to the tree and NodeFactory needed to create the new nodes.
+ * @param myNodeFactory The NodeFactory that can be queried for new NodeItems.
+ * @param parentTree The JTree in which this node is currently contained.
+ */
+ public void buildInfo(JTree parentTree) {
+ this.treeModel = (DefaultTreeModel)parentTree.getModel();
+ }
+
+ public void start() {
+ // find the clicked tree node
+ Node parentNode = (Node)parent.getUserObject();
+ Logger.msg(2, "DynamicTreeBuilder.start() - Filling in children of '"+parentNode.toString()+"'");
+ if (state == IDLE)
+ parentNode.subscribeNode(this);
+ else
+ parentNode.loadMore();
+ state = LOADING;
+ }
+
+ /**
+ * Used by the JTree to find the text representation of the node.
+ */
+ @Override
+ public String toString() {
+ switch (state) {
+ case IDLE:
+ return Language.translate("Initializing Tree Node Loader");
+ case LOADING:
+ return Language.translate("Loading . . .");
+ case PARTIAL:
+ return Language.translate("Double-click to load more");
+ case FINISHED:
+ return Language.translate("Done");
+ default:
+ return "";
+ }
+
+ }
+
+ public ImageIcon getIcon() {
+ if (state == LOADING)
+ return loadIcon;
+ else
+ return pauseIcon;
+ }
+
+ public DefaultMutableTreeNode getTreeNode() {
+ return loading;
+ }
+
+ @Override
+ public void add(Node newNode) {
+ Logger.msg(2, "DynamicTreeBuilder.add() - Received item for tree. Name: "+newNode);
+
+ // have we inserted the node yet?
+ SwingUtilities.invokeLater(new TreeAddThread(newNode));
+ }
+
+ class TreeAddThread implements Runnable {
+ Node newNode;
+ TreeAddThread(Node newNode) {
+ this.newNode = newNode;
+ }
+ @Override
+ public void run() {
+ boolean inserted = false;
+ DefaultMutableTreeNode newTreeNode = newNode.getTreeNode();
+ // loop though all children unless we have done the insertion
+ for (int i=0; i<parent.getChildCount() && !inserted; i++) {
+ DefaultMutableTreeNode child = (DefaultMutableTreeNode)treeModel.getChild(parent, i);
+ if (child == loading) continue; // skip loading node
+
+ Node childNode = (Node)child.getUserObject();
+ if (childNode.getName().equals(newNode.getName())) {
+ // we already have this one, skip it
+ inserted = true;
+ break;
+ }
+ if (childNode.getName().compareTo(newNode.getName()) >= 0) {
+ // if the next string is 'greater than' ours, insert the node before
+ treeModel.insertNodeInto(newTreeNode, parent, i);
+ inserted = true;
+ break;
+ }
+
+ }
+ // if we haven't inserted yet, it must go at the end.
+
+ if (!inserted)
+ treeModel.insertNodeInto(newTreeNode, parent, parent.getChildCount());
+ }
+
+ }
+
+ class TreeRemoveThread implements Runnable {
+ DefaultMutableTreeNode oldNode;
+ TreeRemoveThread(DefaultMutableTreeNode oldNode) {
+ this.oldNode = oldNode;
+ }
+
+ @Override
+ public void run() {
+ treeModel.removeNodeFromParent(oldNode);
+ }
+ }
+
+ @Override
+ public void end(boolean more) {
+ if (more) {
+ state = PARTIAL;
+ }
+ else {
+ state = FINISHED;
+ synchronized(treeModel) {
+ if (loading.getParent() != null)
+ SwingUtilities.invokeLater(new TreeRemoveThread(loading));
+ }
+ }
+ }
+
+ @Override
+ public void remove(Path path) {
+ synchronized (treeModel) {
+ for (int i=0; i<parent.getChildCount(); i++) {
+ DefaultMutableTreeNode child = (DefaultMutableTreeNode)treeModel.getChild(parent, i);
+ if (!(child.getUserObject() instanceof Node)) continue;
+ Node childNode = (Node)child.getUserObject();
+ if (childNode.getPath().equals(path)) {
+ SwingUtilities.invokeLater(new TreeRemoveThread(child));
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/EntityDetails.java b/src/main/java/com/c2kernel/gui/EntityDetails.java
new file mode 100644
index 0000000..56e6edb
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/EntityDetails.java
@@ -0,0 +1,228 @@
+package com.c2kernel.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeListener;
+
+import com.c2kernel.gui.tabs.EntityTabPane;
+import com.c2kernel.gui.tree.NodeEntity;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+/**
+ * The tab pane for each viewed item
+ * @version $Revision: 1.38 $ $Date: 2005/06/27 15:16:14 $
+ * @author $Author: abranson $
+ */
+public class EntityDetails extends JPanel implements ChangeListener, Runnable {
+ protected JTabbedPane myTabbedPane = new JTabbedPane(SwingConstants.BOTTOM);
+ protected JPanel itemTitlePanel;
+ private EntityTabManager desktopManager;
+ protected NodeEntity myEntity;
+ protected HashMap<EntityTabPane, Boolean> childPanes = new HashMap<EntityTabPane, Boolean>();
+ protected String startTab;
+ protected String startCommand = null;
+ protected boolean initialized = false;
+
+ public EntityDetails(NodeEntity thisItem) {
+ super();
+ startTab = MainFrame.getPref("DefaultStartTab", "Properties");
+ myEntity = thisItem;
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Entity Pane Builder");
+ EntityTabPane componentToAdd = null;
+ setLayout(new BorderLayout());
+ itemTitlePanel = getItemTitlePanel();
+ add(itemTitlePanel, BorderLayout.NORTH);
+ add(myTabbedPane);
+
+ // decide which tabs to create
+ ArrayList<?> requiredTabs = myEntity.getTabs();
+
+ for (Object name2 : requiredTabs) {
+ String tabName = (String)name2;
+ if (tabName != null) {
+ //create class instances and initialise
+ Class<?> myClass = null;
+ //look up the required TabbedPane
+ try {
+ myClass = Class.forName(this.getClass().getPackage().getName() + ".tabs." + tabName + "Pane");
+ Logger.msg(2, "ItemDetails.<init> - Creating ItemTabPane instance: " +
+ this.getClass().getPackage().getName() + ".tabs." + tabName + "Pane");
+ componentToAdd = (EntityTabPane)myClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ Logger.msg(2, "ItemDetails.<init> - No specialist tab found for " + tabName + ". Using default.");
+ } catch (InstantiationException e) {
+ Logger.msg(0, "ItemDetails.<init> - Instantiation Error! " + e);
+ } catch (IllegalAccessException e) {
+ Logger.msg(0, "ItemDetails.<init> - Illegal Method Access Error! Class was probably not a ItemTabPane: " + e);
+ }
+ if (componentToAdd == null) componentToAdd = new EntityTabPane(tabName, null);
+ componentToAdd.setParent(this);
+
+ //adds the component to the panel
+ childPanes.put(componentToAdd, new Boolean(false));
+
+ int placement = myTabbedPane.getTabCount();
+ if (tabName.equals("Properties")) // must be first
+ placement = 0;
+ myTabbedPane.insertTab(componentToAdd.getTabName(), null, componentToAdd, null, placement);
+ }
+ }
+ initialized = true;
+ if (!(requiredTabs.contains(startTab))) {
+ startTab = "Properties";
+ startCommand = null;
+ }
+ runCommand(Language.translate(startTab), startCommand);
+ myTabbedPane.setVisible(true);
+ myTabbedPane.addChangeListener(this);
+ validate();
+
+ }
+
+ @Override
+ public void stateChanged(javax.swing.event.ChangeEvent p1) {
+ initialisePane((EntityTabPane)myTabbedPane.getSelectedComponent());
+ }
+
+ public void initialisePane(EntityTabPane pane) {
+ Boolean isInit = childPanes.get(pane);
+ if (isInit.booleanValue() == false) {
+ Logger.msg(4,"Initialising "+pane.getTabName());
+ pane.initForEntity(myEntity);
+ childPanes.put(pane, new Boolean(true));
+ validate();
+ }
+ }
+
+ public EntityTabManager getDesktopManager() {
+ return desktopManager;
+ }
+
+ public void setDesktopManager(EntityTabManager newDesktopManager) {
+ desktopManager = newDesktopManager;
+ }
+
+ public JPanel getItemTitlePanel() {
+ JPanel titlePanel = new JPanel();
+ JComponent current;
+ // Use gridbag layout for title
+ GridBagLayout gridbag = new GridBagLayout();
+ GridBagConstraints c = new GridBagConstraints();
+ titlePanel.setLayout(gridbag);
+ // Place Item Icon
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridheight = GridBagConstraints.REMAINDER;
+ c.anchor = GridBagConstraints.NORTH;
+ c.ipadx = 5;
+ c.ipady = 5;
+ current = new JLabel(Resource.findImage("typeicons/"+myEntity.getIconName()+"_32.png"));
+ gridbag.setConstraints(current, c);
+ titlePanel.add(current);
+ // Place Name/ID Label
+ current = new JLabel(myEntity.getName() + " (" + myEntity.getSysKey() + ")");
+ c.gridx = 1; c.gridy = 0; c.gridheight = 1;
+ c.anchor = GridBagConstraints.NORTH; c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0; c.ipadx = 2; c.ipady = 2;
+ current.setFont(new Font("Helvetica", Font.PLAIN, 18));
+ gridbag.setConstraints(current, c);
+ titlePanel.add(current);
+ // Place Type Label
+ current = new JLabel(myEntity.getType());
+ c.gridx = 1; c.gridy = 2; c.gridheight = 1;
+ c.anchor = GridBagConstraints.CENTER; c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ current.setFont(new Font("Helvetica", Font.PLAIN, 12));
+ gridbag.setConstraints(current, c);
+ titlePanel.add(current);
+ return titlePanel;
+ }
+
+ public void discardTabs() {
+ myTabbedPane.removeChangeListener(this);
+ myTabbedPane.removeAll();
+ for (Iterator<EntityTabPane> iter = childPanes.keySet().iterator(); iter.hasNext();) {
+ EntityTabPane element = iter.next();
+ element.destroy();
+ iter.remove();
+ }
+ }
+
+ public int getSysKey()
+ {
+ return myEntity.getSysKey();
+ }
+
+ public void closeTab() {
+ desktopManager.remove(myEntity.getSysKey());
+ Logger.msg(5,"Remove master Tab :"+myEntity.getType()+ " SysKey "+myEntity.getSysKey());
+ myEntity.getEntity().dumpSubscriptions(0);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("close"))
+ closeTab();
+ }
+
+ public void runCommand(String tab, String command) {
+ if (initialized) {
+ int tabIndex = findTab(tab);
+ Logger.msg(3, "Running command "+tab+" "+command+" ("+tabIndex+")");
+ if (tabIndex == -1) {
+ Logger.error("Tab "+tab+" not found for command "+command);
+ return;
+ }
+ EntityTabPane startPane = (EntityTabPane)myTabbedPane.getComponentAt(tabIndex);
+ myTabbedPane.setSelectedIndex(tabIndex);
+ initialisePane(startPane);
+ if (command!= null) startPane.runCommand(command);
+ }
+ else
+ {
+ Logger.msg(3, "Storing command "+tab+" "+command+" until initialised.");
+ startTab = tab;
+ startCommand = command;
+ }
+ }
+
+ protected int findTab(String tabName) {
+ for (int i=0; i< myTabbedPane.getTabCount(); i++) {
+ EntityTabPane thisPane = (EntityTabPane)myTabbedPane.getComponentAt(i);
+ if (thisPane.getTabName().equals(tabName))
+ return i;
+ }
+ return -1;
+ }
+
+
+ public void refresh()
+ {
+ }
+ /**
+ *
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ Logger.msg(7, "EntityDetails "+myEntity.getSysKey()+" reaped");
+ super.finalize();
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/gui/EntityFinder.java b/src/main/java/com/c2kernel/gui/EntityFinder.java
new file mode 100644
index 0000000..0d53545
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/EntityFinder.java
@@ -0,0 +1,217 @@
+package com.c2kernel.gui;
+
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+import javax.swing.JToggleButton;
+
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.lookup.LDAPLookup;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+public class EntityFinder extends Box implements Runnable {
+ JTextField inputField;
+ JButton findButton;
+ JButton findNextButton;
+ GridBagLayout gridbag = new GridBagLayout();
+ LDAPLookup lookup = Gateway.getLDAPLookup();
+ DomainKeyConsumer defaultConsumer = null;
+ DomainKeyConsumer currentConsumer = null;
+ Enumeration<?> matches;
+ Path rootNode = MainFrame.userNode.getPath();
+
+ static protected ImageIcon mFindIcon = null;
+ static protected ImageIcon mNextIcon = null;
+ static {
+ try
+ {
+ mNextIcon =Resource.findImage("next.png");
+ mFindIcon =Resource.findImage("find.png");
+ }
+ catch (Exception e)
+ {
+ Logger.error("Couldn't load images: " + e);
+ }
+ }
+
+ public EntityFinder() {
+ super(BoxLayout.X_AXIS);
+ initPanel();
+ }
+
+ public void pushNewKey(String key) {
+ inputField.setText(key);
+ runSearch();
+ }
+
+ public void setDefaultConsumer(DomainKeyConsumer newConsumer) {
+ defaultConsumer = newConsumer;
+ currentConsumer = newConsumer;
+ }
+
+ public void setConsumer(DomainKeyConsumer newConsumer, String label) {
+ currentConsumer = newConsumer;
+ findButton.setText(label);
+ }
+
+ public void clearConsumer(DomainKeyConsumer oldConsumer) {
+ if (currentConsumer == oldConsumer) {
+ currentConsumer = defaultConsumer;
+ findButton.setText("");
+ }
+ }
+
+ private void initPanel() {
+
+ JLabel search = new JLabel(" "+Language.translate("Search")+":");
+ add(search);
+ add(Box.createHorizontalStrut(7));
+
+ inputField = new JTextField(20);
+ add(inputField);
+ add(Box.createHorizontalStrut(5));
+ inputField.addActionListener( new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ pushNewKey(inputField.getText());
+ }
+ });
+
+ findButton = new JButton(mFindIcon);//(Language.translate("Find"));
+ findButton.setMargin(new Insets(2, 5, 2, 5));
+ findButton.addActionListener( new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ pushNewKey(inputField.getText());
+ }
+ });
+ add(findButton);
+ add(Box.createHorizontalStrut(5));
+
+ findNextButton = new JButton(mNextIcon);//(Language.translate("Next"));
+ findNextButton.setMargin(new Insets(2, 5, 2, 5));
+ findNextButton.addActionListener( new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ MainFrame.status.setText("Navigating to next match");
+ nextMatch();
+ }
+ });
+ findNextButton.setEnabled(false);
+ add(findNextButton);
+ add(Box.createHorizontalStrut(15));
+
+ // create plugins
+ Logger.msg(6, "ItemFinder() - creating plugins");
+ String requiredListeners = Gateway.getProperty("DomainKeyListeners");
+ if (requiredListeners != null) {
+ StringTokenizer tok = new StringTokenizer(requiredListeners, ",");
+ while (tok.hasMoreTokens()) {
+ String listenerName = tok.nextToken();
+ Logger.msg(6, "ItemFinder() - creating a " + listenerName);
+ try {
+ Class<?> listenerClass = Class.forName(listenerName);
+ DomainKeyListener newListener = (DomainKeyListener)listenerClass.newInstance();
+ newListener.init(); newListener.setConsumer(this);
+ JToggleButton listenerButton = new JToggleButton(newListener.getIcon(), false);
+ listenerButton.addItemListener(new ListenerButtonListener(newListener, listenerButton));
+ listenerButton.setMargin(new Insets(0, 2, 0, 2));
+ listenerButton.setToolTipText("Enable "+newListener.getDescription());
+ add(listenerButton);
+ add(Box.createHorizontalStrut(7));
+ } catch (Exception e) {
+ Logger.error("ItemFinder() - could not create a "+listenerName+": "+e);
+ }
+ }
+ add(Box.createHorizontalGlue());
+ }
+ }
+
+ private void runSearch() {
+ Thread searcher = new Thread(this);
+ searcher.start();
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Entity Search");
+ MainFrame.status.setText("Searching. Please Wait");
+ findButton.setEnabled(false); findNextButton.setEnabled(false);
+ String searchTerm = inputField.getText();
+ if (searchTerm.length() == 0) return; // don't allow null searches
+ findNextButton.setEnabled(false);
+ matches = lookup.search(rootNode,inputField.getText());
+ if (!matches.hasMoreElements()) {
+ MainFrame.status.setText("No results");
+ currentConsumer.push(searchTerm); // for subscribers who don't care if it exists
+ findButton.setEnabled(true);
+ return;
+ }
+ MainFrame.status.setText("Selecting first match.");
+ nextMatch();
+
+ }
+
+ void nextMatch() {
+ findButton.setEnabled(false); findNextButton.setEnabled(false);
+ DomainPath nextMatch = (DomainPath)matches.nextElement();
+ try
+ {
+ currentConsumer.push(nextMatch);
+ }
+ catch (NullPointerException e)
+ {
+ //case the item searched is not found !
+ }
+ findButton.setEnabled(true);
+ findNextButton.setToolTipText("Click to show next match");
+ if (matches.hasMoreElements()) findNextButton.setEnabled(true);
+ }
+
+ private class ListenerButtonListener implements ItemListener {
+ private final DomainKeyListener listener;
+ private final JToggleButton listenerButton;
+
+ public ListenerButtonListener(DomainKeyListener newListener, JToggleButton listenerButton) {
+ this.listener = newListener;
+ this.listenerButton = listenerButton;
+ }
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ // Switch on
+ try {
+ if (!(listener.enable())) listenerButton.doClick(); // allow plugins to disable themselves
+ } catch (IOException ex) {
+ JOptionPane.showMessageDialog(null, ex.getMessage(), "Error initialising "+listener.getDescription(), JOptionPane.ERROR_MESSAGE);
+ listenerButton.doClick();
+ }
+ listenerButton.setToolTipText("Disable "+listener.getDescription());
+ } else {
+ // Switch off
+ listener.disable();
+ listenerButton.setToolTipText("Enable "+listener.getDescription());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/EntityTabManager.java b/src/main/java/com/c2kernel/gui/EntityTabManager.java
new file mode 100644
index 0000000..f1dafd6
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/EntityTabManager.java
@@ -0,0 +1,86 @@
+package com.c2kernel.gui;
+import java.awt.GridLayout;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+
+import com.c2kernel.gui.tabs.JTabbedPaneWithCloseIcons;
+import com.c2kernel.gui.tree.NodeEntity;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Keeps
+ *
+ * @version $Revision: 1.12 $ $Date: 2005/09/12 14:56:19 $
+ * @author $Author: abranson $
+ */
+
+public class EntityTabManager extends JPanel
+{
+ private MainFrame mMainframe;
+
+ protected HashMap<Integer, EntityDetails> openItems = new HashMap<Integer, EntityDetails>();
+ protected JTabbedPaneWithCloseIcons tabbedPane = new JTabbedPaneWithCloseIcons();
+ //JTabbedPane tabbedPane = new JTabbedPane();
+ MenuBuilder myMenuBuilder;
+
+
+ public EntityTabManager() {
+ super();
+ setLayout(new GridLayout(1,1));
+ setBorder(BorderFactory.createLoweredBevelBorder());
+ //UIDefaults ui = UIManager.getDefaults();
+ //ui.put("TabbedPane.selected",Color.red);
+ add(tabbedPane);
+ }
+
+ public EntityDetails add(NodeEntity thisEntity) {
+
+ EntityDetails requestedDetails;
+ if (!openItems.containsKey(new Integer(thisEntity.getSysKey()))) {
+ Logger.msg(1, "ItemWindowManager.add() - Window for syskey "+thisEntity.getSysKey()+" not found. Opening new one.");
+ requestedDetails = new EntityDetails(thisEntity);
+ Thread itemLoader = new Thread(requestedDetails);
+ itemLoader.start();
+ openItems.put(new Integer(thisEntity.getSysKey()), requestedDetails);
+ requestedDetails.setDesktopManager(this);
+
+ // get currently selected item to set location
+ tabbedPane.addTab(thisEntity.getName(), thisEntity.getIcon(), requestedDetails, Integer.toString(thisEntity.getSysKey()));
+
+
+ }
+ else { //opened window but different nodeitem
+ requestedDetails = openItems.get(new Integer(thisEntity.getSysKey()));
+ }
+ tabbedPane.setSelectedComponent(requestedDetails);
+ return requestedDetails;
+ }
+
+ public void setMenuBuilder(MenuBuilder myMenuBuilder) {
+ this.myMenuBuilder = myMenuBuilder;
+ }
+
+ @Override
+ public void remove(int sysKey) {
+ Integer sysKeyObj = new Integer(sysKey);
+ if (!openItems.containsKey(sysKeyObj)) return;
+ EntityDetails tabToClose = openItems.get(sysKeyObj);
+ tabbedPane.remove(tabToClose);
+ tabToClose.discardTabs();
+ openItems.remove(sysKeyObj);
+ }
+
+ public void closeAll(boolean keepOpen) {
+ ArrayList<Integer> toRemove = new ArrayList<Integer>();
+ for (Integer element : openItems.keySet()) {
+ if (keepOpen && openItems.get(element).equals(tabbedPane.getSelectedComponent())) continue;
+ toRemove.add(element);
+ }
+ for (Integer element : toRemove) {
+ remove(element.intValue());
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/LoginBox.java b/src/main/java/com/c2kernel/gui/LoginBox.java
new file mode 100644
index 0000000..aee469f
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/LoginBox.java
@@ -0,0 +1,327 @@
+package com.c2kernel.gui;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2003</p>
+ * <p>Company: </p>
+ * @author not attributable
+ * @version 1.0
+ */
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import com.c2kernel.common.InvalidDataException;
+import com.c2kernel.entity.proxy.AgentProxy;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+
+//import com.borland.jbcl.layout.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2003</p>
+ * <p>Company: </p>
+ * @author not attributable
+ * @version 1.0
+ */
+
+public class LoginBox extends JFrame {
+ private final int xMov;
+ private final int yMov;
+ public String errorMessage=new String("");
+ private int maxNumberLogon;
+ public boolean action = false;
+ public int loginAttemptNumber= 0;
+ JLabel passwordLabel = new JLabel();
+ JTextField username = new JTextField();
+ JButton OK = new JButton();
+ JLabel errorLabel = new JLabel();
+ JPasswordField password = new JPasswordField();
+ JButton Cancel = new JButton();
+ JLabel userLabel = new JLabel();
+ ImageIcon imageMainHolder = new ImageIcon();
+ JLabel pictureLabel = new JLabel();
+ GridBagLayout gridBagLayout1 = new GridBagLayout();
+ MainFrame mainFrameFather;
+ public static AgentProxy userAgent;
+ private boolean logged;
+ private boolean errorSet;
+
+ public LoginBox(int attempt,String title,String lastUser,String bottomMessage,
+ javax.swing.ImageIcon imageHolder,MainFrame mainFrame) {
+ String iconFile = Gateway.getProperty("AppIcon");
+ if (iconFile != null)
+ this.setIconImage(Resource.findImage(iconFile).getImage());
+ this.errorLabel.setText(bottomMessage);
+ if (errorMessage.compareTo("")!=0) this.errorLabel.setText(errorMessage);
+ mainFrameFather=mainFrame;
+ xMov=imageHolder.getIconWidth()+90;
+ yMov=imageHolder.getIconHeight()+40;
+ imageMainHolder=imageHolder;
+ try {
+ jbInit();
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ if (attempt==0) maxNumberLogon=5;
+ else maxNumberLogon=attempt;
+ if (title == null)
+ title = "Cristal2";
+ title = Language.translate("Log in to ")+title;
+ setTitle(title);
+ username.setText(lastUser);
+
+ }
+//OK button pressed OR Enter Hit
+ private void loginClicked(){
+ errorSet=false;
+ try {
+ if (this.getUser().length()>0 && this.getPassword().length()>0)
+ userAgent = Gateway.connect(this.getUser(), this.getPassword());
+ logged = (userAgent != null);
+ Logger.msg(7, "AbstractMain::standardSetUp() - Gateway.connect() OK.");
+ }
+ catch (InvalidDataException ex) {
+ String message = ex.getMessage();
+ int i = ex.getMessage().indexOf(' ');
+ if (i > -1 ) message = message.substring(i);
+ //Here us elanguage translate I guess :)
+ //if (message.length()>65 && message.substring(1,5).compareTo("User")==0)
+ // message = (message.substring(1,50)+ "... not found" );
+ this.errorLabel.setText(message);
+ logged= false;
+ errorSet=true;
+ }
+ if (!logged) {
+ Logger.msg("Login attempt "+loginAttemptNumber+" of "+maxNumberLogon+" failed");
+ if (loginAttemptNumber>=maxNumberLogon) Logger.die("Login failure limit reached");
+ if (!errorSet) this.errorLabel.setText(Language.translate("Please enter username & password"));
+// int posx=xMov+120;
+// int posy=yMov;
+// if (posy<135) posy=135;
+// float texstSize = errorLabel.getFont().getSize2D();
+// if (posx-xMov<errorLabel.getText().length()*(texstSize/2))
+// posx=errorLabel.getText().length()*(int)(texstSize/2)+xMov;
+
+
+ // obtain screen dimensions
+// Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+// this.setBounds(screen.width/2-posx/2, screen.height/2-posy/2,posx,posy);
+ this.validate();
+ }
+
+ else {
+ MainFrame.userAgent = userAgent;
+ this.setVisible(false);
+ mainFrameFather.mainFrameShow();
+ Logger.msg(1, "Login attempt "+loginAttemptNumber+" of "+maxNumberLogon+" succeeded.");
+ }
+ }
+
+
+ private void jbInit() throws Exception {
+
+ //this.getContentPane().setBackground(SystemColor.control);
+ this.setDefaultCloseOperation(EXIT_ON_CLOSE);
+ this.setEnabled(true);
+ this.setLocale(java.util.Locale.getDefault());
+ this.setResizable(false);
+ this.setState(Frame.NORMAL);
+ this.setTitle("");
+ LoginBox_this_keyAdapter submitListener = new LoginBox_this_keyAdapter(this);
+ username.addKeyListener(submitListener);
+ password.addKeyListener(submitListener);
+ this.getContentPane().setLayout(gridBagLayout1);
+
+ passwordLabel.setText(Language.translate("Password")+":");
+
+ OK.setActionCommand("OK");
+ OK.setSelected(true);
+ OK.setText(Language.translate("OK"));
+ OK.addActionListener(new Frame2_OK_actionAdapter(this));
+ OK.setPreferredSize(new Dimension(80,30));
+
+ Cancel.setActionCommand("Cancel");
+ Cancel.setText(Language.translate("Cancel"));
+ Cancel.addActionListener(new Frame2_Cancel_actionAdapter(this));
+ Cancel.setPreferredSize(new Dimension(80,30));
+
+ userLabel.setText(Language.translate("User")+":");
+ pictureLabel= new JLabel(imageMainHolder);
+ pictureLabel.setBorder(new EmptyBorder(0,0,0,5));
+ password.setText("");
+
+ username.setText("");
+
+ GridBagConstraints c = new GridBagConstraints();
+ initBasicConstraints(c,1,1,1,4);
+ c.anchor=GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx=0;
+ c.weighty=1;
+ getContentPane().add(pictureLabel,c);
+
+ initBasicConstraints(c,2,1,1,1);
+ c.anchor=GridBagConstraints.SOUTHWEST;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx=0;
+ c.weighty=1;
+ getContentPane().add(userLabel,c);
+ initBasicConstraints(c,2,2,1,1);
+ c.anchor=GridBagConstraints.SOUTHWEST;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx=0;
+ c.weighty=1;
+ getContentPane().add(passwordLabel,c);
+
+ initBasicConstraints(c,3,1,1,1);
+ c.anchor=GridBagConstraints.SOUTH;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx=1;
+ c.weighty=1;
+ getContentPane().add(username,c);
+
+ initBasicConstraints(c,3,2,1,1);
+ c.anchor=GridBagConstraints.SOUTH;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx=1;
+ c.weighty=1;
+ getContentPane().add(password,c);
+
+ JPanel buttonPane = new JPanel();
+ buttonPane.setLayout(new BoxLayout(buttonPane,BoxLayout.X_AXIS));
+ buttonPane.add(Box.createGlue());
+ buttonPane.add(OK);
+ buttonPane.add(Box.createRigidArea(new Dimension(5,0)));
+ buttonPane.add(Cancel);
+ buttonPane.add(Box.createGlue());
+ buttonPane.setBorder(new EmptyBorder(5,0,0,0));
+
+ initBasicConstraints(c,2,3,2,1);
+ c.weightx=0;
+ c.weighty=1;
+ c.anchor=GridBagConstraints.SOUTH;
+ c.fill = GridBagConstraints.BOTH;
+ getContentPane().add(buttonPane,c);
+
+ initBasicConstraints(c,2,4,2,1);
+ c.weightx=1;
+ c.weighty=1;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor= GridBagConstraints.SOUTHEAST;
+ JPanel msgPane = new JPanel();
+ msgPane.setLayout(new BoxLayout(msgPane,BoxLayout.X_AXIS));
+ msgPane.add(Box.createGlue());
+ msgPane.add(errorLabel);
+ msgPane.add(Box.createGlue());
+ getContentPane().add(msgPane,c);
+
+ ((JPanel)getContentPane()).setBorder(new EmptyBorder(0,0,0,5));
+ pack();
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation(screen.width/2-getWidth()/2, screen.height/2-getHeight()/2);
+
+ }
+
+
+
+ protected void initBasicConstraints(GridBagConstraints constraints,int x,int y,int width,int height)
+ {
+ constraints.gridx=x;
+ constraints.gridy=y;
+ constraints.gridwidth=width;
+ constraints.gridheight=height;
+ }
+
+ public String getUser() {
+ return username.getText();
+ }
+
+ public String getPassword() {
+ return String.valueOf(password.getPassword());
+ }
+
+ void Cancel_actionPerformed(ActionEvent e) {
+ Logger.die("User cancelled login.");
+ }
+
+ void OK_actionPerformed(ActionEvent e) {
+ try{
+ this.loginAttemptNumber++;
+ loginClicked();}
+ catch (Exception ex){
+ Logger.error(ex);
+ }
+ }
+
+ void this_keyPressed(KeyEvent e) {
+ if (e.getKeyCode()==10){
+ try{
+ this.loginAttemptNumber++;
+ loginClicked();
+ }
+ catch (Exception ex){
+ Logger.error(ex);
+ }
+ }
+ }
+
+}
+
+class Frame2_Cancel_actionAdapter implements java.awt.event.ActionListener {
+ LoginBox adaptee;
+
+ Frame2_Cancel_actionAdapter(LoginBox adaptee) {
+ this.adaptee = adaptee;
+ }
+ @Override
+public void actionPerformed(ActionEvent e) {
+ adaptee.Cancel_actionPerformed(e);
+ }
+}
+
+class Frame2_OK_actionAdapter implements java.awt.event.ActionListener {
+ LoginBox adaptee;
+
+ Frame2_OK_actionAdapter(LoginBox adaptee) {
+ this.adaptee = adaptee;
+ }
+ @Override
+public void actionPerformed(ActionEvent e) {
+ adaptee.OK_actionPerformed(e);
+ }
+}
+
+class LoginBox_this_keyAdapter extends java.awt.event.KeyAdapter {
+ LoginBox adaptee;
+
+ LoginBox_this_keyAdapter(LoginBox adaptee) {
+ this.adaptee = adaptee;
+ }
+ @Override
+public void keyPressed(KeyEvent e) {
+ adaptee.this_keyPressed(e);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/gui/Main.java b/src/main/java/com/c2kernel/gui/Main.java
new file mode 100644
index 0000000..7cf54cb
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/Main.java
@@ -0,0 +1,40 @@
+package com.c2kernel.gui;
+
+
+import com.c2kernel.process.Gateway;
+import com.c2kernel.process.StandardClient;
+import com.c2kernel.utils.Logger;
+
+
+/**
+ *
+ * @version $Revision: 1.15 $ $Date: 2004/10/26 11:33:56 $
+ * @author $Author: abranson $
+ */
+public class Main extends StandardClient
+{
+ static public void main(String[] args)
+ {
+ try
+ {
+ Gateway.init(readC2KArgs(args), false);
+ Logger.initConsole("GUI");
+ MainFrame client = new MainFrame();
+ client.showLogin();
+
+ }
+ catch( Exception ex )
+ {
+ Logger.error(ex);
+
+ try
+ {
+ Gateway.close();
+ }
+ catch(Exception ex1)
+ {
+ Logger.error(ex1);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/MainFrame.java b/src/main/java/com/c2kernel/gui/MainFrame.java
new file mode 100644
index 0000000..46937d0
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/MainFrame.java
@@ -0,0 +1,309 @@
+package com.c2kernel.gui;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Point;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+import com.c2kernel.entity.proxy.AgentProxy;
+import com.c2kernel.gui.tabs.execution.DefaultExecutor;
+import com.c2kernel.gui.tabs.execution.Executor;
+import com.c2kernel.gui.tree.Node;
+import com.c2kernel.gui.tree.NodeContext;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+/**
+ * @version $Revision: 1.83 $ $Date: 2005/09/12 14:56:19 $
+ * @author $Author: abranson $
+ */
+public class MainFrame extends javax.swing.JFrame {
+ public static TreeBrowser treeBrowser;
+ public static EntityTabManager myDesktopManager;
+ public static EntityFinder itemFinder;
+ protected static Node userNode = null;
+ protected MenuBuilder menuBuilder;
+ protected org.omg.CORBA.ORB orb;
+ public static Properties prefs = new Properties();
+ public static JLabel status = new JLabel();
+ public String logoURL;
+ public static AgentProxy userAgent;
+ protected JSplitPane splitPane;
+ public static boolean isAdmin;
+ int splitPanePos;
+ public static final JFileChooser xmlChooser;
+
+ static {
+ xmlChooser = new JFileChooser();
+ xmlChooser.addChoosableFileFilter(
+ new javax.swing.filechooser.FileFilter() {
+ @Override
+ public String getDescription() {
+ return "XML Files";
+ }
+ @Override
+ public boolean accept(File f) {
+ if (f.isDirectory() || (f.isFile() && f.getName().endsWith(".xml"))) {
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+ /** Creates new gui client for Cristal2 */
+
+ public MainFrame() {
+
+ // Load gui preferences
+ try {
+ FileInputStream prefsfile =
+ new FileInputStream("cristal.preferences");
+ prefs.load(prefsfile);
+ prefsfile.close();
+ } catch (IOException e) {
+ Logger.msg(2, "Creating new preference file");
+ }
+
+ // set look & feel from pref
+ try {
+ String lf = getPref("Style", null);
+ if (lf == null)
+ lf = UIManager.getCrossPlatformLookAndFeelClassName();
+ UIManager.setLookAndFeel(lf);
+ SwingUtilities.updateComponentTreeUI(this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void showLogin() {
+ // Log in
+ logoURL = Gateway.getProperty("Logo");
+ URL pictureUrl;
+ String bottomMessage =
+ Language.translate("Please enter username & password");
+ ImageIcon imageHolder = new ImageIcon("");
+ try {
+ pictureUrl = new URL(logoURL);
+ imageHolder = new ImageIcon(pictureUrl);
+ } catch (java.net.MalformedURLException m) {
+ imageHolder = Resource.findImage(logoURL);
+ }
+
+ LoginBox login =
+ new LoginBox(
+ 5,
+ Gateway.getProperty("Name"),
+ getPref("lastUser."+Gateway.getCentreId(), null),
+ bottomMessage,
+ imageHolder, this);
+
+ login.setVisible(true);
+ }
+
+ public void mainFrameShow() {
+ prefs.setProperty("lastUser."+Gateway.getCentreId(), userAgent.getName());
+ isAdmin = userAgent.getPath().hasRole("Admin");
+ GridBagLayout gridbag = new GridBagLayout();
+ getContentPane().setLayout(gridbag);
+
+ this.setTitle(
+ userAgent.getName()+"@"+Gateway.getProperty("Name") + " - " + Language.translate("Cristal 2"));
+
+ String iconFile = Gateway.getProperty("AppIcon");
+ if (iconFile != null)
+ this.setIconImage(Resource.findImage(iconFile).getImage());
+
+ //preload loading image
+ Resource.findImage("loading.gif");
+ // close listener
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ exitForm();
+ }
+ });
+ // initialise the desktop manager
+ myDesktopManager = new EntityTabManager();
+
+ //get the menu bar and add it to the frame
+ menuBuilder = new MenuBuilder(this);
+ setJMenuBar(menuBuilder);
+
+ // set the menu builder in the window manager
+ myDesktopManager.setMenuBuilder(menuBuilder);
+
+ userNode = new NodeContext(new DomainPath(""), myDesktopManager);
+ treeBrowser = new TreeBrowser(myDesktopManager, userNode);
+ treeBrowser.setVisible(getPref("ShowTree", "true").equals("true"));
+
+ // add search box
+ itemFinder = new EntityFinder();
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ gridbag.setConstraints(itemFinder, c);
+ getContentPane().add(itemFinder);
+ // register the browser as the key consumer
+ itemFinder.setDefaultConsumer(treeBrowser);
+
+ c.gridy++;
+ c.weightx = 1.0;
+ c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(getSplitPanel(), c);
+ getContentPane().add(getSplitPanel());
+ // setup status bar
+ status.setText("Cristal 2");
+ status.setFont(
+ new Font("SansSerif", Font.PLAIN, status.getFont().getSize()));
+ JPanel statusPanel = new JPanel();
+ statusPanel.setLayout(new BorderLayout());
+ statusPanel.setBorder(BorderFactory.createLoweredBevelBorder());
+ status.setForeground(Color.black);
+
+ statusPanel.add(status);
+ c.gridy++;
+ c.weighty = 0.0;
+ gridbag.setConstraints(statusPanel, c);
+ getContentPane().add(statusPanel);
+ pack();
+ String paneSize = getPref("WindowSize", null);
+ if (paneSize != null) {
+ StringTokenizer tok = new StringTokenizer(paneSize, ",");
+ Dimension window = new Dimension();
+ window.setSize(
+ Integer.parseInt(tok.nextToken()),
+ Integer.parseInt(tok.nextToken()));
+ this.setSize(window);
+ }
+ String panePos = getPref("WindowPosition", null);
+ if (panePos != null) {
+ StringTokenizer tok = new StringTokenizer(panePos, ",");
+ Point window =
+ new Point(
+ Integer.parseInt(tok.nextToken()),
+ Integer.parseInt(tok.nextToken()));
+ this.setLocation(window);
+ }
+ super.toFront();
+ this.validate();
+ this.setVisible(true);
+ }
+ public static String getPref(String name, String defaultValue) {
+ return prefs.getProperty(name, defaultValue);
+ }
+ public static void setPref(String name, String value) {
+ prefs.setProperty(name, value);
+ }
+ // things to do on exit
+ public void exitForm() {
+ // close connections
+ Gateway.close();
+ // save window sizing
+ setPref(
+ "WindowSize",
+ (int) (this.getSize().getWidth())
+ + ","
+ + (int) (this.getSize().getHeight()));
+ setPref(
+ "WindowPosition",
+ (int) (this.getLocation().getX())
+ + ","
+ + (int) (this.getLocation().getY()));
+ setPref(
+ "Style",
+ UIManager.getLookAndFeel().getClass().getName());
+ setPref(
+ "SplitPanePosition",
+ String.valueOf(splitPane.getDividerLocation()));
+ // save preferences file
+ try {
+ FileOutputStream prefsfile =
+ new FileOutputStream("cristal.preferences", false);
+ prefs.store(prefsfile, "Cristal 2");
+ prefsfile.close();
+ } catch (Exception e) {
+ Logger.warning(
+ "Could not write to preferences file. Preferences have not been updated.");
+ }
+ this.setVisible(false);
+ // allow waiting threads time to quit
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ }
+ System.exit(0);
+ }
+
+ public void toggleTree() {
+ boolean showTree = getPref("ShowTree", "true").equals("false");
+ setPref("ShowTree", String.valueOf(showTree));
+ if (!showTree) splitPanePos = splitPane.getDividerLocation();
+ getSplitPanel().getLeftComponent().setVisible(showTree);
+ if (showTree) getSplitPanel().setDividerLocation(splitPanePos);
+ getSplitPanel().validate();
+ }
+
+ public static JComboBox getExecutionPlugins() {
+ JComboBox plugins = new JComboBox();
+ // create execution selector
+ Executor defaultExecutor = new DefaultExecutor();
+ plugins.addItem(defaultExecutor);
+ plugins.setSelectedIndex(0);
+
+ // load execution plugins
+ String pluginList = Gateway.getProperty("Executors");
+ if (pluginList != null) {
+ StringTokenizer tok = new StringTokenizer(pluginList, ",");
+ while (tok.hasMoreTokens()) {
+ String pluginName = tok.nextToken();
+ try {
+ Class<?> pluginClass = Class.forName(pluginName);
+ Executor domainExecutor = (Executor)pluginClass.newInstance();
+ plugins.addItem(domainExecutor);
+ } catch (Exception ex) {
+ Logger.error("Could not load the executor plugin "+pluginName);
+ }
+ }
+ }
+ return plugins;
+ }
+ protected JSplitPane getSplitPanel()
+ {
+ // create the split pane, and add the Tree to it.
+ if (splitPane == null)
+ {
+ splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, treeBrowser, myDesktopManager);
+ splitPane.setDividerSize(5);
+ splitPanePos = Integer.parseInt(getPref("SplitPanePosition", "200"));
+ getSplitPanel().setDividerLocation(splitPanePos);
+ }
+ return splitPane;
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/MenuBuilder.java b/src/main/java/com/c2kernel/gui/MenuBuilder.java
new file mode 100644
index 0000000..255e7c1
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/MenuBuilder.java
@@ -0,0 +1,281 @@
+package com.c2kernel.gui;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemListener;
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLEditorKit;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.property.Property;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+/**
+ * @version $Revision: 1.47 $ $Date: 2006/03/03 13:52:21 $
+ * @author $Author: abranson $
+ */
+public class MenuBuilder extends JMenuBar implements ActionListener, ItemListener, HyperlinkListener
+{
+
+ protected UIManager.LookAndFeelInfo[] availableViews = UIManager.getInstalledLookAndFeels();
+ protected MainFrame myParentFrame;
+ protected JMenu fileMenu;
+ protected JMenu consoleMenu;
+ protected JMenu styleMenu;
+ protected JMenu prefMenu;
+ protected JMenu helpMenu;
+ protected HashMap<String, JMenu> availableMenus = new HashMap<String, JMenu>();
+
+ public MenuBuilder()
+ {}
+
+ /** Creates new DynamicMenuBuilder */
+ public MenuBuilder(MainFrame parentFrame)
+ {
+ myParentFrame = parentFrame;
+ fileMenu = new JMenu(Language.translate("File"));
+ consoleMenu = new JMenu(Language.translate("Console"));
+ styleMenu = new JMenu(Language.translate("Style"));
+ prefMenu = new JMenu("Preferences");
+ helpMenu = new JMenu(Language.translate("Help"));
+ availableMenus.put("file", fileMenu);
+ availableMenus.put("console", consoleMenu);
+ availableMenus.put("preferences", prefMenu);
+ availableMenus.put("style", styleMenu);
+ availableMenus.put("help", helpMenu);
+
+ addMenuItem(Language.translate("Close All"), "file", null, 0);
+ addMenuItem(Language.translate("Close Others"), "file", null, 0);
+ fileMenu.insertSeparator(2);
+ addMenuItem(Language.translate("Exit"), "file", null, 0);
+
+ addMenuItem(Language.translate("Local console"), "console", null, 0);
+ consoleMenu.insertSeparator(5);
+ addServerConsoles();
+
+ ButtonGroup styleButtonGroup = new ButtonGroup();
+ for (LookAndFeelInfo availableView : availableViews)
+ addMenuItem(availableView.getName(), "style", styleButtonGroup, 0);
+
+ addMenuItem(Language.translate("Tree Browser"), "preferences", null, MainFrame.getPref("ShowTree", "true").equals("true")?2:1);
+ addMenuItem(Language.translate("Outcome Field Help"), "preferences", null, MainFrame.getPref("ShowHelp", "true").equals("true")?2:1);
+ addMenuItem(Language.translate("Graph Properties"), "preferences", null, MainFrame.getPref("ShowProps", "true").equals("true")?2:1);
+ addMenuItem(Language.translate("About"), "help", null, 0);
+
+ add(fileMenu);
+ add(consoleMenu);
+ add(styleMenu);
+ add(prefMenu);
+ add(helpMenu);
+ }
+ /**
+ *
+ */
+ private void addServerConsoles() {
+ Enumeration<?> servers = Gateway.getLDAPLookup().searchEntities(new DomainPath("/servers"));
+ while(servers.hasMoreElements()) {
+ Path thisServerPath = (Path)servers.nextElement();
+ try {
+ int syskey = thisServerPath.getSysKey();
+ String serverName = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/Name", null)).getValue();
+ String portStr = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/ConsolePort", null)).getValue();
+ addMenuItem(serverName+":"+portStr, "console", null, 0);
+ } catch (Exception ex) {
+ Logger.error("Exception retrieving proxy server connection data for "+thisServerPath);
+ Logger.error(ex);
+ }
+ }
+
+ }
+
+ /**
+ * Adds a menu item to a menu. Adds an action listener to the menu item.
+ */
+ public void addMenuItem(String itemName, String menuName, ButtonGroup bg, int checkBox)
+ {
+ //checks to see if the menu to add the item to exists
+ if (availableMenus.containsKey(menuName))
+ {
+ JMenuItem myItem = new JMenuItem(itemName);
+ if (bg != null)
+ {
+ //if the menu item equals the current style, set it selected
+ myItem = new JRadioButtonMenuItem(itemName, UIManager.getLookAndFeel().getName().equals(itemName));
+ bg.add(myItem);
+ }
+ if (checkBox != 0)
+ {
+ myItem = new JCheckBoxMenuItem(itemName, checkBox == 2);
+ }
+ myItem.addActionListener(this);
+ JMenu myMenu = availableMenus.get(menuName);
+ myMenu.add(myItem);
+ }
+ }
+ //checks to see if the event dispatched is one of the
+ //styles that belong to the UIManager
+ public int isStyleChange(String style)
+ {
+ for (int i = 0; i < availableViews.length; i++)
+ {
+ if (style.equals(availableViews[i].getName()))
+ return i;
+ }
+ return -1;
+ }
+ //listens for events performed on the menu items
+ @Override
+ public void actionPerformed(java.awt.event.ActionEvent e)
+ {
+ String s = e.getActionCommand();
+ int i = isStyleChange(s);
+ if (s.equals("Close All") || s.equals("Close Others")) {
+ MainFrame.myDesktopManager.closeAll(s.equals("Close Others"));
+ }
+ else if (s.equals(Language.translate("Exit")))
+ myParentFrame.exitForm();
+ else if (s.equals(Language.translate("About")))
+ showAboutWindow();
+ else if (i >= 0)
+ {
+ try
+ {
+ UIManager.setLookAndFeel(availableViews[i].getClassName());
+ SwingUtilities.updateComponentTreeUI(myParentFrame);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ else if (s.equals(Language.translate("Tree Browser")))
+ {
+ myParentFrame.toggleTree();
+ }
+ else if (s.indexOf(":")>0) { // server console
+ try
+ {
+ String[] serverDetails = s.split(":");
+ new Console(serverDetails[0], Integer.parseInt(serverDetails[1])).setVisible(true);
+ }
+ catch (Exception ex)
+ {
+ Logger.error(ex);
+ }
+ }
+ else if (s.equals(Language.translate("Local console"))) {
+ try
+ {
+ new Console("localhost", Logger.getConsolePort()).setVisible(true);
+ }
+ catch (Exception ex)
+ {
+ Logger.error(ex);
+ }
+ }
+ else if (s.equals(Language.translate("Outcome Field Help"))) {
+ MainFrame.setPref("ShowHelp", String.valueOf(!MainFrame.getPref("ShowHelp", "true").equals("true")));
+ }
+ else if (s.equals(Language.translate("Graph Properties"))) {
+ MainFrame.setPref("ShowProps", String.valueOf(!MainFrame.getPref("ShowProps", "true").equals("true")));
+ }
+ else
+ Logger.msg(1, "MenuBuilder.actionPerformed() - No action associated with the event received");
+ }
+ //constructs an about dialog
+ public void showAboutWindow()
+ {
+ JOptionPane myPane = new JOptionPane();
+ Box about = Box.createVerticalBox();
+
+ String aboutInfo;
+ try
+ {
+ aboutInfo = FileStringUtility.file2String(Gateway.getProperty("about"));
+ }
+ catch (Exception e)
+ {
+ aboutInfo = Language.translate("Cristal 2 Itembrowser");
+ }
+ JLabel title = new JLabel(aboutInfo);
+ about.add(title);
+
+ about.add(new JLabel("Kernel version: "+Resource.getKernelVersion()));
+ about.add(new JLabel("Modules loaded: "+Gateway.getModuleManager().getModuleVersions()));
+ // get license info
+
+ StringBuffer lictxt = new StringBuffer();
+ try {
+ lictxt.append(Resource.getTextResource(null, "textFiles/license.html"));
+ } catch (ObjectNotFoundException e) { } // no kernel license found
+ for (String ns : Resource.getModuleBaseURLs().keySet()) {
+ String domlictxt;
+ try {
+ domlictxt = Resource.getTextResource(ns, "license.html");
+ lictxt.append(domlictxt).append("\n");
+ } catch (ObjectNotFoundException e) { }
+
+ }
+
+
+ JEditorPane license = new JEditorPane();
+ license.setEditable(false);
+ license.setEditorKit(new HTMLEditorKit());
+ license.setContentType("text/html");
+ license.addHyperlinkListener(this);
+ license.setText(lictxt.toString());
+ JScrollPane scroll = new JScrollPane(license);
+ scroll.setPreferredSize(new Dimension(300,200));
+ license.setCaretPosition(0);
+
+ about.add(scroll);
+ myPane.setMessage(about);
+ myPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
+ JDialog dialog = myPane.createDialog(null, Language.translate("About"));
+ dialog.setResizable(false);
+ Icon icon = Resource.findImage(Gateway.getProperty("banner"));
+ myPane.setIcon(icon);
+ dialog.pack();
+ dialog.setVisible(true);
+ }
+
+ @Override
+public void hyperlinkUpdate(HyperlinkEvent e) {
+ try {
+ if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+ Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler "+e.getURL().toString());
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+
+ @Override
+ public void itemStateChanged(java.awt.event.ItemEvent e)
+ {
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/TreeBrowser.java b/src/main/java/com/c2kernel/gui/TreeBrowser.java
new file mode 100644
index 0000000..bcafe00
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/TreeBrowser.java
@@ -0,0 +1,213 @@
+package com.c2kernel.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.ToolTipManager;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeExpansionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import com.c2kernel.gui.tree.Node;
+import com.c2kernel.gui.tree.NodeEntity;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Container for the tree browser
+ * @version $Revision: 1.31 $ $Date: 2006/01/17 07:49:44 $
+ * @author $Author: abranson $
+ */
+
+ // must put in top level list of loaded items, so we don't have duplicates
+public class TreeBrowser extends JPanel implements DomainKeyConsumer
+{
+ private EntityTabManager desktop;
+ protected JTree tree;
+ private Node userRoot;
+
+ public TreeBrowser(EntityTabManager target, Node userRoot) {
+ setLayout(new java.awt.BorderLayout());
+ //record the desktop and node factory for our item frames
+ this.desktop = target;
+ this.userRoot = userRoot;
+ this.setPreferredSize(new Dimension(300, 500));
+ tree = new JTree(new DefaultTreeModel(userRoot.getTreeNode()));
+ tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+ tree.setToggleClickCount(3); // need three clicks to expand a branch
+ tree.addTreeExpansionListener(
+ new TreeExpansionListener() {
+ @Override
+ public void treeCollapsed(TreeExpansionEvent e) {
+ //REVISIT: possible reaping here if things are getting heavy
+ }
+ @Override
+ public void treeExpanded(TreeExpansionEvent e) {
+ TreePath p = e.getPath();
+ // find the clicked tree node
+ DefaultMutableTreeNode nodeClicked = (DefaultMutableTreeNode)p.getLastPathComponent();
+ // run the tree builder if it is there.
+ DefaultMutableTreeNode loadNode = (DefaultMutableTreeNode)nodeClicked.getFirstChild();
+ if (loadNode.getUserObject() instanceof DynamicTreeBuilder) {
+ DynamicTreeBuilder loading = (DynamicTreeBuilder)loadNode.getUserObject();
+ if (loading.state == DynamicTreeBuilder.IDLE) {
+ loading.buildInfo(tree);
+ loading.start();
+ }
+ }
+ }
+ }
+ );
+
+ //Enable tool tips.
+ ToolTipManager.sharedInstance().registerComponent(tree);
+ tree.setCellRenderer(new ItemRenderer());
+ tree.addMouseListener(new TreeMouseListener());
+ JScrollPane myScrollPane = new JScrollPane(tree);
+ this.add(myScrollPane);
+ DefaultMutableTreeNode loadNode = (DefaultMutableTreeNode)userRoot.getTreeNode().getFirstChild();
+ DynamicTreeBuilder loading = (DynamicTreeBuilder)loadNode.getUserObject();
+ loading.buildInfo(tree);
+ loading.start();
+ }
+
+ @Override
+ public void push(DomainPath target) {
+ Logger.debug("Opening tree node "+target);
+ String[] components = target.getPath();
+ Node currentNode = userRoot;
+ Object[] treePath = new Object[components.length+1];
+ treePath[0] = currentNode.getTreeNode();
+ for (int i=0; i<components.length; i++) {
+ // create sub-path
+ String[] newPath = new String[i+1];
+ for (int j=0; j<newPath.length; j++)
+ newPath[j] = components[j];
+ DomainPath nextNodePath = new DomainPath(newPath);
+ Node nextNode = currentNode.getChildNode(nextNodePath);
+ if (nextNode == null) {
+ Logger.msg(6, "TreeBrowser.push() - creating "+nextNodePath);
+ nextNode = currentNode.newNode(nextNodePath);
+ currentNode.add(nextNode);
+ DynamicTreeBuilder builder = currentNode.getTreeBuilder();
+ builder.buildInfo(tree);
+ builder.add(nextNode);
+ }
+ treePath[i+1] = nextNode.getTreeNode();
+ currentNode = nextNode;
+ }
+ // select it
+ TreePath targetNode = new TreePath(treePath);
+ if (Logger.doLog(5)) dumpPath(targetNode, 5);
+
+ tree.clearSelection();
+ tree.addSelectionPath(targetNode);
+ tree.makeVisible(targetNode);
+ // open it
+ if (currentNode instanceof NodeEntity) {
+ MainFrame.status.setText("Opening "+currentNode.getName());
+ desktop.add((NodeEntity)currentNode);
+ MainFrame.status.setText("Done");
+ }
+ }
+
+ @Override
+ public void push(String name) {
+ // only interested in real paths
+ JOptionPane.showMessageDialog(null, "'"+name+"' was not found.",
+ "No results", JOptionPane.INFORMATION_MESSAGE);
+
+ }
+
+ private static void dumpPath(TreePath selPath, int logLevel) {
+ if (selPath == null) { Logger.msg(logLevel, "TreeBrowser.dumpPath() - selPath null"); return; }
+ for (int i =0; i<selPath.getPath().length; i++)
+ Logger.msg(logLevel, "TreeBrowser.dumpPath() - selPath "+i+" = "+selPath.getPath()[i]);
+ }
+
+ private class ItemRenderer extends DefaultTreeCellRenderer {
+ public ItemRenderer() {
+ }
+
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf,
+ int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+ Object thisLeaf = ((DefaultMutableTreeNode)value).getUserObject();
+ if (thisLeaf instanceof Node) {
+ Node thisNode = (Node)thisLeaf;
+ if (thisNode.getIcon() !=null) setIcon(thisNode.getIcon());
+ setToolTipText(thisNode.getType());
+ }
+ else if (thisLeaf instanceof DynamicTreeBuilder) {
+ DynamicTreeBuilder thisLoader = (DynamicTreeBuilder)thisLeaf;
+ ImageIcon loadGif = thisLoader.getIcon();
+ setIcon(loadGif);
+ loadGif.setImageObserver(tree);
+ setToolTipText("Tree Content Loader");
+ }
+ return this;
+ }
+ }
+
+ private class TreeMouseListener extends MouseAdapter {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger())
+ showPopup(e);
+ else {
+ Object source = getNodeAt(e);
+ if (source == null) return;
+ if (e.getClickCount() == 2) {
+ if (source instanceof NodeEntity) {
+ NodeEntity thisNode = (NodeEntity)source;
+ desktop.add(thisNode);
+ MainFrame.status.setText("Opened "+thisNode.getName());
+ }
+ if (source instanceof DynamicTreeBuilder) {
+ DynamicTreeBuilder thisLoader = (DynamicTreeBuilder)source;
+ if (thisLoader.state == DynamicTreeBuilder.PARTIAL)
+ thisLoader.start();
+ }
+ }
+ }
+ }
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ showPopup(e);
+ }
+ }
+ private void showPopup(MouseEvent e) {
+ Object source = getNodeAt(e);
+ if (source == null) return;
+ if (source instanceof Node) {
+ Node thisNode = (Node)source;
+ thisNode.getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
+ }
+ }
+ private Object getNodeAt(MouseEvent e) {
+ Object source = null;
+ TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
+ if (selPath != null)
+ try {
+ DefaultMutableTreeNode nodeClicked = (DefaultMutableTreeNode)selPath.getLastPathComponent();
+ source = nodeClicked.getUserObject(); // fetch its nodeItem
+ }
+ catch (Exception ex) { } // Not a node that was clicked on
+
+ return source;
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/collection/AggregationMemberRenderer.java b/src/main/java/com/c2kernel/gui/collection/AggregationMemberRenderer.java
new file mode 100644
index 0000000..8c4b80f
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/collection/AggregationMemberRenderer.java
@@ -0,0 +1,125 @@
+package com.c2kernel.gui.collection;
+
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.collection.AggregationMember;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.utils.Logger;
+
+/**
+ * @version $Revision: 1.24 $ $Date: 2005/12/01 14:23:15 $
+ * @author $Author: abranson $
+ */
+
+public class AggregationMemberRenderer implements VertexRenderer
+{
+
+ private Aggregation mAggregation = null;
+
+ public AggregationMemberRenderer()
+ {
+ }
+
+ public void setAggregation(Aggregation agg)
+ {
+ mAggregation = agg;
+ }
+
+
+ @Override
+ public void draw(Graphics2D g2d, Vertex vertex)
+ {
+ GraphPoint centre = vertex.getCentrePoint();
+ GraphPoint[] outline = vertex.getOutlinePoints();
+ FontMetrics metrics = g2d.getFontMetrics();
+
+ AggregationMember memberPair = mAggregation.getMemberPair(vertex.getID());
+
+ try
+ {
+ String name = memberPair.getEntityName();
+
+ g2d.drawString( name,
+ centre.x-metrics.stringWidth(name)/2,
+ vertex.getID()%2==0?topYOfOutline(outline):bottomYOfOutline(outline)+metrics.getHeight() );
+
+ g2d.drawImage
+ (
+ memberPair.getImage(),
+ centre.x - 8,
+ centre.y - 8,
+ null
+ );
+
+
+
+ // Draw the outline of the vertex
+ if(outline.length > 1)
+ {
+ for(int i=0; i<outline.length-1; i++)
+ {
+ g2d.drawLine
+ (
+ outline[i].x,
+ outline[i].y,
+ outline[i+1].x,
+ outline[i+1].y
+ );
+ }
+
+ g2d.drawLine
+ (
+ outline[outline.length-1].x,
+ outline[outline.length-1].y,
+ outline[0].x,
+ outline[0].y
+ );
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ Logger.error("AggregationMemberRenderer::draw() " + ex);
+ }
+ }
+
+
+ int topYOfOutline(GraphPoint[] outline)
+ {
+ int topY = outline[0].y;
+ int i = 0;
+
+
+ for(i=1; i<outline.length; i++)
+ {
+ if(outline[i].y < topY)
+ {
+ topY = outline[i].y;
+ }
+ }
+
+ return topY;
+ }
+
+ int bottomYOfOutline(GraphPoint[] outline)
+ {
+ int bottomY = outline[0].y;
+ int i = 0;
+
+
+ for(i=1; i<outline.length; i++)
+ {
+ if(outline[i].y > bottomY)
+ {
+ bottomY = outline[i].y;
+ }
+ }
+
+ return bottomY;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/collection/CollectionFrame.java b/src/main/java/com/c2kernel/gui/collection/CollectionFrame.java
new file mode 100644
index 0000000..76a964b
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/collection/CollectionFrame.java
@@ -0,0 +1,41 @@
+package com.c2kernel.gui.collection;
+
+import java.awt.GridLayout;
+
+import javax.swing.JFrame;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.gui.tabs.CollectionPane;
+
+
+/**
+ * @version $Revision: 1.10 $ $Date: 2003/04/06 15:06:36 $
+ * @author $Author: abranson $
+ */
+
+public class CollectionFrame extends JFrame
+{
+
+ private CollectionPane mCollectionPane = new CollectionPane();
+
+ public CollectionFrame()
+ {
+ createLayout();
+ }
+
+ public void setAggregation(Aggregation aggregation)
+ {
+ mCollectionPane.add(aggregation);
+ }
+
+
+ private void createLayout()
+ {
+ getContentPane().setLayout(new GridLayout(1, 1));
+
+ getContentPane().add(mCollectionPane);
+
+ setSize(1000, 1000);
+ setVisible(true);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/collection/PropertyPanel.java b/src/main/java/com/c2kernel/gui/collection/PropertyPanel.java
new file mode 100644
index 0000000..38e3fd3
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/collection/PropertyPanel.java
@@ -0,0 +1,37 @@
+package com.c2kernel.gui.collection;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.collection.AggregationMember;
+import com.c2kernel.collection.CollectionMember;
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexPropertyPanel;
+
+public class PropertyPanel extends VertexPropertyPanel {
+
+ Aggregation mCollection;
+
+ public PropertyPanel() {
+ super();
+ }
+
+ public void setCollection(Aggregation collection) {
+ mCollection = collection;
+ }
+
+ @Override
+ public void setVertex(Vertex vert) {
+ try {
+ CollectionMember newMember = mCollection.getMember(vert.getID());
+ if (newMember instanceof AggregationMember) {
+ super.setVertex((AggregationMember)newMember);
+ return;
+ }
+ else
+ clear();
+ } catch (ObjectNotFoundException ex) {
+ clear();
+ selObjClass.setText("No Collection Member object found");
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/collection/SelectedMemberPanel.java b/src/main/java/com/c2kernel/gui/collection/SelectedMemberPanel.java
new file mode 100644
index 0000000..489f316
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/collection/SelectedMemberPanel.java
@@ -0,0 +1,164 @@
+package com.c2kernel.gui.collection;
+
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.JToggleButton;
+
+import com.c2kernel.collection.AggregationMember;
+import com.c2kernel.collection.MembershipException;
+import com.c2kernel.entity.proxy.EntityProxy;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.DomainKeyConsumer;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.graph.view.SelectedVertexPanel;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.lookup.EntityPath;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.10 $
+ * $Date: 2005/05/12 10:12:52 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+public class SelectedMemberPanel extends SelectedVertexPanel implements DomainKeyConsumer {
+
+ JLabel slotNumber = new JLabel();
+ JTextField memberKey = new JTextField(14);
+
+ JButton findButton = new JButton(Language.translate("Find"));
+ JToggleButton changeButton = new JToggleButton(Language.translate("Change"));
+ JButton removeButton = new JButton(Language.translate("Remove"));
+
+ SelectedMemberPanel me;
+ AggregationMember selectedMember = null;
+
+ public SelectedMemberPanel() {
+ me=this;
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+ JPanel attrs = new JPanel(new GridLayout(3,2));
+ attrs.add(new JLabel(Language.translate("Slot Number:")));
+ attrs.add(slotNumber);
+ attrs.add(new JLabel(Language.translate("Assigned Member:")));
+ attrs.add(memberKey);
+ memberKey.setEditable(false);
+
+ add(attrs);
+ add(Box.createVerticalStrut(10));
+
+ findButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ String code = memberKey.getText();
+ if (code == null || code.length() == 0)
+ code = memberKey.getText().replace('/',' ');
+ MainFrame.itemFinder.pushNewKey(code);
+ }
+ });
+
+ changeButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ if (changeButton.getModel().isSelected()) {
+ MainFrame.status.setText(Language.translate("Please scan or type your barcode to assign in the top field"));
+ MainFrame.itemFinder.setConsumer(me, "Assign");
+ findButton.setEnabled(false);
+ }
+ else {
+ MainFrame.status.setText("");
+ MainFrame.itemFinder.clearConsumer(me);
+ if (selectedMember.getEntityKey() > -1) findButton.setEnabled(true);
+ }
+ }
+ });
+
+ removeButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ selectedMember.clearEntity();
+ selectedMember.getProperties().remove("Name");
+ select(selectedMember);
+ }
+ });
+
+ Box buttonBox = Box.createHorizontalBox();
+ buttonBox.add(findButton);
+ if (MainFrame.isAdmin) {
+ buttonBox.add(changeButton);
+ buttonBox.add(removeButton);
+ }
+
+ setButtons(false);
+ add(buttonBox);
+ }
+
+ @Override
+ public void select(Vertex vert) {
+ selectedMember = (AggregationMember)vert;
+ slotNumber.setText(String.valueOf(vert.getID()));
+ int memberId = selectedMember.getEntityKey();
+ String name = "Empty";
+ try {
+ EntityProxy member = Gateway.getProxyManager().getProxy(new EntityPath(memberId));
+ name = member.getName();
+ } catch (Exception e) { }
+ memberKey.setText(name);
+ setButtons(true);
+
+ revalidate();
+ }
+
+ @Override
+ public void clear() {
+ slotNumber.setText("");
+ memberKey.setText("");
+ setButtons(false);
+ revalidate();
+ }
+
+ public void setButtons(boolean state) {
+ findButton.setEnabled(state);
+ changeButton.getModel().setSelected(false);
+ changeButton.setEnabled(state);
+ removeButton.setEnabled(state);
+ MainFrame.itemFinder.clearConsumer(me);
+ }
+ /**
+ *
+ */
+ @Override
+ public void push(DomainPath key) {
+ MainFrame.status.setText("Assigning entity "+key.getSysKey()+" to slot "+selectedMember.getID());
+ try {
+ selectedMember.assignEntity(key.getSysKey());
+ select(selectedMember);
+ } catch (MembershipException ex) {
+ JOptionPane.showMessageDialog(null, "Product does not fit in this slot", "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void push(String name) {
+ JOptionPane.showMessageDialog(null, "Product is not known in this centre", "Error", JOptionPane.ERROR_MESSAGE);
+ }
+
+}
+
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/AutoScrollController.java b/src/main/java/com/c2kernel/gui/graph/controller/AutoScrollController.java
new file mode 100644
index 0000000..a09d6a2
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/AutoScrollController.java
@@ -0,0 +1,41 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+import com.c2kernel.gui.graph.view.GraphPanel;
+
+
+public class AutoScrollController implements MouseMotionListener
+{
+ private GraphPanel mGraphPanel = null;
+
+
+ public void setGraphPanel(GraphPanel graphPanel)
+ {
+ mGraphPanel = graphPanel;
+ mGraphPanel.addMouseMotionListener(this);
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent me)
+ {
+ Point mousePoint = null;
+
+
+ if(mGraphPanel != null)
+ {
+ mousePoint = me.getPoint();
+ mGraphPanel.scrollRectToVisible(new Rectangle(mousePoint.x, mousePoint.y, 1, 1));
+ }
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/DeletionController.java b/src/main/java/com/c2kernel/gui/graph/controller/DeletionController.java
new file mode 100644
index 0000000..4a8fb47
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/DeletionController.java
@@ -0,0 +1,92 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JButton;
+
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.Vertex;
+
+
+// The deletion controller is responsible for deleting the present
+// selection within the graph.
+//
+// The controller listens to:
+// * The graph model to determine if there is a selection
+// * The delete button
+// * The graph panel for the typing of the delete key
+//
+// The controller modifies:
+// * The graph model to delete the current selection
+// * The delete button to enable it only when there is a selection
+public class DeletionController extends KeyAdapter implements Observer, ActionListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private JButton mDeleteButton = null;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ mGraphModelManager.addObserver(this);
+ }
+
+
+ public void setDeleteButton(JButton deleteButton)
+ {
+ mDeleteButton = deleteButton;
+ mDeleteButton.addActionListener(this);
+ }
+
+
+ // Invoked by the graph model
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ SelectionChangedEvent event = null;
+ DirectedEdge selectedEdge = null;
+ Vertex[] selectedVertices = null;
+
+
+ // If the selected edge has changed
+ if(arg instanceof SelectionChangedEvent && mDeleteButton != null && mGraphModelManager.isEditable())
+ {
+ // Enable the button if a single edge or single vertex is selected
+ event = (SelectionChangedEvent)arg;
+
+ selectedEdge = event.mSelection.mEdge;
+ selectedVertices = event.mSelection.mVertices;
+
+ mDeleteButton.setEnabled((selectedEdge != null) || (selectedVertices != null));
+ }
+ }
+
+
+ // Invoked by the graph panel
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if(e.getKeyCode() == KeyEvent.VK_DELETE && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().deleteSelection();
+ }
+ }
+
+
+ // Invoked by the delete button
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ if(mGraphModelManager != null && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().deleteSelection();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/EdgeConstructionController.java b/src/main/java/com/c2kernel/gui/graph/controller/EdgeConstructionController.java
new file mode 100644
index 0000000..f76d314
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/EdgeConstructionController.java
@@ -0,0 +1,253 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.EditorModeListener;
+import com.c2kernel.gui.graph.view.EditorToolBar;
+
+
+public class EdgeConstructionController extends MouseAdapter implements EditorModeListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private EditorToolBar mEditorToolBar = null;
+
+
+ /**********/
+ /* States */
+ /**********/
+ private final Integer kOtherMode = new Integer(0);
+ private final Integer kWaitOrigin = new Integer(1);
+ private final Integer kWaitTerminus = new Integer(2);
+
+
+ /**********/
+ /* Events */
+ /**********/
+ private final int kEdgeEntered = 0;
+ private final int kOtherEntered = 1;
+ private final int kPressOnVertex = 2;
+ private final int kDrag = 3;
+ private final int kReleaseOnTerminus = 4;
+ private final int kReleaseOnNothing = 5;
+
+
+ /***********/
+ /* Actions */
+ /***********/
+
+ private interface Action
+ {
+ public void doIt(Object data);
+ }
+
+
+ private Action mSetOriginVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeOriginVertex((Vertex)data);
+ }
+ }
+ };
+
+
+ private Action mSetEndPoint = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeEndPoint((Point)data);
+ }
+ }
+ };
+
+
+ private Action mClearEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setNewEdgeOriginVertex(null);
+ mGraphModelManager.getModel().setNewEdgeEndPoint(null);
+ }
+ }
+ };
+
+
+ private Action mCreateEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ if((mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().createDirectedEdge
+ (
+ mGraphModelManager.getModel().getNewEdgeOriginVertex(),
+ (Vertex)data,
+ mEditorToolBar.getSelectedEdgeType()
+ );
+ mGraphModelManager.getModel().setNewEdgeOriginVertex(null);
+ mGraphModelManager.getModel().setNewEdgeEndPoint(null);
+ }
+ }
+ };
+
+
+ /***********************************/
+ /* Finite State Transition Network */
+ /***********************************/
+
+ private Object[][][] mFSTN =
+ {// OtherMode WaitOrigin WaitTerminus
+ /* EdgeEntered */ {{null, kWaitOrigin}, null , null },
+ /* OtherEntered */ { null , {null , kOtherMode} , null },
+ /* PressOnVertex */ { null , {mSetOriginVertex, kWaitTerminus}, null },
+ /* Drag */ { null , null , {mSetEndPoint, null} },
+ /* ReleaseOnTerminus */ { null , null , {mCreateEdge , kWaitOrigin}},
+ /* ReleaseOnNothing */ { null , null , {mClearEdge , kWaitOrigin}}
+ };
+
+
+ /*****************/
+ /* Current state */
+ /*****************/
+
+ private Integer mState = kOtherMode;
+
+
+ /**************************/
+ /* Event processing logic */
+ /**************************/
+
+ private void processEvent(int event, Object data)
+ {
+ Object[] transition = mFSTN[event][mState.intValue()];
+ Action action = null;
+ Integer nextState = null;
+
+ if(transition != null)
+ {
+ action = (Action)transition[0];
+ nextState = (Integer)transition[1];
+
+ if(action != null)
+ {
+ action.doIt(data);
+ }
+
+ if(nextState != null)
+ {
+ mState = nextState;
+ }
+ }
+ }
+
+
+ /********************/
+ /* Public interface */
+ /********************/
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ public void setEditorToolBar(EditorToolBar editorToolBar)
+ {
+ mEditorToolBar = editorToolBar;
+ mEditorToolBar.addEditorModeListener(this);
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ if(idOfNewMode.equals("Edge"))
+ {
+ processEvent(kEdgeEntered, null);
+ }
+ else
+ {
+ processEvent(kOtherEntered, null);
+ }
+ }
+
+
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ Vertex vertex = null;
+ Point mousePoint = null;
+
+ if(mGraphModelManager != null)
+ {
+ // Determine if there is a vertex under the mouse cursor
+ mousePoint = me.getPoint();
+ vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ // If the mouse has been pressed on a vertex
+ if(vertex != null)
+ {
+ processEvent(kPressOnVertex, vertex);
+ }
+ }
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent me)
+ {
+ Vertex vertex = null;
+ Point mousePoint = null;
+
+ if(mGraphModelManager != null)
+ {
+ // Determine if there is a vertex under the mouse cursor
+ mousePoint = me.getPoint();
+ vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ // If the mouse has been released on a vertex which is not the origin vertex
+ if((vertex != null) && (vertex != mGraphModelManager.getModel().getNewEdgeOriginVertex()))
+ {
+ processEvent(kReleaseOnTerminus, vertex);
+ }
+ else
+ {
+ processEvent(kReleaseOnNothing, null);
+ }
+ }
+ }
+
+
+ @Override
+ public void mouseExited(MouseEvent me)
+ {
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent me)
+ {
+ processEvent(kDrag, me.getPoint());
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/MultiSelectionDragController.java b/src/main/java/com/c2kernel/gui/graph/controller/MultiSelectionDragController.java
new file mode 100644
index 0000000..2d77996
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/MultiSelectionDragController.java
@@ -0,0 +1,571 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.Point;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.ElasticBand;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.GraphableVertex;
+import com.c2kernel.graph.model.Selection;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.EditorModeListener;
+
+
+public class MultiSelectionDragController
+extends MouseAdapter
+implements EditorModeListener, KeyListener
+{
+ private class ResizeInf
+ {
+ public int mMousePressedX = 0;
+ public int mMousePressedY = 0;
+ public Vertex mSelectedVertex = null;
+ public GraphPoint[] mOldOutline = null;
+ public int mCentreX = 0;
+ public int mCentreY = 0;
+ public int mOldHeight = 0;
+ public int mOldWidth = 0;
+ }
+ private ResizeInf mResizeInf = new ResizeInf();
+
+ private class DispForSelection
+ {
+ public int mXDisp = 0;
+ public int mYDisp = 0;
+ }
+ private DispForSelection mDispForSelection = null;
+
+ private class VertexAndDisp
+ {
+ public Vertex mVertex = null;
+ public int mXDisp = 0;
+ public int mYDisp = 0;
+ }
+
+ protected GraphModelManager mGraphModelManager = null;
+
+
+ /**********/
+ /* States */
+ /**********/
+ protected final Integer kOtherMode = new Integer(0);
+ protected final Integer kWaiting = new Integer(1);
+ protected final Integer kResizing = new Integer(2);
+ protected final Integer kDraggingSelection = new Integer(3);
+ protected final Integer kStretching = new Integer(4);
+
+
+ /**********/
+ /* Events */
+ /**********/
+ protected final int kSelectEntered = 0;
+ protected final int kOtherEntered = 1;
+ protected final int kPressOnEdge = 2;
+ protected final int kPressOnVertex = 3;
+ protected final int kPressOnSelection = 4;
+ protected final int kPressOnResizePad = 5;
+ protected final int kCTRLPressOnVertex = 6;
+ protected final int kCTRL_A = 7;
+ protected final int kPressOnNothing = 8;
+ protected final int kDrag = 9;
+ protected final int kRelease = 10;
+ protected final int kZoomIn = 11;
+
+ /***********/
+ /* Actions */
+ /***********/
+
+ protected interface Action
+ {
+ public void doIt(Object data);
+ }
+
+
+ protected Action mStoreResizeInf = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ GraphPoint centre = null;
+
+ mResizeInf.mMousePressedX = mousePoint.x;
+ mResizeInf.mMousePressedY = mousePoint.y;
+ mResizeInf.mSelectedVertex = mGraphModelManager.getModel().getSelection().mVertices[0];
+ mResizeInf.mOldOutline = mResizeInf.mSelectedVertex.getOutlinePoints();
+ centre = mResizeInf.mSelectedVertex.getCentrePoint();
+ mResizeInf.mCentreX = centre.x;
+ mResizeInf.mCentreY = centre.y;
+ mResizeInf.mOldHeight = mResizeInf.mSelectedVertex.getHeight();
+ mResizeInf.mOldWidth = mResizeInf.mSelectedVertex.getWidth();
+ }
+ };
+
+
+ protected Action mResizeVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ int resizeX = 0;
+ int resizeY = 0;
+
+
+ // Calculate how much the old outline should be resized
+ resizeX = mousePoint.x - mResizeInf.mMousePressedX;
+ resizeY = mousePoint.y - mResizeInf.mMousePressedY;
+
+ // Clip the resize so that outline does not get any
+ // smaller than 10 x 10 pixels
+ if(resizeX < -mResizeInf.mOldWidth/2 + 10)
+ {
+ resizeX = -mResizeInf.mOldWidth/2 + 10;
+ }
+
+ if(resizeY < -mResizeInf.mOldHeight/2 + 10)
+ {
+ resizeY = -mResizeInf.mOldHeight/2 + 10;
+ }
+
+ if (mGraphModelManager.isEditable()) {
+ mResizeInf.mSelectedVertex.setOutlinePoints(newOutline(resizeX, resizeY));
+ mGraphModelManager.forceNotify();
+ }
+ }
+
+
+ private GraphPoint[] newOutline(int resizeX, int resizeY)
+ {
+ GraphPoint[] newOutline = new GraphPoint[mResizeInf.mOldOutline.length];
+ int x = 0;
+ int y = 0;
+ int i = 0;
+
+
+ for(i=0; i<newOutline.length; i++)
+ {
+ if(mResizeInf.mOldOutline[i].x > mResizeInf.mCentreX)
+ {
+ x = mResizeInf.mOldOutline[i].x + resizeX;
+ }
+ else if(mResizeInf.mOldOutline[i].x < mResizeInf.mCentreX)
+ {
+ x = mResizeInf.mOldOutline[i].x - resizeX;
+ }
+ else
+ {
+ x = mResizeInf.mOldOutline[i].x;
+ }
+
+ if(mResizeInf.mOldOutline[i].y > mResizeInf.mCentreY)
+ {
+ y = mResizeInf.mOldOutline[i].y + resizeY;
+ }
+ else if(mResizeInf.mOldOutline[i].y < mResizeInf.mCentreY)
+ {
+ y = mResizeInf.mOldOutline[i].y - resizeY;
+ }
+ else
+ {
+ y = mResizeInf.mOldOutline[i].y;
+ }
+
+ newOutline[i] = new GraphPoint(x, y);
+ }
+
+ return newOutline;
+ }
+ };
+
+
+ protected Action mSelectEdge = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Selection selection = new Selection((DirectedEdge)data, null, 0, 0, 0, 0);
+
+ mGraphModelManager.getModel().setSelection(selection);
+ }
+ };
+
+
+ protected Action mSelectVertexAndStoreDisp = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ VertexAndDisp vertexAndDisp = (VertexAndDisp)data;
+ GraphPoint centrePoint = vertexAndDisp.mVertex.getCentrePoint();
+ Selection selection = new Selection(null,
+ new Vertex[] {vertexAndDisp.mVertex},
+ centrePoint.x,
+ centrePoint.y,
+ centrePoint.x,
+ centrePoint.y);
+
+ mGraphModelManager.getModel().setSelection(selection);
+ mDispForSelection = new DispForSelection();
+ mDispForSelection.mXDisp = vertexAndDisp.mXDisp;
+ mDispForSelection.mYDisp = vertexAndDisp.mYDisp;
+ }
+ };
+
+
+ protected Action mStoreDisp = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mDispForSelection = (DispForSelection)data;
+ }
+ };
+
+
+ protected Action mToggleVertex = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Vertex vertex = (Vertex)data;
+
+ if(mGraphModelManager.getModel().inSelection(vertex))
+ {
+ mGraphModelManager.getModel().removeFromSelection(vertex);
+ }
+ else
+ {
+ mGraphModelManager.getModel().addToSelection(vertex);
+ }
+ }
+ };
+
+
+ protected Action mSelectAll = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().selectAll();
+ }
+ };
+
+
+ protected Action mCreateBand = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point fixedCorner = (Point)data;
+
+ mGraphModelManager.getModel().setElasticBand(new ElasticBand(fixedCorner, fixedCorner));
+ }
+ };
+
+
+ protected Action mMoveSelection = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ Point mousePoint = (Point)data;
+ int topLeftX = mousePoint.x - mDispForSelection.mXDisp;
+ int topLeftY = mousePoint.y - mDispForSelection.mYDisp;
+ if (mGraphModelManager.isEditable()) {
+ mGraphModelManager.getModel().moveAbsoluteSelection(topLeftX, topLeftY);
+ }
+ }
+ };
+
+
+ protected Action mResizeBand = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().resizeElasticBand((Point)data);
+ }
+ };
+
+
+ protected Action mSelectContents = new Action()
+ {
+ @Override
+ public void doIt(Object data)
+ {
+ mGraphModelManager.getModel().selectContentsOfElasticBand();
+ }
+ };
+
+ protected Action mZoomIn = new Action()
+ {
+ @Override
+ public void doIt(Object data) // data is the clicked vertex
+ {
+ // Need to get child graph model out of the vertex before we can zoom in
+ if (data instanceof Vertex) {
+ Vertex zoomTo = (Vertex)data;
+ if (((GraphableVertex)zoomTo).getIsComposite()) mGraphModelManager.zoomIn(zoomTo);
+ }
+ }
+ };
+
+ /***********************************/
+ /* Finite State Transition Network */
+ /***********************************/
+
+ protected Object[][][] mFSTN =
+ {// OtherMode Waiting Resizing DraggingSelection Stretching
+ /* SelectEntered */ {{null, kWaiting}, null , null , null , null },
+ /* OtherEntered */ { null , {null , kOtherMode }, null , null , null },
+ /* PressOnEdge */ { null , {mSelectEdge , null }, null , null , null },
+ /* PressOnVertex */ { null , {mSelectVertexAndStoreDisp, kDraggingSelection}, null , null , null },
+ /* PressOnSelection */ { null , {mStoreDisp , kDraggingSelection}, null , null , null },
+ /* PressOnResizePad */ { null , {mStoreResizeInf , kResizing }, null , null , null },
+ /* CTRLPressOnVertex */ { null , {mToggleVertex , null }, null , null , null },
+ /* CTRL_A */ { null , {mSelectAll , null }, null , null , null },
+ /* PressOnNothing */ { null , {mCreateBand , kStretching }, null , null , null },
+ /* Drag */ { null , null , {mResizeVertex, null }, {mMoveSelection, null }, {mResizeBand , null }},
+ /* Release */ { null , null , {null , kWaiting}, {null , kWaiting}, {mSelectContents, kWaiting}},
+ /* Double Click */ { null , {mZoomIn , null }, null , null , null },
+ };
+
+
+ /*****************/
+ /* Current state */
+ /*****************/
+
+ private Integer mState = kWaiting;
+
+
+ /**************************/
+ /* Event processing logic */
+ /**************************/
+
+ protected void processEvent(int event, Object data)
+ {
+ Object[] transition = mFSTN[event][mState.intValue()];
+ Action action = null;
+ Integer nextState = null;
+
+ if(transition != null)
+ {
+ action = (Action)transition[0];
+ nextState = (Integer)transition[1];
+
+ if(action != null)
+ {
+ action.doIt(data);
+ }
+
+ if(nextState != null)
+ {
+ mState = nextState;
+ }
+ }
+ }
+
+
+ /********************/
+ /* Public interface */
+ /********************/
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ if(idOfNewMode.equals("Select"))
+ {
+ processEvent(kSelectEntered, null);
+ }
+ else
+ {
+ processEvent(kOtherEntered, null);
+ }
+ }
+
+
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ int modifiers = me.getModifiers();
+
+ if(mGraphModelManager != null)
+ {
+ if((modifiers & InputEvent.CTRL_MASK) == 0)
+ {
+ mousePressedWithoutCTRL(me.getPoint());
+ }
+ else
+ {
+ mousePressedWithCTRL(me.getPoint());
+ }
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent me)
+ {
+ if (me.getClickCount() == 2) { // want double click
+ Point clickedSpot = me.getPoint();
+ GraphPoint mouseGPoint = new GraphPoint(clickedSpot.x, clickedSpot.y);
+ Vertex clicked = mGraphModelManager.getModel().getVertex(mouseGPoint);
+ if (clicked != null)
+ processEvent(kZoomIn, clicked);
+ }
+ }
+
+ private void mousePressedWithoutCTRL(Point mousePoint)
+ {
+ GraphPoint mouseGPoint = new GraphPoint(mousePoint.x, mousePoint.y);
+ DirectedEdge edge = mGraphModelManager.getModel().getEdge(mouseGPoint);
+ Vertex vertex = mGraphModelManager.getModel().getVertex(mouseGPoint);
+ GraphPoint vertexCentrePoint = null;
+ VertexAndDisp vertexAndDisp = null;
+ Selection selection = null;
+ DispForSelection dispForSelection = null;
+
+
+ // In order of priority:
+ // 1. Click on resize pad
+ // 2. Click on vertex
+ // 3. Click on edge
+ if(onResizePad(mouseGPoint))
+ {
+ processEvent(kPressOnResizePad, mousePoint);
+ }
+ else if(vertex != null)
+ {
+ if(mGraphModelManager.getModel().inSelection(vertex))
+ {
+ selection = mGraphModelManager.getModel().getSelection();
+ dispForSelection = new DispForSelection();
+ dispForSelection.mXDisp = mousePoint.x - selection.mTopLeftX;
+ dispForSelection.mYDisp = mousePoint.y - selection.mTopLeftY;
+
+ processEvent(kPressOnSelection, dispForSelection);
+ }
+ else
+ {
+ vertexCentrePoint = vertex.getCentrePoint();
+
+ vertexAndDisp = new VertexAndDisp();
+ vertexAndDisp.mVertex = vertex;
+ vertexAndDisp.mXDisp = mousePoint.x - vertexCentrePoint.x;
+ vertexAndDisp.mYDisp = mousePoint.y - vertexCentrePoint.y;
+
+ processEvent(kPressOnVertex, vertexAndDisp);
+ }
+ }
+ // vertex == null
+ else
+ {
+ if(edge == null)
+ {
+ processEvent(kPressOnNothing, mousePoint);
+ }
+ else
+ {
+ processEvent(kPressOnEdge, edge);
+ }
+ }
+ }
+
+
+ private boolean onResizePad(GraphPoint mouseGPoint)
+ {
+ Selection selection = mGraphModelManager.getModel().getSelection();
+ GraphPoint vertexCentre = null;
+ int bottomRightX = 0;
+ int bottomRightY = 0;
+
+
+ if(selection.mVertices == null) return false;
+
+ if(selection.mVertices.length == 1)
+ {
+ vertexCentre = selection.mVertices[0].getCentrePoint();
+ if (vertexCentre == null) return false;
+ bottomRightX = vertexCentre.x + selection.mVertices[0].getWidth()/2;
+ bottomRightY = vertexCentre.y + selection.mVertices[0].getHeight()/2;
+
+ return
+ (
+ (mouseGPoint.x > bottomRightX) &&
+ (mouseGPoint.x < bottomRightX + 10) &&
+ (mouseGPoint.y > bottomRightY) &&
+ (mouseGPoint.y < bottomRightY + 10)
+ );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+ private void mousePressedWithCTRL(Point mousePoint)
+ {
+ Vertex vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y));
+
+ if(vertex != null)
+ {
+ processEvent(kCTRLPressOnVertex, vertex);
+ }
+ }
+
+
+ @Override
+ public void mouseReleased(MouseEvent me)
+ {
+ processEvent(kRelease, null);
+ }
+
+
+ @Override
+ public void mouseMoved(MouseEvent me)
+ {
+ }
+
+
+ @Override
+ public void mouseDragged(MouseEvent e)
+ {
+ processEvent(kDrag, e.getPoint());
+ }
+
+
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if((e.getKeyCode() == KeyEvent.VK_A) && e.isControlDown())
+ {
+ processEvent(kCTRL_A, null);
+ }
+ }
+
+
+ @Override
+ public void keyReleased(KeyEvent e)
+ {
+ }
+
+
+ @Override
+ public void keyTyped(KeyEvent e)
+ {
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/StartVertexController.java b/src/main/java/com/c2kernel/gui/graph/controller/StartVertexController.java
new file mode 100644
index 0000000..e973132
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/StartVertexController.java
@@ -0,0 +1,79 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JButton;
+
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.Vertex;
+
+
+// The start vertex controller is responsible for selecting
+// the vertex at the start of the graph.
+//
+// The controller listens to:
+// * The graph model to determine if there is a single
+// vertex selected
+// * The start vertex button
+//
+// The controller modifies:
+// * The graph model to select the start vertex
+// * The start button to enable it only when there is a
+// single vertex selected
+public class StartVertexController implements Observer, ActionListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private JButton mStartButton = null;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ mGraphModelManager.addObserver(this);
+ }
+
+
+ public void setStartButton(JButton startButton)
+ {
+ mStartButton = startButton;
+ mStartButton.addActionListener(this);
+ }
+
+
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ SelectionChangedEvent event = null;
+ Vertex[] selectedVertices = null;
+
+ // If the selected vertex has changed
+ if(arg instanceof SelectionChangedEvent && mStartButton != null)
+ {
+ event = (SelectionChangedEvent)arg;
+ selectedVertices = event.mSelection.mVertices;
+
+ if(selectedVertices == null)
+ {
+ mStartButton.setEnabled(false);
+ }
+ else if (mGraphModelManager.isEditable())
+ {
+ mStartButton.setEnabled(selectedVertices.length == 1);
+ }
+ }
+ }
+
+
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ if(mGraphModelManager != null)
+ {
+ mGraphModelManager.getModel().setSelectedVertexToBeStart();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/controller/VertexConstructionController.java b/src/main/java/com/c2kernel/gui/graph/controller/VertexConstructionController.java
new file mode 100644
index 0000000..cd6d455
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/controller/VertexConstructionController.java
@@ -0,0 +1,47 @@
+package com.c2kernel.gui.graph.controller;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.gui.graph.view.EditorModeListener;
+import com.c2kernel.gui.graph.view.EditorToolBar;
+
+
+public class VertexConstructionController extends MouseAdapter implements EditorModeListener
+{
+ private GraphModelManager mGraphModelManager = null;
+ private EditorToolBar mEditorToolBar = null;
+ private boolean mCreatingVertices = false;
+
+
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+
+
+ public void setEditorToolBar(EditorToolBar editorToolBar)
+ {
+ mEditorToolBar = editorToolBar;
+ mEditorToolBar.addEditorModeListener(this);
+ }
+
+
+ @Override
+ public void editorModeChanged(String idOfNewMode)
+ {
+ mCreatingVertices = idOfNewMode.equals("Vertex");
+ }
+
+
+ @Override
+ public void mouseClicked(MouseEvent me)
+ {
+ if(mCreatingVertices && (mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable())
+ {
+ mGraphModelManager.getModel().createVertex(me.getPoint(), mEditorToolBar.getSelectedVertexType());
+ mEditorToolBar.enterSelectMode();
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/DefaultDirectedEdgeRenderer.java b/src/main/java/com/c2kernel/gui/graph/view/DefaultDirectedEdgeRenderer.java
new file mode 100644
index 0000000..e0d02c0
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/DefaultDirectedEdgeRenderer.java
@@ -0,0 +1,75 @@
+package com.c2kernel.gui.graph.view;
+
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+
+
+public class DefaultDirectedEdgeRenderer implements DirectedEdgeRenderer
+{
+ private GeneralPath mArrowTemplate = new GeneralPath();
+ private Paint mLinePaint = null;
+
+
+ public DefaultDirectedEdgeRenderer(Paint linePaint)
+ {
+ mLinePaint = linePaint;
+
+ mArrowTemplate.moveTo(-5, 5);
+ mArrowTemplate.lineTo( 0, 0);
+ mArrowTemplate.lineTo( 5, 5);
+ }
+
+
+ @Override
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge)
+ {
+ GraphPoint originPoint = directedEdge.getOriginPoint();
+ GraphPoint terminusPoint = directedEdge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+ AffineTransform transform = new AffineTransform();
+ Shape arrow = null;
+
+ g2d.setPaint(mLinePaint);
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x)/2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y)/2;
+
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y));
+
+ arrow = mArrowTemplate.createTransformedShape(transform);
+
+ g2d.draw(arrow);
+ }
+
+
+ private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY) {
+ double width = terminusX - originX;
+ double height = terminusY - originY;
+
+ if((width == 0) && (height > 0)) return Math.PI;
+
+ if((width == 0) && (height < 0)) return 0;
+
+ if((width > 0) && (height == 0)) return Math.PI/2.0;
+
+ if((width < 0) && (height == 0)) return -1.0 * Math.PI/2.0;
+
+ if((width > 0) && (height > 0)) return Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width));
+
+ if((width > 0) && (height < 0)) return Math.atan(Math.abs(width)/Math.abs(height));
+
+ if((width < 0) && (height < 0)) return -1.0 * Math.atan(Math.abs(width)/Math.abs(height));
+
+ if((width < 0) && (height > 0)) return -1.0 * (Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width)));
+
+ return 0.0;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/DefaultVertexRenderer.java b/src/main/java/com/c2kernel/gui/graph/view/DefaultVertexRenderer.java
new file mode 100644
index 0000000..c8804e2
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/DefaultVertexRenderer.java
@@ -0,0 +1,60 @@
+package com.c2kernel.gui.graph.view;
+
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Polygon;
+
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+
+
+public class DefaultVertexRenderer implements VertexRenderer
+{
+ private Paint mLinePaint = null;
+ private Paint mTextPaint = null;
+ private Paint mFillPaint = null;
+
+
+ public DefaultVertexRenderer(Paint linePaint, Paint textPaint, Paint fillPaint)
+ {
+ mLinePaint = linePaint;
+ mTextPaint = textPaint;
+ mFillPaint = fillPaint;
+ }
+
+
+ @Override
+ public void draw(Graphics2D g2d, Vertex vertex)
+ {
+ GraphPoint[] outlinePoints = vertex.getOutlinePoints();
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ Polygon outline = new Polygon();
+
+ String vertexName = vertex.getName();
+ FontMetrics metrics = g2d.getFontMetrics();
+ int textWidth = metrics.stringWidth(vertexName);
+ int textHeight = metrics.getHeight();
+ int textX = centrePoint.x - textWidth/2;
+ int textY = centrePoint.y + textHeight/3;
+
+ int i = 0;
+
+
+ // Construct a shape in the outline of the vertex
+ for(i=0; i<outlinePoints.length; i++)
+ {
+ outline.addPoint(outlinePoints[i].x, outlinePoints[i].y);
+ }
+
+ // Fill and then draw the outline
+ g2d.setPaint(mFillPaint);
+ g2d.fill(outline);
+ g2d.setPaint(mLinePaint);
+ g2d.draw(outline);
+
+ // Write the name of the vertex in the centre of the outline
+ g2d.setPaint(mTextPaint);
+ g2d.drawString(vertexName, textX, textY);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/DirectedEdgeRenderer.java b/src/main/java/com/c2kernel/gui/graph/view/DirectedEdgeRenderer.java
new file mode 100644
index 0000000..32d9d92
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/DirectedEdgeRenderer.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.graph.view;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.DirectedEdge;
+
+
+public interface DirectedEdgeRenderer
+{
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge);
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/EditorModeListener.java b/src/main/java/com/c2kernel/gui/graph/view/EditorModeListener.java
new file mode 100644
index 0000000..c23f37e
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/EditorModeListener.java
@@ -0,0 +1,8 @@
+package com.c2kernel.gui.graph.view;
+
+
+
+public interface EditorModeListener
+{
+ public void editorModeChanged(String idOfNewMode);
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/EditorPanel.java b/src/main/java/com/c2kernel/gui/graph/view/EditorPanel.java
new file mode 100644
index 0000000..1feb691
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/EditorPanel.java
@@ -0,0 +1,104 @@
+package com.c2kernel.gui.graph.view;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import com.c2kernel.graph.model.EdgeFactory;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.TypeNameAndConstructionInfo;
+import com.c2kernel.graph.model.VertexFactory;
+import com.c2kernel.graph.model.VertexOutlineCreator;
+import com.c2kernel.gui.graph.controller.AutoScrollController;
+import com.c2kernel.gui.graph.controller.EdgeConstructionController;
+import com.c2kernel.gui.graph.controller.MultiSelectionDragController;
+import com.c2kernel.gui.graph.controller.VertexConstructionController;
+public class EditorPanel extends JPanel
+{
+ // Graph Model
+ public final GraphModelManager mGraphModelManager = new GraphModelManager();
+ // Graph View
+ public GraphPanel mGraphPanel = null;
+ protected JScrollPane mGraphScrollPane = null;
+ // Graph Controllers
+ protected MultiSelectionDragController mMultiSelectionDragController = new MultiSelectionDragController();
+ protected VertexConstructionController mVertexConstructionController = new VertexConstructionController();
+ protected EdgeConstructionController mEdgeConstructionController = new EdgeConstructionController();
+ protected AutoScrollController mAutoScrollController = new AutoScrollController();
+ // Tool bar
+ protected EditorToolBar mEditorToolBar = null;
+ protected EditorPanel()
+ {
+ }
+ public EditorPanel(EdgeFactory eFactory, VertexFactory vFactory, VertexOutlineCreator vOutlineCreator, boolean edgeCreationMode, // True
+ // if
+ // edges
+ // can
+ // be
+ // created
+ JButton[] otherButtons, GraphPanel graphPanel)
+ {
+ // Create the graph panel and editor tool bar
+ setDoubleBuffered(true);
+ mGraphPanel = graphPanel;
+ mGraphPanel.setGraphModelManager(mGraphModelManager);
+ mGraphScrollPane = new JScrollPane(mGraphPanel);
+ mGraphModelManager.setExternalEdgeFactory(eFactory);
+ mGraphModelManager.setExternalVertexFactory(vFactory);
+ mGraphModelManager.setVertexOutlineCreator(vOutlineCreator);
+ mEditorToolBar = new EditorToolBar(edgeCreationMode, otherButtons, graphPanel);
+ mEditorToolBar.setGraphModelManager(mGraphModelManager);
+ mEditorToolBar.setGraphPanel(mGraphPanel);
+ createLayout();
+ // The graph panel observes the graph model
+ mGraphModelManager.addObserver(mGraphPanel);
+ // The multi selection drag controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mMultiSelectionDragController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mMultiSelectionDragController);
+ mGraphPanel.addMouseMotionListener(mMultiSelectionDragController);
+ mGraphPanel.addKeyListener(mMultiSelectionDragController);
+ mEditorToolBar.addEditorModeListener(mMultiSelectionDragController);
+ // The edge construction controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mEdgeConstructionController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mEdgeConstructionController);
+ mGraphPanel.addMouseMotionListener(mEdgeConstructionController);
+ mEdgeConstructionController.setEditorToolBar(mEditorToolBar);
+ // The vertex construction controller modifies the graph model
+ // and listens to the graph panel and editor tool bar
+ mVertexConstructionController.setGraphModelManager(mGraphModelManager);
+ mGraphPanel.addMouseListener(mVertexConstructionController);
+ mVertexConstructionController.setEditorToolBar(mEditorToolBar);
+ // The auto scroll controller listens to and modifies the
+ // graph panel
+ mAutoScrollController.setGraphPanel(mGraphPanel);
+ }
+
+ protected void createLayout()
+ {
+ setLayout(new BorderLayout());
+ add(mEditorToolBar, BorderLayout.NORTH);
+ mGraphPanel.setPreferredSize(new Dimension(mGraphModelManager.getModel().getWidth(), mGraphModelManager.getModel().getHeight()));
+ add(mGraphScrollPane, BorderLayout.CENTER);
+ }
+ public void enterSelectMode()
+ {
+ mEditorToolBar.enterSelectMode();
+ }
+ public void updateEdgeTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ mEditorToolBar.updateEdgeTypes(typeNameAndConstructionInfo);
+ }
+ public void updateVertexTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ mEditorToolBar.updateVertexTypes(typeNameAndConstructionInfo);
+ }
+ public void setEditable(boolean editable)
+ {
+ mGraphModelManager.setEditable(editable);
+ mEditorToolBar.setGraphEditable(editable);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/EditorToolBar.java b/src/main/java/com/c2kernel/gui/graph/view/EditorToolBar.java
new file mode 100644
index 0000000..deeaebb
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/EditorToolBar.java
@@ -0,0 +1,346 @@
+package com.c2kernel.gui.graph.view;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.util.Vector;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JToggleButton;
+
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.TypeNameAndConstructionInfo;
+import com.c2kernel.gui.graph.controller.DeletionController;
+import com.c2kernel.gui.graph.controller.StartVertexController;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+/**
+ * Tool bar with mode toggle buttons, start and delete buttons, and the possibility to add other arbitrary buttons at constructions time.
+ */
+public class EditorToolBar extends Box implements Printable
+{
+ protected boolean mEdgeCreationMode = false; // True if edges can be created
+ protected GraphPanel mGraphPanel = null;
+ // There is on mode button listener per mode button.
+ // When a mode button fires anaction performed event
+ // its corresponding listener notifies all of the
+ // editor mode listeners.
+ protected class ModeButtonListener implements ActionListener
+ {
+ protected String mModeId = null;
+ public ModeButtonListener(String modeId)
+ {
+ mModeId = modeId;
+ }
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ notifyListeners(mModeId);
+ }
+ }
+ // Vertex types and ids
+ protected JComboBox mVertexTypeBox = new JComboBox();
+ // Edge types and ids
+ protected JComboBox mEdgeTypeBox = new JComboBox();
+ // Mode buttons
+ protected ButtonGroup mModeButtonGroup = new ButtonGroup();
+ protected JToggleButton mVertexModeButton = new JToggleButton(Resource.findImage("graph/newvertex.png"));
+ protected JToggleButton mSelectModeButton = new JToggleButton(Resource.findImage("graph/selection.gif"));
+ protected JToggleButton mEdgeModeButton = new JToggleButton(Resource.findImage("graph/edge.png"));
+ // Normal buttons
+ protected JButton[] mOtherButtons = null;
+ protected JButton mStartButton = new JButton(Resource.findImage("graph/start.png"));
+ protected JButton mDeleteButton = new JButton(Resource.findImage("graph/delete.png"));
+ protected JButton mPrintButton = new JButton(Resource.findImage("graph/print.png"));
+ protected JButton mCopyButton = new JButton(Resource.findImage("graph/copy.png"));
+ // Controllers
+ protected StartVertexController mStartVertexController = new StartVertexController();
+ protected DeletionController mDeletionController = new DeletionController();
+ // Editor mode listeners
+ protected Vector<EditorModeListener> mListenerVector = new Vector<EditorModeListener>(10, 10);
+ public EditorToolBar(boolean edgeCreationMode, // True if edges can be created
+ JButton[] otherButtons, GraphPanel graphP)
+ {
+ super(BoxLayout.X_AXIS);
+ mGraphPanel = graphP;
+ mEdgeCreationMode = edgeCreationMode;
+ mOtherButtons = otherButtons;
+ prepareModeButtons();
+ mStartVertexController.setStartButton(mStartButton);
+ mDeletionController.setDeleteButton(mDeleteButton);
+ createLayout();
+ createListeners();
+ }
+ protected void prepareModeButtons()
+ {
+ // Set the tool tip texts
+ mVertexModeButton.setToolTipText(Language.translate("Create vertex"));
+ mSelectModeButton.setToolTipText(Language.translate("Multi-select and drag"));
+ mEdgeModeButton.setToolTipText(Language.translate("Create edge"));
+ mStartButton.setToolTipText(Language.translate("Select the start vertex of the graph"));
+ mDeleteButton.setToolTipText(Language.translate("Delete the selection"));
+ mPrintButton.setToolTipText(Language.translate("Print this graph"));
+ mPrintButton.setToolTipText(Language.translate("Copy an image of this graph to the clipboard"));
+ // Set the button margins to 0
+ mVertexModeButton.setMargin(new Insets(0, 0, 0, 0));
+ mSelectModeButton.setMargin(new Insets(0, 0, 0, 0));
+ mEdgeModeButton.setMargin(new Insets(0, 0, 0, 0));
+ // The initial mode is select mode
+ mSelectModeButton.setSelected(true);
+ // Add the mode buttons to the mode button group
+ mModeButtonGroup.add(mVertexModeButton);
+ mModeButtonGroup.add(mSelectModeButton);
+ mModeButtonGroup.add(mEdgeModeButton);
+ // Add the action listeners
+ mVertexModeButton.addActionListener(new ModeButtonListener("Vertex"));
+ mSelectModeButton.addActionListener(new ModeButtonListener("Select"));
+ mEdgeModeButton.addActionListener(new ModeButtonListener("Edge"));
+ }
+ public void enterSelectMode()
+ {
+ mSelectModeButton.setSelected(true);
+ notifyListeners("Select");
+ }
+ public void updateVertexTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ int i = 0;
+ mVertexTypeBox.removeAllItems();
+ for (i = 0; i < typeNameAndConstructionInfo.length; i++)
+ {
+ mVertexTypeBox.addItem(typeNameAndConstructionInfo[i]);
+ }
+ }
+ public void updateEdgeTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo)
+ {
+ int i = 0;
+ mEdgeTypeBox.removeAllItems();
+ for (i = 0; i < typeNameAndConstructionInfo.length; i++)
+ {
+ mEdgeTypeBox.addItem(typeNameAndConstructionInfo[i]);
+ }
+ }
+ public TypeNameAndConstructionInfo getSelectedVertexType()
+ {
+ return (TypeNameAndConstructionInfo) mVertexTypeBox.getSelectedItem();
+ }
+ public TypeNameAndConstructionInfo getSelectedEdgeType()
+ {
+ return (TypeNameAndConstructionInfo) mEdgeTypeBox.getSelectedItem();
+ }
+ protected void createLayout()
+ {
+ int i = 0;
+ add(mSelectModeButton);
+ add(mVertexModeButton);
+ add(mVertexTypeBox);
+ add(Box.createHorizontalStrut(10));
+ if (mEdgeCreationMode)
+ {
+ add(mEdgeModeButton);
+ add(mEdgeTypeBox);
+ }
+ add(Box.createGlue());
+ mPrintButton.setEnabled(true);
+ mPrintButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mPrintButton);
+ mCopyButton.setEnabled(true);
+ mCopyButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mCopyButton);
+ mStartButton.setEnabled(false);
+ mStartButton.setMargin(new Insets(0, 0, 0, 0));
+ mDeleteButton.setEnabled(false);
+ mDeleteButton.setMargin(new Insets(0, 0, 0, 0));
+ add(mDeleteButton);
+ add(Box.createRigidArea(new Dimension(20, 0)));
+ add(mStartButton);
+ if (mOtherButtons != null)
+ {
+ for (i = 0; i < mOtherButtons.length; i++)
+ {
+ mOtherButtons[i].setMargin(new Insets(0, 0, 0, 0));
+ add(mOtherButtons[i]);
+ }
+ }
+ }
+ protected void createListeners()
+ {
+ // The vertex mode button should be selected if the
+ // user select a vertex type from the vertex type box
+ mVertexTypeBox.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ mVertexModeButton.setSelected(true);
+ notifyListeners("Vertex");
+ }
+ });
+ // The edge mode button should be selected if the
+ // user select an edge type from the edge type box
+ mEdgeTypeBox.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ mEdgeModeButton.setSelected(true);
+ notifyListeners("Edge");
+ }
+ });
+ mPrintButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ PrinterJob _monJob = PrinterJob.getPrinterJob();
+ if (_monJob.printDialog())
+ _monJob.setPrintable(self());
+ try
+ {
+ _monJob.print();
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ });
+
+ try {
+ Class.forName("java.awt.datatransfer.DataFlavor").getDeclaredField("imageFlavor");
+ mCopyButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ try
+ {
+ Image i = createImage(mGraphPanel.getWidth(),mGraphPanel.getHeight());
+ Graphics g = i.getGraphics();
+ mGraphPanel.paintComponent(g);
+ ImageTransferable it = new ImageTransferable(i, mGraphPanel.getWidth(), mGraphPanel.getHeight());
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(it, it);
+ }
+ catch (Exception e)
+ {
+ Logger.error(e);
+ }
+ }
+ });
+ } catch (Exception ex) { //image clipboard transfer not supported
+ mCopyButton.setEnabled(false);
+ }
+ }
+
+ protected class ImageTransferable implements Transferable, ClipboardOwner {
+ Image image;
+ int width,height;
+ DataFlavor javaImg;
+ public ImageTransferable(Image image, int width, int height) {
+ this.image = image;
+ this.width = width;
+ this.height = height;
+ try {
+ javaImg = new DataFlavor("image/x-java-image; class=java.awt.Image", "AWT Image");
+ } catch (Exception ex){ }
+ }
+ @Override
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
+ if (!isDataFlavorSupported(flavor) || image == null) {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ return image;
+ }
+
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ boolean result = in(flavor, getTransferDataFlavors());
+ return result;
+ }
+
+ @Override
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] { javaImg };
+ }
+ protected boolean in(DataFlavor flavor, DataFlavor[] flavors) {
+ int f = 0;
+ while ((f < flavors.length) && !flavor.equals(flavors[f])) {
+ f++;
+ }
+ return f < flavors.length;
+ }
+ @Override
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ image = null;
+ }
+ }
+
+ protected void notifyListeners(String newModeId)
+ {
+ int i = 0;
+ EditorModeListener listener = null;
+ for (i = 0; i < mListenerVector.size(); i++)
+ {
+ listener = mListenerVector.elementAt(i);
+ listener.editorModeChanged(newModeId);
+ }
+ }
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mStartVertexController.setGraphModelManager(graphModelManager);
+ mDeletionController.setGraphModelManager(graphModelManager);
+ }
+ public void setGraphPanel(GraphPanel graphPanel)
+ {
+ graphPanel.addKeyListener(mDeletionController);
+ }
+ public void addEditorModeListener(EditorModeListener listener)
+ {
+ mListenerVector.add(listener);
+ }
+ public void removeEditorModeListener(EditorModeListener listener)
+ {
+ mListenerVector.remove(listener);
+ }
+ public void setGraphEditable(boolean editable)
+ {
+ mVertexModeButton.setEnabled(editable);
+ mEdgeModeButton.setEnabled(editable);
+ }
+ public EditorToolBar self()
+ {
+ return this;
+ }
+ @Override
+ public int print(Graphics g, PageFormat pf, int i) throws PrinterException
+ {
+ if (i >= 1)
+ {
+ return Printable.NO_SUCH_PAGE;
+ }
+ Graphics2D g2d = (Graphics2D) g;
+ double scalex = pf.getImageableWidth() / mGraphPanel.getWidth();
+ double scaley = pf.getImageableHeight() / mGraphPanel.getHeight();
+ double scale = Math.min(Math.min(scalex, scaley), 1);
+ g2d.translate(pf.getImageableX(), pf.getImageableY());
+ g2d.scale(scale, scale);
+ mGraphPanel.printComponent(g2d);
+ return Printable.PAGE_EXISTS;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/GraphPanel.java b/src/main/java/com/c2kernel/gui/graph/view/GraphPanel.java
new file mode 100644
index 0000000..fa7ed6f
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/GraphPanel.java
@@ -0,0 +1,272 @@
+package com.c2kernel.gui.graph.view;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JPanel;
+
+import com.c2kernel.graph.event.EntireModelChangedEvent;
+import com.c2kernel.graph.event.GraphModelResizedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.ElasticBand;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Selection;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.utils.Resource;
+public class GraphPanel extends JPanel implements Observer
+{
+ protected final Paint mSelectionPaint = Color.black;
+ protected final Paint mStartPaint = Color.green;
+ protected final Image mResizePadImg = Resource.findImage("graph/resizepad.gif").getImage();
+ protected final BasicStroke mDashed =
+ new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 5.0f }, 0.0f);
+ protected GraphModelManager mGraphModelManager = null;
+ protected VertexRenderer mVertexRenderer = null;
+ protected DirectedEdgeRenderer mDirectedEdgeRenderer = null;
+ public GraphPanel(DirectedEdgeRenderer eRenderer, VertexRenderer vRenderer)
+ {
+ mVertexRenderer = vRenderer;
+ mDirectedEdgeRenderer = eRenderer;
+ // Request the keyboard focus if the mouse
+ // is pressed on the graph panel
+ addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent me)
+ {
+ requestFocus();
+ }
+ });
+ }
+ public void setGraphModelManager(GraphModelManager graphModelManager)
+ {
+ mGraphModelManager = graphModelManager;
+ }
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ if (arg instanceof GraphModelResizedEvent || arg instanceof EntireModelChangedEvent)
+ {
+ setPreferredSize(new Dimension(mGraphModelManager.getModel().getWidth(), mGraphModelManager.getModel().getHeight()));
+ revalidate();
+ }
+ repaint();
+ }
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2d = (Graphics2D) g;
+ DirectedEdge[] edges = null;
+ Vertex[] vertices = null;
+ Vertex startVertex = null;
+ Selection selection = null;
+ ElasticBand elasticBand = null;
+ Vertex newEdgeOriginVertex = null;
+ GraphPoint newEdgeOriginPoint = null;
+ Point newEdgeEndPoint = null;
+ GraphPoint vertexCentre = null;
+ int i = 0;
+ super.paintComponent(g);
+ if (mGraphModelManager != null)
+ {
+ // Get the edges and vertices from the model
+ edges = mGraphModelManager.getModel().getEdges();
+ vertices = mGraphModelManager.getModel().getVertices();
+ //graphable = mGraphModelManager.getModel().
+ // Draw the edges
+ for (i = 0; i < edges.length; i++)
+ {
+ mDirectedEdgeRenderer.draw(g2d, edges[i]);
+ }
+ // Draw the vertices
+ for (i = 0; i < vertices.length; i++)
+ {
+ mVertexRenderer.draw(g2d, vertices[i]);
+ }
+ g2d.setPaint(mStartPaint);
+ // Highlight the start vertex if there is one
+ startVertex = mGraphModelManager.getModel().getStartVertex();
+ if (startVertex != null)
+ {
+ drawVertexHighlight(g2d, startVertex, 1);
+ }
+ // Get the present selection
+ selection = mGraphModelManager.getModel().getSelection();
+ g2d.setPaint(mSelectionPaint);
+ // Draw the outline of the selected
+ // vertices if there are any
+ if (selection.mVertices != null)
+ {
+ g2d.setStroke(mDashed);
+ for (i = 0; i < selection.mVertices.length; i++)
+ {
+ if (selection.mVertices[i] != mGraphModelManager.getModel().getContainingVertex())
+ drawVertexHighlight(g2d, selection.mVertices[i], 5);
+ }
+ // Draw the resize pads if there is one and only one vertex selected
+ if (selection.mVertices.length == 1 &&
+ selection.mVertices[0] != mGraphModelManager.getModel().getContainingVertex())
+ {
+ vertexCentre = selection.mVertices[0].getCentrePoint();
+ g2d.drawImage(
+ mResizePadImg,
+ vertexCentre.x + selection.mVertices[0].getWidth() / 2,
+ vertexCentre.y + selection.mVertices[0].getHeight() / 2,
+ this);
+ }
+ }
+ // Draw the outline of the selected
+ // edge if there is one
+ if (selection.mEdge != null)
+ {
+ drawEdgeHighlight(g2d, selection.mEdge);
+ }
+ // Get the elastic band
+ elasticBand = mGraphModelManager.getModel().getElasticBand();
+ // Draw the elastic band if there
+ // is one
+ if (elasticBand != null)
+ {
+ g2d.drawLine(
+ elasticBand.mFixedCorner.x,
+ elasticBand.mFixedCorner.y,
+ elasticBand.mMovingCorner.x,
+ elasticBand.mFixedCorner.y);
+ g2d.drawLine(
+ elasticBand.mMovingCorner.x,
+ elasticBand.mFixedCorner.y,
+ elasticBand.mMovingCorner.x,
+ elasticBand.mMovingCorner.y);
+ g2d.drawLine(
+ elasticBand.mMovingCorner.x,
+ elasticBand.mMovingCorner.y,
+ elasticBand.mFixedCorner.x,
+ elasticBand.mMovingCorner.y);
+ g2d.drawLine(
+ elasticBand.mFixedCorner.x,
+ elasticBand.mMovingCorner.y,
+ elasticBand.mFixedCorner.x,
+ elasticBand.mFixedCorner.y);
+ }
+ // Draw the new edge under construction if there is one
+ newEdgeEndPoint = mGraphModelManager.getModel().getNewEdgeEndPoint();
+ newEdgeOriginVertex = mGraphModelManager.getModel().getNewEdgeOriginVertex();
+ if ((newEdgeEndPoint != null) && (newEdgeOriginVertex != null))
+ {
+ newEdgeOriginPoint = newEdgeOriginVertex.getCentrePoint();
+ g2d.setPaint(Color.black);
+ g2d.drawLine(newEdgeOriginPoint.x, newEdgeOriginPoint.y, newEdgeEndPoint.x, newEdgeEndPoint.y);
+ }
+ }
+ }
+ // Draws the highlight of the specified vertex the specified dist from its outline
+ protected void drawVertexHighlight(Graphics2D g2d, Vertex vertex, int dist)
+ {
+ GraphPoint[] outlinePoints = vertex.getOutlinePoints();
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ int i = 0;
+ /*
+ * float dash1[] ={5.0f}; BasicStroke bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,10.0f, dash1,0.0f);
+ */
+ for (i = 0; i < outlinePoints.length - 1; i++)
+ {
+ drawShiftedLine(dist, g2d, centrePoint, outlinePoints[i].x, outlinePoints[i].y, outlinePoints[i + 1].x, outlinePoints[i + 1].y);
+ }
+ drawShiftedLine(
+ dist,
+ g2d,
+ centrePoint,
+ outlinePoints[outlinePoints.length - 1].x,
+ outlinePoints[outlinePoints.length - 1].y,
+ outlinePoints[0].x,
+ outlinePoints[0].y);
+ }
+ // Draws the specifed line the specified distance away from the specified centre point
+ private static void drawShiftedLine(int dist, Graphics2D g2d, GraphPoint centrePoint, int x1, int y1, int x2, int y2)
+ {
+ if (x1 > centrePoint.x)
+ x1 += dist;
+ if (x1 < centrePoint.x)
+ x1 -= dist;
+ if (y1 > centrePoint.y)
+ y1 += dist;
+ if (y1 < centrePoint.y)
+ y1 -= dist;
+ if (x2 > centrePoint.x)
+ x2 += dist;
+ if (x2 < centrePoint.x)
+ x2 -= dist;
+ if (y2 > centrePoint.y)
+ y2 += dist;
+ if (y2 < centrePoint.y)
+ y2 -= dist;
+ g2d.drawLine(x1, y1, x2, y2);
+ }
+ // Draws the highlight of the specified edge
+ protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge)
+ {
+ GraphPoint originPoint = edge.getOriginPoint();
+ GraphPoint terminusPoint = edge.getTerminusPoint();
+ int midX = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ int midY = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ int minX = midX - 10;
+ int minY = midY - 10;
+ int maxX = midX + 10;
+ int maxY = midY + 10;
+ g2d.drawLine(minX, minY, maxX, minY);
+ g2d.drawLine(maxX, minY, maxX, maxY);
+ g2d.drawLine(maxX, maxY, minX, maxY);
+ g2d.drawLine(minX, maxY, minX, minY);
+ }
+ @Override
+ public void printComponent(Graphics g)
+ {
+ super.paintComponent(g);
+ Graphics2D g2d = (Graphics2D) g;
+ DirectedEdge[] edges = null;
+ Vertex[] vertices = null;
+ Vertex startVertex = null;
+ int i = 0;
+ g.setColor(Color.white);
+ g2d.fillRect(0,0,getWidth(),getHeight());
+ if (mGraphModelManager != null)
+ {
+ // Get the edges and vertices from the model
+ edges = mGraphModelManager.getModel().getEdges();
+ vertices = mGraphModelManager.getModel().getVertices();
+ //graphable = mGraphModelManager.getModel().
+ // Draw the edges
+ for (i = 0; i < edges.length; i++)
+ {
+ mDirectedEdgeRenderer.draw(g2d, edges[i]);
+ }
+ // Draw the vertices
+ for (i = 0; i < vertices.length; i++)
+ {
+ mVertexRenderer.draw(g2d, vertices[i]);
+ }
+ g2d.setPaint(mStartPaint);
+ // Highlight the start vertex if there is one
+ startVertex = mGraphModelManager.getModel().getStartVertex();
+ if (startVertex != null)
+ {
+ drawVertexHighlight(g2d, startVertex, 1);
+ }
+ }
+ }
+
+ protected void superPaint(Graphics g)
+ {
+ super.paintComponent(g);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/PropertyTable.java b/src/main/java/com/c2kernel/gui/graph/view/PropertyTable.java
new file mode 100644
index 0000000..3776f86
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/PropertyTable.java
@@ -0,0 +1,40 @@
+package com.c2kernel.gui.graph.view;
+
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+
+
+public class PropertyTable extends JTable
+{
+ public PropertyTable(PropertyTableModel tableModel)
+ {
+ super(tableModel);
+ }
+
+
+ @Override
+ public TableCellRenderer getCellRenderer(int row, int column) {
+
+
+ return getDefaultRenderer(getCellClass(row, column));
+
+ }
+
+ @Override
+public TableCellEditor getCellEditor(int row, int column) {
+
+ return getDefaultEditor(getCellClass(row, column));
+
+ }
+
+ private Class<?> getCellClass(int row, int column) {
+ Class<?> cellClass = String.class;
+
+ try {
+ cellClass = dataModel.getValueAt(row, column).getClass();
+ } catch (NullPointerException ex) { }
+
+ return cellClass;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/PropertyTableModel.java b/src/main/java/com/c2kernel/gui/graph/view/PropertyTableModel.java
new file mode 100644
index 0000000..ce408e8
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/PropertyTableModel.java
@@ -0,0 +1,135 @@
+package com.c2kernel.gui.graph.view;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+
+import javax.swing.JOptionPane;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/08/02 07:50:10 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class PropertyTableModel extends AbstractTableModel {
+
+ private final String[] mColumnNames = { Language.translate("Name"), Language.translate("Value") };
+ HashMap<String, Object> sourceMap = new HashMap<String, Object>();
+ ArrayList<String> sortedNameList = new ArrayList<String>();
+ boolean isEditable = false;
+
+ public PropertyTableModel() {
+ super();
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return mColumnNames.length;
+ }
+ @Override
+ public String getColumnName(int col)
+ {
+ return mColumnNames[col];
+ }
+ @Override
+ public int getRowCount()
+ {
+ synchronized (sourceMap) {
+ return sourceMap.size();
+ }
+ }
+ @Override
+ public Object getValueAt(int rowIndex, int colIndex)
+ {
+ synchronized (sourceMap) {
+ String rowName = sortedNameList.get(rowIndex);
+ if (colIndex == 0)
+ return rowName;
+ else
+ return sourceMap.get(rowName);
+ }
+ }
+
+ @Override
+ public void setValueAt(Object value, int rowIndex, int colIndex)
+ {
+ synchronized (sourceMap) {
+ if (colIndex == 0) return;
+ String rowName = sortedNameList.get(rowIndex);
+ Class<? extends Object> oldElement = sourceMap.get(rowName).getClass();
+ if (oldElement == Double.class && value.getClass() == String.class)
+ try {
+ value = Double.valueOf((String)value);
+ } catch (Exception ex) { }
+ if (value.getClass() != oldElement)
+ JOptionPane.showMessageDialog(null, "This property should contain a "+oldElement.getName()+" not a "+value.getClass().getName(), "Incorrect datatype", JOptionPane.ERROR_MESSAGE);
+ else {
+ sourceMap.put(rowName, value);
+ fireTableCellUpdated(rowIndex, colIndex);
+ }
+ }
+ }
+
+ public void setMap(HashMap<String, Object> props) {
+ synchronized (sourceMap) {
+ sourceMap = props;
+ sortedNameList = new ArrayList<String>(props.size());
+ for (String string : props.keySet())
+ sortedNameList.add(string);
+
+ Collections.sort(sortedNameList, new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return (o1.compareToIgnoreCase(o2));
+ }
+ });
+ }
+ fireTableChanged(new TableModelEvent(this));
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int col)
+ {
+ return col==1 && isEditable;
+ }
+
+ /**
+ * @return Returns the isEditable.
+ */
+ public boolean isEditable() {
+ return isEditable;
+ }
+ /**
+ * @param isEditable The isEditable to set.
+ */
+ public void setEditable(boolean isEditable) {
+ this.isEditable = isEditable;
+ }
+
+ /**
+ * @param text
+ * @param object
+ */
+ public void addProperty(String text, Object object) {
+ sourceMap.put(text,object);
+ setMap(sourceMap);
+ }
+
+ /**
+ * @param object
+ */
+ public void delProperty(Object propName) {
+ sourceMap.remove(propName);
+ setMap(sourceMap);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/SelectedVertexPanel.java b/src/main/java/com/c2kernel/gui/graph/view/SelectedVertexPanel.java
new file mode 100644
index 0000000..282ce09
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/SelectedVertexPanel.java
@@ -0,0 +1,27 @@
+package com.c2kernel.gui.graph.view;
+
+import javax.swing.JPanel;
+
+import com.c2kernel.graph.model.Vertex;
+
+/**************************************************************************
+ *
+ * $Revision: 1.1 $
+ * $Date: 2005/05/12 10:12:52 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+
+public abstract class SelectedVertexPanel extends JPanel {
+
+ public SelectedVertexPanel() {
+ super();
+ }
+
+ public abstract void select(Vertex vert);
+
+ public abstract void clear();
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/VertexPropertyPanel.java b/src/main/java/com/c2kernel/gui/graph/view/VertexPropertyPanel.java
new file mode 100644
index 0000000..c4b6303
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/VertexPropertyPanel.java
@@ -0,0 +1,259 @@
+package com.c2kernel.gui.graph.view;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+
+import com.c2kernel.graph.event.EntireModelChangedEvent;
+import com.c2kernel.graph.event.SelectionChangedEvent;
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphModelManager;
+import com.c2kernel.graph.model.GraphableEdge;
+import com.c2kernel.graph.model.GraphableVertex;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.tabs.EntityTabPane;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/09/09 12:19:28 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class VertexPropertyPanel extends JPanel implements Observer, TableModelListener, ActionListener {
+
+ private final PropertyTableModel mPropertyModel;
+ private final PropertyTable mPropertyTable;
+ private GraphModelManager mGraphModelManager;
+ private boolean isEditable = false;
+ GridBagLayout gridbag = new GridBagLayout();
+ protected JLabel selObjName;
+ protected JLabel selObjClass;
+ JButton addPropButton;
+ JButton delPropButton;
+ Box newPropBox;
+ private JTextField newPropName;
+ private JComboBox newPropType;
+ String[] typeOptions = { "String", "Boolean", "Integer", "Float" };
+ String[] typeInitVal = { "", "false", "0", "0.0"};
+ SelectedVertexPanel mSelPanel;
+
+ public VertexPropertyPanel() {
+ super();
+ setLayout(gridbag);
+ mPropertyModel = new PropertyTableModel();
+ mPropertyModel.addTableModelListener(this);
+ mPropertyTable = new PropertyTable(mPropertyModel);
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void update(Observable o, Object arg) {
+ Vertex[] selectedVertices = null;
+ DirectedEdge selectedEdge = null;
+ // If the selection has changed
+ if (arg instanceof SelectionChangedEvent)
+ {
+ SelectionChangedEvent event = (SelectionChangedEvent) arg;
+ selectedVertices = event.mSelection.mVertices;
+ if (selectedVertices != null)
+ {
+ if (selectedVertices.length == 1)
+ {
+ setVertex(selectedVertices[0]);
+ return;
+ }
+ }
+ selectedEdge = event.mSelection.mEdge;
+ if (selectedEdge != null)
+ {
+ setEdge(selectedEdge);
+ return;
+ }
+ }
+ if (arg instanceof SelectionChangedEvent || arg instanceof EntireModelChangedEvent){
+ clear();
+ }
+ }
+
+
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ if (mGraphModelManager!=null)
+ mGraphModelManager.forceNotify();
+
+ }
+
+ public void setVertex(Vertex vert) {
+ if (vert.getName().equals("domain"))
+ selObjName.setText("Domain Workflow");
+ else
+ selObjName.setText(vert.getName());
+ String className = vert.getClass().getName();
+ selObjClass.setText(className.substring(className.lastIndexOf('.')+1));
+ if (mSelPanel != null) mSelPanel.select(vert);
+ if (vert instanceof GraphableVertex) {
+ mPropertyModel.setMap(((GraphableVertex)vert).getProperties());
+ addPropButton.setEnabled(isEditable);
+ delPropButton.setEnabled(isEditable);
+ }
+ }
+
+ public void setEdge(DirectedEdge edge) {
+ selObjName.setText(edge.getName());
+ String className = edge.getClass().getName();
+ selObjClass.setText(className.substring(className.lastIndexOf('.')+1));
+ if (edge instanceof GraphableEdge) {
+ mPropertyModel.setMap(((GraphableEdge)edge).getProperties());
+ addPropButton.setEnabled(isEditable);
+ delPropButton.setEnabled(isEditable);
+ }
+ if (mSelPanel != null) mSelPanel.clear();
+ }
+
+ public void clear() {
+ selObjName.setText("");
+ selObjClass.setText("Nothing Selected");
+ mPropertyModel.setMap(new HashMap<String, Object>());
+ if (mSelPanel != null) mSelPanel.clear();
+ addPropButton.setEnabled(false);
+ delPropButton.setEnabled(false);
+ }
+
+ /**
+ * @param isEditable The isEditable to set.
+ */
+ public void setEditable(boolean editable) {
+ mPropertyModel.setEditable(editable);
+ isEditable = editable;
+ newPropBox.setVisible(editable);
+ }
+
+ public void setGraphModelManager(GraphModelManager manager) {
+ mGraphModelManager = manager;
+ manager.addObserver(this);
+ }
+
+ public void createLayout(SelectedVertexPanel selPanel)
+ {
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 1;
+ c.weighty = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.ipadx = 5;
+ c.ipady = 5;
+
+ selObjName = new JLabel();
+ selObjName.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(selObjName, c);
+ add(selObjName);
+
+ c.gridy++;
+ selObjClass = new JLabel();
+ gridbag.setConstraints(selObjClass, c);
+ add(selObjClass);
+
+ c.gridy++;
+ JLabel title = new JLabel("Properties");
+ title.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(title, c);
+ add(title);
+
+ c.gridy++;
+ c.fill = GridBagConstraints.BOTH;
+ c.weighty = 2;
+ JScrollPane scroll = new JScrollPane(mPropertyTable);
+ gridbag.setConstraints(scroll, c);
+ add(scroll);
+
+ newPropBox = Box.createHorizontalBox();
+ newPropBox.add(new JLabel(Language.translate("New :")));
+ newPropBox.add(Box.createHorizontalGlue());
+ newPropName = new JTextField(15);
+ newPropBox.add(newPropName);
+ newPropType = new JComboBox(typeOptions);
+ newPropBox.add(newPropType);
+ newPropBox.add(Box.createHorizontalStrut(1));
+ addPropButton = new JButton("Add");
+ addPropButton.setMargin(new Insets(0, 0, 0, 0));
+ delPropButton = new JButton("Del");
+ delPropButton.setMargin(new Insets(0, 0, 0, 0));
+ addPropButton.addActionListener(this);
+ delPropButton.addActionListener(this);
+ newPropBox.add(addPropButton);
+ newPropBox.add(delPropButton);
+
+ c.gridy++;
+ c.weighty=0;
+ c.fill= GridBagConstraints.HORIZONTAL;
+ gridbag.setConstraints(newPropBox, c);
+ add(newPropBox);
+
+ if (selPanel != null) {
+ c.gridy++;
+ mSelPanel = selPanel;
+ gridbag.setConstraints(mSelPanel, c);
+ add(mSelPanel);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == addPropButton) {
+ if (newPropName.getText().length() < 1) {
+ JOptionPane.showMessageDialog(this, "Enter a name for the new property", "Cannot add property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (mPropertyModel.sourceMap.containsKey(newPropName.getText())) {
+ JOptionPane.showMessageDialog(this, "Property '"+newPropName.getText()+"' already exists.", "Cannot add property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (mPropertyTable.getCellEditor() != null)
+ mPropertyTable.getCellEditor().stopCellEditing();
+
+ try {
+ Class<?> newPropClass = Class.forName("java.lang."+typeOptions[newPropType.getSelectedIndex()]);
+ Class<?>[] params = {String.class};
+ Constructor<?> init = newPropClass.getConstructor(params);
+ Object[] initParams = { typeInitVal[newPropType.getSelectedIndex()] };
+ mPropertyModel.addProperty(newPropName.getText(), init.newInstance(initParams));
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+ else if (e.getSource() == delPropButton) {
+ int selrow = mPropertyTable.getSelectedRow();
+ if (selrow == -1) {
+ JOptionPane.showMessageDialog(this, "Select a property to remove", "Cannot delete property", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ mPropertyModel.delProperty(mPropertyModel.sortedNameList.get(selrow));
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/graph/view/VertexRenderer.java b/src/main/java/com/c2kernel/gui/graph/view/VertexRenderer.java
new file mode 100644
index 0000000..9757b0f
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/graph/view/VertexRenderer.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.graph.view;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.Vertex;
+
+
+public interface VertexRenderer
+{
+ public void draw(Graphics2D g2d, Vertex vertex);
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/ActivitySlotDefRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/ActivitySlotDefRenderer.java
new file mode 100644
index 0000000..56cb44d
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/ActivitySlotDefRenderer.java
@@ -0,0 +1,71 @@
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.ActivitySlotDef;
+import com.c2kernel.utils.Language;
+
+public class ActivitySlotDefRenderer implements VertexRenderer
+{
+ private Paint mInactivePaint = new Color(255, 255, 255);
+ private Paint mErrorPaint = new Color( 255, 50, 0 );
+ private Paint mCompositePaint= new Color(200, 200, 255);
+ private Paint mTextPaint = Color.black;
+
+
+ @Override
+ public void draw( Graphics2D g2d, Vertex vertex)
+ {
+ ActivitySlotDef activitySlotDef = ( ActivitySlotDef )vertex;
+ boolean hasError = activitySlotDef.verify();
+ boolean isComposite = false;
+ isComposite = activitySlotDef.getIsComposite();
+ GraphPoint centrePoint = activitySlotDef.getCentrePoint();
+ int vertexHeight = activitySlotDef.getHeight();
+ int vertexWidth = activitySlotDef.getWidth();
+
+ String[] linesOfText = new String[2+(hasError?0:1)];
+ FontMetrics metrics = g2d.getFontMetrics();
+ int lineWidth = 0;
+ int lineHeight = metrics.getHeight();
+ int linesHeight = lineHeight * linesOfText.length;
+ int linesStartY = centrePoint.y - linesHeight / 2 + lineHeight * 2 / 3;
+ int x = 0;
+ int y = 0;
+ int i = 0;
+
+ linesOfText[0]="("+activitySlotDef.getActivityDef()+")";
+ linesOfText[1]=(String)activitySlotDef.getProperties().get("Name");
+
+ if (!hasError)linesOfText[2]=Language.translate(activitySlotDef.getErrors());
+
+ g2d.setPaint( !hasError ? mErrorPaint : isComposite ? mCompositePaint : mInactivePaint );
+ g2d.fill3DRect
+ (
+ centrePoint.x - vertexWidth / 2,
+ centrePoint.y - vertexHeight / 2,
+ vertexWidth,
+ vertexHeight,
+ true
+ );
+
+ g2d.setPaint( mTextPaint );
+
+ // Draw the lines of text
+ for ( i = 0; i < linesOfText.length; i++ )
+ {
+ if (linesOfText[i] == null) linesOfText[i] = "";
+ lineWidth = metrics.stringWidth( linesOfText[ i ] );
+ x = centrePoint.x - lineWidth / 2;
+ y = linesStartY + i * lineHeight;
+ g2d.drawString( linesOfText[ i ], x, y );
+ }
+ }
+}
+
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/CompActDefOutcomeHandler.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/CompActDefOutcomeHandler.java
new file mode 100644
index 0000000..16a03a4
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/CompActDefOutcomeHandler.java
@@ -0,0 +1,232 @@
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+
+import com.c2kernel.graph.layout.DefaultGraphLayoutGenerator;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.graph.view.EditorPanel;
+import com.c2kernel.gui.graph.view.VertexPropertyPanel;
+import com.c2kernel.gui.lifecycle.instance.FindActDefPanel;
+import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException;
+import com.c2kernel.gui.tabs.outcome.InvalidSchemaException;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException;
+import com.c2kernel.lifecycle.CompositeActivityDef;
+import com.c2kernel.lifecycle.gui.model.WfEdgeDefFactory;
+import com.c2kernel.lifecycle.gui.model.WfVertexDefFactory;
+import com.c2kernel.lifecycle.gui.model.WfVertexDefOutlineCreator;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.CastorXMLUtility;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+/**************************************************************************
+ *
+ * $Revision: 1.14 $
+ * $Date: 2005/09/07 13:46:31 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class CompActDefOutcomeHandler
+ extends JPanel
+ implements OutcomeHandler {
+
+ protected JButton mLoadButton = new JButton(Resource.findImage("graph/load.png"));
+ protected JButton mLayoutButton = new JButton(Resource.findImage("graph/autolayout.png"));
+ protected JButton[] mOtherToolBarButtons = { mLayoutButton, mLoadButton };
+
+ protected CompositeActivityDef mCompActDef = null;
+ protected WfEdgeDefFactory mWfEdgeDefFactory = new WfEdgeDefFactory();
+ protected WfVertexDefFactory mWfVertexDefFactory = new WfVertexDefFactory();
+
+ protected EditorPanel mEditorPanel;
+ protected VertexPropertyPanel mPropertyPanel;
+ protected JSplitPane mSplitPane;
+ boolean unsaved;
+
+ public CompActDefOutcomeHandler() {
+ super();
+ mPropertyPanel = loadPropertyPanel();
+ mPropertyPanel.createLayout(new FindActDefPanel());
+ mEditorPanel =
+ new EditorPanel(
+ mWfEdgeDefFactory,
+ mWfVertexDefFactory,
+ new WfVertexDefOutlineCreator(),
+ true,
+ mOtherToolBarButtons,
+ new WfDefGraphPanel(new WfDirectedEdgeDefRenderer(),
+ new WfVertexDefRenderer()));
+ }
+
+ protected void createLayout()
+ {
+ mLoadButton.setToolTipText("Load from local disc");
+ mLayoutButton.setToolTipText("Auto-Layout");
+
+ // Add the editor pane
+ GridBagLayout gridbag = new GridBagLayout();
+ setLayout(gridbag);
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.fill = GridBagConstraints.BOTH;
+ c.weighty = 2.0;
+ c.weightx = 2.0;
+ mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mEditorPanel, mPropertyPanel);
+ mSplitPane.setDividerSize(5);
+ gridbag.setConstraints(mSplitPane, c);
+ add(mSplitPane);
+ }
+
+ protected void createListeners()
+ {
+ mLoadButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ File selectedFile = null;
+
+ int returnValue = MainFrame.xmlChooser.showOpenDialog(null);
+
+ switch (returnValue)
+ {
+ case JFileChooser.APPROVE_OPTION :
+ selectedFile = MainFrame.xmlChooser.getSelectedFile();
+ try {
+ String newWf = FileStringUtility.file2String(selectedFile);
+ setOutcome(newWf);
+ setUpGraphEditor();
+ } catch (Exception e) {
+ Logger.exceptionDialog(e);
+ }
+ case JFileChooser.CANCEL_OPTION :
+ case JFileChooser.ERROR_OPTION :
+
+ default :
+ }
+ }
+ });
+
+ mLayoutButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ DefaultGraphLayoutGenerator.layoutGraph(mEditorPanel.mGraphModelManager.getModel());
+ }
+ });
+ }
+
+ public void setUpGraphEditor() {
+ mEditorPanel.mGraphModelManager.setModel(mCompActDef.getChildrenGraphModel());
+ // Give the editor panel the edge and vertex types
+ mEditorPanel.updateVertexTypes(mCompActDef.getVertexTypeNameAndConstructionInfo());
+ mEditorPanel.updateEdgeTypes(mCompActDef.getEdgeTypeNameAndConstructionInfo());
+ mEditorPanel.enterSelectMode();
+ mWfVertexDefFactory.setCreationContext(mCompActDef);
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void setOutcome(String outcome) throws InvalidOutcomeException {
+ try {
+ CompositeActivityDef newAct = (CompositeActivityDef)CastorXMLUtility.unmarshall(outcome);
+ if (mCompActDef != null)
+ newAct.setName(mCompActDef.getName());
+ mCompActDef = newAct;
+ } catch (Exception ex) {
+ Logger.error(ex);
+ throw new InvalidOutcomeException(ex.getMessage());
+ }
+ }
+ /**
+ *
+ */
+ @Override
+ public void setDescription(String description)
+ throws InvalidSchemaException {
+ // ignore - always the same
+ }
+ /**
+ *
+ */
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ mLayoutButton.setEnabled(!readOnly);
+ mLoadButton.setEnabled(!readOnly);
+ mEditorPanel.setEditable(!readOnly);
+ mPropertyPanel.setEditable(!readOnly);
+ }
+ /**
+ *
+ */
+ @Override
+ public JPanel getPanel() throws OutcomeNotInitialisedException {
+ return this;
+ }
+ /**
+ *
+ */
+ @Override
+ public String getOutcome() throws OutcomeException {
+ try {
+ return CastorXMLUtility.marshall(mCompActDef);
+ } catch (Exception ex) {
+ throw new OutcomeException(ex.getMessage());
+ }
+ }
+ /**
+ *
+ */
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Composite Act Def Viewer");
+ createLayout();
+ createListeners();
+ mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager);
+ setUpGraphEditor();
+ }
+
+ public VertexPropertyPanel loadPropertyPanel()
+ {
+ String wfPanelClass = Gateway.getProperty("WfPropertyPanel");
+ if (wfPanelClass != null) {
+ try {
+ Class<?> panelClass = Class.forName(wfPanelClass);
+ return (VertexPropertyPanel)panelClass.newInstance();
+ } catch (Exception ex) {
+ Logger.error("Could not load wf props panel:"+wfPanelClass);
+ Logger.error(ex);
+ }
+ }
+ return new VertexPropertyPanel();
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return unsaved;
+ }
+
+ @Override
+ public void saved() {
+ unsaved = false;
+ }
+
+ @Override
+ public void export(File targetFile) throws Exception {
+ ElemActDefOutcomeHandler.exportAct(targetFile.getParentFile(), mCompActDef);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/ElemActDefOutcomeHandler.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/ElemActDefOutcomeHandler.java
new file mode 100644
index 0000000..f6e4e9b
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/ElemActDefOutcomeHandler.java
@@ -0,0 +1,161 @@
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.io.File;
+
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import com.c2kernel.graph.model.GraphableVertex;
+import com.c2kernel.gui.graph.view.VertexPropertyPanel;
+import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException;
+import com.c2kernel.gui.tabs.outcome.InvalidSchemaException;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException;
+import com.c2kernel.lifecycle.ActivityDef;
+import com.c2kernel.lifecycle.ActivitySlotDef;
+import com.c2kernel.lifecycle.CompositeActivityDef;
+import com.c2kernel.utils.CastorXMLUtility;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.LocalObjectLoader;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.5 $
+ * $Date: 2005/10/05 07:39:37 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class ElemActDefOutcomeHandler extends VertexPropertyPanel implements OutcomeHandler {
+
+ ActivityDef act;
+ boolean unsaved;
+ public ElemActDefOutcomeHandler() {
+ super();
+ createLayout(null);
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void setOutcome(String outcome) throws InvalidOutcomeException {
+ try {
+ act = (ActivityDef)CastorXMLUtility.unmarshall(outcome);
+ setVertex(act);
+ } catch (Exception ex) {
+ Logger.error(ex);
+ throw new InvalidOutcomeException();
+ }
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void setDescription(String description)
+ throws InvalidSchemaException {
+ // ignore
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ setEditable(!readOnly);
+
+ }
+
+ /**
+ *
+ */
+ @Override
+ public JPanel getPanel() throws OutcomeNotInitialisedException {
+ return this;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public String getOutcome() throws OutcomeException {
+ try {
+ return CastorXMLUtility.marshall(act);
+ } catch (Exception ex) {
+ Logger.error(ex);
+ throw new OutcomeException();
+ }
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void run() {
+ validate();
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return unsaved;
+ }
+
+ @Override
+ public void saved() {
+ unsaved = false;
+ }
+
+ @Override
+ public void export(File targetFile) throws Exception {
+ exportAct(targetFile.getParentFile(), act);
+ }
+
+ public static void exportAct(File dir, ActivityDef actDef) throws Exception {
+ FileStringUtility.string2File(new File(dir, actDef.getActName()+".xml"), CastorXMLUtility.marshall(actDef));
+ // Export associated schema
+ exportSchema((String)actDef.getProperties().get("SchemaType"), (String)actDef.getProperties().get("SchemaVersion"), dir);
+ // Export associated script
+ exportScript((String)actDef.getProperties().get("ScriptName"), (String)actDef.getProperties().get("ScriptVersion"), dir);
+
+ //Export child act if composite
+ if (actDef instanceof CompositeActivityDef) {
+ CompositeActivityDef compActDef = (CompositeActivityDef)actDef;
+ for (int i=0; i<compActDef.getChildren().length; i++) {
+ GraphableVertex vert = compActDef.getChildren()[i];
+ exportScript((String)vert.getProperties().get("ScriptName"), (String)vert.getProperties().get("ScriptVersion"), dir);
+ exportScript((String)vert.getProperties().get("RoutingScriptName"), (String)vert.getProperties().get("RoutingScriptVersion"), dir);
+ }
+ GraphableVertex[] childDefs = compActDef.getLayoutableChildren();
+ for (GraphableVertex childDef : childDefs) {
+ if (childDef instanceof ActivitySlotDef)
+ exportAct(dir, ((ActivitySlotDef)childDef).getTheActivityDef());
+ }
+ }
+ }
+
+ public static void exportScript(String name, String version, File dir) {
+ if (name == null || name.length()==0) return;
+ try {
+ FileStringUtility.string2File(new File(dir, name+"_"+version+".xml"),
+ LocalObjectLoader.getScript(name, version));
+ } catch (Exception ex) {
+ Logger.error(ex);
+ JOptionPane.showMessageDialog(null, "Could not export script "+name+"_"+version, "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ public static void exportSchema(String name, String version, File dir) {
+ if (name == null || name.length()==0) return;
+ try {
+ FileStringUtility.string2File(new File(dir, name+"_"+version+".xsd"),
+ LocalObjectLoader.getSchema(name, Integer.parseInt(version)).schema);
+ } catch (Exception ex) {
+ Logger.error(ex);
+ JOptionPane.showMessageDialog(null, "Could not export schema "+name+"_"+version, "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/SplitJoinDefRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/SplitJoinDefRenderer.java
new file mode 100644
index 0000000..f756696
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/SplitJoinDefRenderer.java
@@ -0,0 +1,138 @@
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.AndSplitDef;
+import com.c2kernel.lifecycle.JoinDef;
+import com.c2kernel.lifecycle.LoopDef;
+import com.c2kernel.lifecycle.OrSplitDef;
+import com.c2kernel.lifecycle.WfVertexDef;
+import com.c2kernel.lifecycle.XOrSplitDef;
+import com.c2kernel.utils.Language;
+
+
+public class SplitJoinDefRenderer implements VertexRenderer
+{
+ private Paint mTextPaint = Color.black;
+ private Paint mBoxPaint = new Color( 204, 204, 204 );
+ private Paint mErrorPaint = new Color( 255, 50, 0 );
+ private boolean mTextOffsetsNotInitialised = true;
+ private int mTextYOffset = 0;
+ private String mAndText = "And";
+ private int mAndTextXOffset = 0;
+ private String mOrText = "Or";
+ private int mOrTextXOffset = 0;
+ private String mXOrText = "XOr";
+ private int mXOrTextXOffset = 0;
+ private String mJoinText = "Join";
+ private int mJoinTextXOffset = 0;
+ private String mLoopText = "Loop";
+ private int mLoopTextXOffset = 0;
+ private String mRouteText = "";
+ private int mRouteTextXOffset = 0;
+ private String mXXXText = "XXX";
+ private int mXXXTextXOffset = 0;
+
+ @Override
+ public void draw( Graphics2D g2d, Vertex vertex)
+ {
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ String text = null;
+ int textXOffset = 0;
+ int vertexHeight = vertex.getHeight();
+ int vertexWidth = vertex.getWidth();
+ boolean hasError = !((WfVertexDef)vertex).verify();
+
+
+ if ( mTextOffsetsNotInitialised )
+ {
+ initialiseTextOffsets( g2d );
+ mTextOffsetsNotInitialised = false;
+ }
+ if ( vertex instanceof LoopDef )
+ {
+ text = Language.translate(mLoopText);
+ textXOffset = mLoopTextXOffset;
+ }
+ else if ( vertex instanceof XOrSplitDef )
+ {
+ text = Language.translate(mXOrText);
+ textXOffset = mXOrTextXOffset;
+ }
+ else if ( vertex instanceof OrSplitDef )
+ {
+ text = Language.translate(mOrText);
+ textXOffset = mOrTextXOffset;
+ }
+ else if ( vertex instanceof AndSplitDef )
+ {
+ text = Language.translate(mAndText);
+ textXOffset = mAndTextXOffset;
+ }
+ else if ( vertex instanceof JoinDef)
+ {
+ String type= (String)((JoinDef)vertex).getProperties().get("Type");
+ if (type!=null && type.equals("Route"))
+ {
+ text = mRouteText;
+ textXOffset = mRouteTextXOffset;
+ }
+ else
+ {
+ text = Language.translate(mJoinText);
+ textXOffset = mJoinTextXOffset;
+ }
+ }
+ else
+ {
+ text = mXXXText;
+ textXOffset = mXXXTextXOffset;
+ }
+
+
+ g2d.setPaint( hasError ? mErrorPaint : mBoxPaint );
+ g2d.fillRect
+ (
+ centrePoint.x - vertexWidth / 2,
+ centrePoint.y - vertexHeight / 2,
+ vertexWidth,
+ vertexHeight
+ );
+ g2d.setPaint( mTextPaint );
+ g2d.drawRect
+ (
+ centrePoint.x - vertexWidth / 2,
+ centrePoint.y - vertexHeight / 2,
+ vertexWidth,
+ vertexHeight
+ );
+ g2d.drawString( text, centrePoint.x - textXOffset, centrePoint.y + mTextYOffset );
+ if (hasError) {
+ g2d.setPaint( mErrorPaint );
+ String errors = Language.translate(((WfVertexDef)vertex).getErrors());
+ int errorWidth = g2d.getFontMetrics().stringWidth( errors );
+ g2d.drawString( errors, centrePoint.x - ( errorWidth / 2), centrePoint.y + vertexHeight );
+ }
+ }
+
+ private void initialiseTextOffsets( Graphics2D g2d )
+ {
+ FontMetrics metrics = g2d.getFontMetrics();
+
+
+ mTextYOffset = metrics.getHeight() / 3;
+ mAndTextXOffset = metrics.stringWidth( Language.translate(mAndText) ) / 2;
+ mOrTextXOffset = metrics.stringWidth( Language.translate(mOrText) ) / 2;
+ mXOrTextXOffset = metrics.stringWidth( Language.translate(mXOrText) ) / 2;
+ mJoinTextXOffset = metrics.stringWidth( Language.translate(mJoinText) ) / 2;
+ mLoopTextXOffset = metrics.stringWidth( Language.translate(mJoinText) ) / 2;
+ mRouteTextXOffset = metrics.stringWidth( Language.translate(mRouteText) ) / 2;
+ }
+}
+
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDefGraphPanel.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDefGraphPanel.java
new file mode 100644
index 0000000..7177a4d
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDefGraphPanel.java
@@ -0,0 +1,59 @@
+/*Created on 21 nov. 2003 */
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.gui.graph.view.DirectedEdgeRenderer;
+import com.c2kernel.gui.graph.view.GraphPanel;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.NextDef;
+
+/** @author XSeb74*/
+public class WfDefGraphPanel extends GraphPanel
+{
+ public WfDefGraphPanel(DirectedEdgeRenderer d,VertexRenderer v)
+ {
+ super(d,v);
+ }
+ // Draws the highlight of the specified edge
+ @Override
+ protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge)
+ {
+ GraphPoint originPoint = edge.getOriginPoint();
+ GraphPoint terminusPoint = edge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+
+ if ("Straight".equals(((NextDef)edge).getProperties().get("Type")) || ((NextDef)edge).getProperties().get("Type") == null)
+ {
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ }
+ else if (("Broken +".equals(((NextDef)edge).getProperties().get("Type"))))
+ {
+ midPoint.x = (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = (originPoint.y + terminusPoint.y) / 2;
+ }
+ else if (("Broken -".equals(((NextDef)edge).getProperties().get("Type"))))
+ {
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y;
+ }
+ else if (("Broken |".equals(((NextDef)edge).getProperties().get("Type"))))
+ {
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y;
+ }
+ int minX = midPoint.x - 10;
+ int minY = midPoint.y - 10;
+ int maxX = midPoint.x + 10;
+ int maxY = midPoint.y + 10;
+ g2d.drawLine(minX, minY, maxX, minY);
+ g2d.drawLine(maxX, minY, maxX, maxY);
+ g2d.drawLine(maxX, maxY, minX, maxY);
+ g2d.drawLine(minX, maxY, minX, minY);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDirectedEdgeDefRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDirectedEdgeDefRenderer.java
new file mode 100644
index 0000000..695934b
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfDirectedEdgeDefRenderer.java
@@ -0,0 +1,134 @@
+package com.c2kernel.gui.lifecycle.desc;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.gui.graph.view.DirectedEdgeRenderer;
+import com.c2kernel.lifecycle.NextDef;
+public class WfDirectedEdgeDefRenderer implements DirectedEdgeRenderer
+{
+ private GeneralPath mArrowTemplate = new GeneralPath();
+ public WfDirectedEdgeDefRenderer()
+ {
+ mArrowTemplate.moveTo(-5, 5);
+ mArrowTemplate.lineTo(0, 0);
+ mArrowTemplate.lineTo(5, 5);
+ }
+ @Override
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge)
+ {
+ GraphPoint originPoint = directedEdge.getOriginPoint();
+ GraphPoint terminusPoint = directedEdge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+ AffineTransform transform = new AffineTransform();
+ Shape arrow = null;
+ NextDef nextDef = (NextDef) directedEdge;
+ boolean hasError = !nextDef.verify();
+ String text = (String) nextDef.getProperties().get("Alias");
+ g2d.setPaint(hasError ? Color.red : Color.black);
+ if (("Broken +".equals(nextDef.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, (originPoint.y + terminusPoint.y) / 2);
+ g2d.drawLine(originPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, (originPoint.y + terminusPoint.y) / 2);
+ g2d.drawLine(terminusPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, terminusPoint.y);
+ midPoint.x = (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = (originPoint.y + terminusPoint.y) / 2;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(
+ calcArrowAngle(
+ originPoint.x,
+ originPoint.x - terminusPoint.x > -5
+ && originPoint.x - terminusPoint.x < 5 ? originPoint.y : (originPoint.y + terminusPoint.y) / 2,
+ terminusPoint.x,
+ originPoint.x - terminusPoint.x > -5
+ && originPoint.x - terminusPoint.x < 5 ? terminusPoint.y : (originPoint.y + terminusPoint.y) / 2));
+ }
+ else if (("Broken -".equals(nextDef.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, originPoint.y);
+ g2d.drawLine(terminusPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y;
+ transform.translate(midPoint.x, midPoint.y);
+ transform
+ .rotate(
+ calcArrowAngle(
+ arrowOnY ? terminusPoint.x : originPoint.x,
+ arrowOnY ? originPoint.y : originPoint.y,
+ arrowOnY ? terminusPoint.x : terminusPoint.x,
+ arrowOnY ? terminusPoint.y : originPoint.y));
+ }
+ else if (("Broken |".equals(nextDef.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, terminusPoint.y);
+ g2d.drawLine(originPoint.x, terminusPoint.y, terminusPoint.x, terminusPoint.y);
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y;
+ transform.translate(midPoint.x, midPoint.y);
+ transform
+ .rotate(
+ calcArrowAngle(
+ arrowOnY ? terminusPoint.x : originPoint.x,
+ arrowOnY ? originPoint.y : originPoint.y,
+ arrowOnY ? terminusPoint.x : terminusPoint.x,
+ arrowOnY ? terminusPoint.y : originPoint.y));
+ }
+ else
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y));
+ }
+
+ arrow = mArrowTemplate.createTransformedShape(transform);
+ g2d.draw(arrow);
+ if (text != null)
+ g2d.drawString(text, midPoint.x + 10, midPoint.y);
+ }
+ private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY)
+ {
+ double width = terminusX - originX;
+ double height = terminusY - originY;
+ if ((width == 0) && (height > 0))
+ {
+ return Math.PI;
+ }
+ if ((width == 0) && (height < 0))
+ {
+ return 0;
+ }
+ if ((width > 0) && (height == 0))
+ {
+ return Math.PI / 2.0;
+ }
+ if ((width < 0) && (height == 0))
+ {
+ return -1.0 * Math.PI / 2.0;
+ }
+ if ((width > 0) && (height > 0))
+ {
+ return Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width));
+ }
+ if ((width > 0) && (height < 0))
+ {
+ return Math.atan(Math.abs(width) / Math.abs(height));
+ }
+ if ((width < 0) && (height < 0))
+ {
+ return -1.0 * Math.atan(Math.abs(width) / Math.abs(height));
+ }
+ if ((width < 0) && (height > 0))
+ {
+ return -1.0 * (Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width)));
+ }
+ return 0.0;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/desc/WfVertexDefRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfVertexDefRenderer.java
new file mode 100644
index 0000000..6ba6c49
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/desc/WfVertexDefRenderer.java
@@ -0,0 +1,30 @@
+package com.c2kernel.gui.lifecycle.desc;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.ActivitySlotDef;
+import com.c2kernel.lifecycle.AndSplitDef;
+import com.c2kernel.lifecycle.JoinDef;
+
+public class WfVertexDefRenderer implements VertexRenderer
+{
+ protected ActivitySlotDefRenderer mActivitySlotDefRenderer = new ActivitySlotDefRenderer();
+ protected SplitJoinDefRenderer mSplitJoinDefRenderer = new SplitJoinDefRenderer();
+
+
+ @Override
+ public void draw( Graphics2D g2d, Vertex vertex)
+ {
+ if ( vertex instanceof ActivitySlotDef )
+ {
+ mActivitySlotDefRenderer.draw( g2d, vertex);
+ }
+ else if ( ( vertex instanceof AndSplitDef ) || ( vertex instanceof JoinDef ) )
+ {
+ mSplitJoinDefRenderer.draw( g2d, vertex);
+ }
+ }
+}
+
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/ActivityRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/ActivityRenderer.java
new file mode 100644
index 0000000..4d7da95
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/ActivityRenderer.java
@@ -0,0 +1,117 @@
+package com.c2kernel.gui.lifecycle.instance;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Polygon;
+
+import com.c2kernel.common.GTimeStamp;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.instance.Activity;
+import com.c2kernel.lifecycle.instance.stateMachine.States;
+import com.c2kernel.utils.DateUtility;
+import com.c2kernel.utils.Language;
+public class ActivityRenderer implements VertexRenderer
+{
+ private Paint mActivePaint = new Color(100, 255, 100);
+ private Paint mActiveCompPaint = new Color(100, 255, 255);
+ private Paint mInactivePaint = new Color(255, 255, 255);
+ private Paint mInactiveCompPaint = new Color(200, 200, 255);
+ private Paint mErrorPaint = new Color(255, 50, 0);
+ private Paint mTextPaint = Color.black;
+ @Override
+ public void draw(Graphics2D g2d, Vertex vertex)
+ {
+ Activity activity = (Activity) vertex;
+ boolean active = activity.getActive();
+ boolean hasError = !activity.verify();
+ boolean isComposite = activity.getIsComposite();
+ GraphPoint centrePoint = activity.getCentrePoint();
+ //String description = activity.getDescription();
+ String[] linesOfText = new String[3];
+ linesOfText[0] = "(" + activity.getType() + ")";
+ linesOfText[1] = activity.getName();
+ if (hasError)
+ linesOfText[2] = Language.translate(activity.getErrors());
+ else
+ {
+ int cs = activity.getCurrentState();
+ if (cs == States.WAITING && activity.getActive())
+ linesOfText[2] =
+ Language.translate(States.getStateName(cs))
+ + (((Boolean) activity.getProperties().get("Show time")).booleanValue()
+ ? " " + getWaitTime(activity.getActiveDate())
+ : "");
+ else if (cs == States.STARTED)
+ linesOfText[2] =
+ Language.translate(States.getStateName(cs))
+ + (((Boolean) activity.getProperties().get("Show time")).booleanValue()
+ ? " " + getWaitTime(activity.getStartDate())
+ : "");
+ else
+ linesOfText[2] = Language.translate(States.getStateName(cs));
+ }
+
+ FontMetrics metrics = g2d.getFontMetrics();
+ int lineWidth = 0;
+ int lineHeight = metrics.getHeight();
+ int linesHeight = lineHeight * linesOfText.length;
+ int linesStartY = centrePoint.y - linesHeight / 2 + lineHeight * 2 / 3;
+ int x = 0;
+ int y = 0;
+ int i = 0;
+ GraphPoint[] outline = vertex.getOutlinePoints();
+ Paint actColour;
+ if (hasError)
+ actColour = mErrorPaint;
+ else if (active)
+ if (isComposite)
+ actColour = mActiveCompPaint;
+ else
+ actColour = mActivePaint;
+ else if (isComposite)
+ actColour = mInactiveCompPaint;
+ else
+ actColour = mInactivePaint;
+ g2d.setPaint(actColour);
+ //g2d.fill3DRect( centrePoint.x - mSize.width / 2, centrePoint.y - mSize.height / 2, mSize.width, mSize.height, true );
+ g2d.fill(graphPointsToPolygon(outline));
+ g2d.setPaint(mTextPaint);
+ for (i = 0; i < linesOfText.length; i++)
+ {
+ lineWidth = metrics.stringWidth(linesOfText[i]);
+ x = centrePoint.x - lineWidth / 2;
+ y = linesStartY + i * lineHeight;
+ g2d.drawString(linesOfText[i], x, y);
+ }
+ }
+ private static Polygon graphPointsToPolygon(GraphPoint[] points)
+ {
+ Polygon polygon = new Polygon();
+ int i = 0;
+ for (i = 0; i < points.length; i++)
+ {
+ polygon.addPoint(points[i].x, points[i].y);
+ }
+ return polygon;
+ }
+ private static String getWaitTime(GTimeStamp date)
+ {
+ GTimeStamp now = new GTimeStamp();
+ DateUtility.setToNow(now);
+ long diff = DateUtility.diff(now, date);
+ long secondes = diff % 60;
+ long minutes = (diff / 60) % 60;
+ long hours = (diff / 3600) % 24;
+ long days = (diff / 3600 / 24);
+ if (days > 0)
+ return days + " " + Language.translate("d") + " " + hours + " " + Language.translate("h");
+ if (hours > 0)
+ return hours + " " + Language.translate("h") + " " + minutes + " " + Language.translate("min");
+ if (minutes > 0)
+ return minutes + " " + Language.translate("min");
+ return secondes + " " + Language.translate("sec");
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/FindActDefPanel.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/FindActDefPanel.java
new file mode 100644
index 0000000..04ab560
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/FindActDefPanel.java
@@ -0,0 +1,72 @@
+package com.c2kernel.gui.lifecycle.instance;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.graph.view.SelectedVertexPanel;
+import com.c2kernel.lifecycle.ActivitySlotDef;
+import com.c2kernel.lookup.DomainPath;
+
+/**************************************************************************
+ *
+ * $Revision: 1.3 $
+ * $Date: 2005/12/01 14:23:15 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class FindActDefPanel extends SelectedVertexPanel {
+
+ JButton findButton;
+ ActivitySlotDef currentAct;
+
+ public FindActDefPanel() {
+ super();
+ findButton = new JButton("Open Definition");
+ findButton.setEnabled(false);
+ add(findButton);
+ findButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ try {
+ DomainPath actPath = (DomainPath)new DomainPath("/desc/ActivityDesc/").find(currentAct.getActivityDef());
+ MainFrame.treeBrowser.push(actPath);
+ } catch (ObjectNotFoundException e1) { }
+ }
+ });
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void select(Vertex vert) {
+ if (vert instanceof ActivitySlotDef) {
+ findButton.setEnabled(true);
+ currentAct = (ActivitySlotDef)vert;
+ }
+ else
+ clear();
+
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void clear() {
+ findButton.setEnabled(false);
+ currentAct = null;
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/SplitJoinRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/SplitJoinRenderer.java
new file mode 100644
index 0000000..3152772
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/SplitJoinRenderer.java
@@ -0,0 +1,142 @@
+package com.c2kernel.gui.lifecycle.instance;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.instance.AndSplit;
+import com.c2kernel.lifecycle.instance.Join;
+import com.c2kernel.lifecycle.instance.Loop;
+import com.c2kernel.lifecycle.instance.OrSplit;
+import com.c2kernel.lifecycle.instance.WfVertex;
+import com.c2kernel.lifecycle.instance.XOrSplit;
+import com.c2kernel.utils.Language;
+
+public class SplitJoinRenderer implements VertexRenderer
+{
+ private Paint mTextPaint = Color.black;
+ private Paint mBoxPaint = new Color( 204, 204, 204 );
+ private Paint mErrorPaint = new Color( 255, 0, 0 );
+ private boolean mTextOffsetsNotInitialised = true;
+ private int mTextYOffset = 0;
+ private String mAndText = "And";
+ private int mAndTextXOffset = 0;
+ private String mOrText = "Or";
+ private int mOrTextXOffset = 0;
+ private String mLoopText = "Loop";
+ private int mLoopTextXOffset = 0;
+ private String mXOrText = "XOr";
+ private int mXOrTextXOffset = 0;
+ private String mJoinText = "Join";
+ private int mJoinTextXOffset = 0;
+ private String mRouteText = "";
+ private int mRouteTextXOffset = 0;
+ private String mXXXText = "XXX";
+ private int mXXXTextXOffset = 0;
+
+
+ @Override
+ public void draw( Graphics2D g2d, Vertex vertex)
+ {
+ GraphPoint centrePoint = vertex.getCentrePoint();
+ String text = null;
+ int textXOffset = 0;
+ int vertexHeight = vertex.getHeight();
+ int vertexWidth = vertex.getWidth();
+
+
+ if ( mTextOffsetsNotInitialised )
+ {
+ initialiseTextOffsets( g2d );
+ mTextOffsetsNotInitialised = false;
+ }
+ if ( vertex instanceof AndSplit )
+ {
+ text = Language.translate(mAndText);
+ textXOffset = mAndTextXOffset;
+ }
+ else if ( vertex instanceof OrSplit )
+ {
+ text = Language.translate(mOrText);
+ textXOffset = mOrTextXOffset;
+ }
+ else if ( vertex instanceof Loop )
+ {
+ text = Language.translate(mLoopText);
+ textXOffset = mLoopTextXOffset;
+ }
+ else if ( vertex instanceof XOrSplit )
+ {
+ text = Language.translate(mXOrText);
+ textXOffset = mXOrTextXOffset;
+ }
+ else if ( vertex instanceof Join )
+ {
+ text = Language.translate(mJoinText);
+ textXOffset = mJoinTextXOffset;
+ }
+ else if ( vertex instanceof Join)
+ {
+ String type= (String)((Join)vertex).getProperties().get("Type");
+ if (type!=null && type.equals("Route"))
+ {
+ text = mRouteText;
+ textXOffset = mRouteTextXOffset;
+ }
+ else
+ {
+ text = Language.translate(mJoinText);
+ textXOffset = mJoinTextXOffset;
+ }
+ }
+ else
+ {
+ text = mXXXText;
+ textXOffset = mXXXTextXOffset;
+ }
+
+ boolean hasErrors = ((WfVertex)vertex).verify();
+ g2d.setPaint( hasErrors ? mBoxPaint : mErrorPaint );
+ g2d.fillRect
+ (
+ centrePoint.x - vertexWidth / 2,
+ centrePoint.y - vertexHeight / 2,
+ vertexWidth,
+ vertexHeight
+ );
+ g2d.setPaint( mTextPaint );
+ g2d.drawRect
+ (
+ centrePoint.x - vertexWidth / 2,
+ centrePoint.y - vertexHeight / 2,
+ vertexWidth,
+ vertexHeight
+ );
+ g2d.drawString( text, centrePoint.x - textXOffset, centrePoint.y + mTextYOffset );
+
+ if (!hasErrors) {
+ g2d.setPaint( mErrorPaint );
+ String errors = Language.translate(((WfVertex)vertex).getErrors());
+ int errorWidth = g2d.getFontMetrics().stringWidth( errors );
+ g2d.drawString( errors, centrePoint.x - ( errorWidth / 2), centrePoint.y + vertexHeight );
+ }
+ }
+
+ private void initialiseTextOffsets( Graphics2D g2d )
+ {
+ FontMetrics metrics = g2d.getFontMetrics();
+
+
+ mTextYOffset = metrics.getHeight() / 3;
+ mAndTextXOffset = metrics.stringWidth( Language.translate(mAndText) ) / 2;
+ mOrTextXOffset = metrics.stringWidth( Language.translate(mOrText) ) / 2;
+ mXOrTextXOffset = metrics.stringWidth( Language.translate(mXOrText) ) / 2;
+ mJoinTextXOffset = metrics.stringWidth( Language.translate(mJoinText) ) / 2;
+ mLoopTextXOffset = metrics.stringWidth( Language.translate(mLoopText) ) / 2;
+ }
+}
+
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/TransitionPanel.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/TransitionPanel.java
new file mode 100644
index 0000000..1314f2f
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/TransitionPanel.java
@@ -0,0 +1,187 @@
+package com.c2kernel.gui.lifecycle.instance;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.graph.view.SelectedVertexPanel;
+import com.c2kernel.gui.tabs.EntityTabPane;
+import com.c2kernel.gui.tabs.execution.Executor;
+import com.c2kernel.lifecycle.instance.Activity;
+import com.c2kernel.lifecycle.instance.stateMachine.StateMachine;
+import com.c2kernel.lifecycle.instance.stateMachine.States;
+import com.c2kernel.lifecycle.instance.stateMachine.Transitions;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.8 $
+ * $Date: 2005/09/07 13:46:31 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class TransitionPanel extends SelectedVertexPanel implements ActionListener {
+ protected Activity mCurrentAct;
+ protected GridBagLayout gridbag;
+ protected GridBagConstraints c;
+ protected Box transBox;
+ protected JComboBox executors;
+ protected JComboBox states = new JComboBox(States.states);
+ protected JCheckBox active = new JCheckBox();
+ protected JLabel status = new JLabel();
+ protected ItemProxy mItem;
+
+ public TransitionPanel() {
+ super();
+ gridbag = new GridBagLayout();
+ setLayout(gridbag);
+ c = new GridBagConstraints();
+ c.gridx=0; c.gridy=0;
+ c.weightx=1; c.weighty=0;
+ c.fill=GridBagConstraints.HORIZONTAL;
+
+ JLabel title = new JLabel("Available Transitions");
+ title.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(title, c);
+ add(title);
+
+ c.gridy++;
+ gridbag.setConstraints(status, c);
+ add(status);
+ c.gridy++;
+
+ transBox = Box.createHorizontalBox();
+ gridbag.setConstraints(transBox, c);
+ add(transBox);
+
+ c.weightx=0; c.gridx++;
+ executors = MainFrame.getExecutionPlugins();
+ if (executors.getItemCount() > 1) {
+ gridbag.setConstraints(executors, c);
+ add(executors);
+ }
+
+
+
+ if (MainFrame.isAdmin) {
+ c.gridx=0; c.gridy++;
+ title = new JLabel("State Hacking");
+ title.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(title, c);
+ add(title);
+ Box hackBox = Box.createHorizontalBox();
+ hackBox.add(states);
+ hackBox.add(Box.createHorizontalGlue());
+ hackBox.add(new JLabel("Active:"));
+ hackBox.add(active);
+ c.gridy++;
+ gridbag.setConstraints(hackBox, c);
+ add(hackBox);
+ states.addActionListener(this);
+ active.addActionListener(this);
+ }
+
+ clear();
+
+ }
+ /**
+ *
+ */
+ @Override
+ public void select(Vertex vert) {
+ clear();
+ if (!(vert instanceof Activity)) return;
+ mCurrentAct = (Activity)vert;
+ states.setSelectedIndex(mCurrentAct.getCurrentState());
+ states.setEnabled(true);
+ active.setSelected(mCurrentAct.active);
+ active.setEnabled(true);
+ Logger.msg("Retrieving possible transitions for activity "+mCurrentAct.getName());
+ int[] transitions = mCurrentAct.getMachine().possibleTransition();
+ if (transitions.length == 0) {
+ status.setText("None");
+ return;
+ }
+ for (int i = 0; i < transitions.length; i++) {
+ String trans= Transitions.getTransitionName(transitions[i]);
+ if (!(transitions[i]==Transitions.DONE) && !(transitions[i]==Transitions.COMPLETE)) {
+ String buttonLabel = trans.substring(0,1).toUpperCase()+trans.substring(1);
+ JButton thisTrans = new JButton(buttonLabel);
+ thisTrans.setActionCommand("Trans:"+String.valueOf(transitions[i]));
+ thisTrans.addActionListener(this);
+ transBox.add(thisTrans);
+ transBox.add(Box.createHorizontalGlue());
+ }
+ status.setText(transitions.length+" transitions possible.");
+ }
+ revalidate();
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == active && mCurrentAct != null) {
+ mCurrentAct.active = active.isSelected();
+ return;
+ }
+ if (e.getSource() == states && mCurrentAct != null) {
+ mCurrentAct.getMachine().state = states.getSelectedIndex();
+ return;
+ }
+ if (!e.getActionCommand().startsWith("Trans:")) return;
+ int transition = Integer.parseInt(e.getActionCommand().substring(6));
+ Logger.msg("Requesting transition "+transition);
+ Job thisJob = new Job(mItem.getSystemKey(),
+ mCurrentAct.getPath(),
+ transition,
+ new StateMachine(mCurrentAct).simulate(transition),
+ mCurrentAct.getCurrentState(),
+ mCurrentAct.getName(),
+ mCurrentAct.getProperties(),
+ mCurrentAct.getType(),
+ MainFrame.userAgent.getName());
+ try {
+ Executor selectedExecutor = (Executor)executors.getSelectedItem();
+ selectedExecutor.execute(thisJob, status);
+ } catch (Exception ex) {
+ String className = ex.getClass().getName();
+ className = className.substring(className.lastIndexOf('.')+1);
+ Logger.error(ex);
+ JOptionPane.showMessageDialog(null, ex.getMessage(), className, JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+
+ @Override
+ public void clear() {
+ mCurrentAct = null;
+ transBox.removeAll();
+ status.setText("No activity selected");
+ states.setSelectedIndex(0);
+ states.setEnabled(false);
+ active.setSelected(false);
+ active.setEnabled(false);
+ revalidate();
+ }
+
+
+ /**
+ * @param item The mItem to set.
+ */
+ public void setItem(ItemProxy item) {
+ mItem = item;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/WfDirectedEdgeRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfDirectedEdgeRenderer.java
new file mode 100644
index 0000000..484b2fc
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfDirectedEdgeRenderer.java
@@ -0,0 +1,130 @@
+package com.c2kernel.gui.lifecycle.instance;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.gui.graph.view.DirectedEdgeRenderer;
+import com.c2kernel.lifecycle.instance.Next;
+public class WfDirectedEdgeRenderer implements DirectedEdgeRenderer
+{
+ private GeneralPath mArrowTemplate = new GeneralPath();
+ public WfDirectedEdgeRenderer()
+ {
+ mArrowTemplate.moveTo(-5, 5);
+ mArrowTemplate.lineTo(0, 0);
+ mArrowTemplate.lineTo(5, 5);
+ }
+ @Override
+ public void draw(Graphics2D g2d, DirectedEdge directedEdge)
+ {
+ GraphPoint originPoint = directedEdge.getOriginPoint();
+ GraphPoint terminusPoint = directedEdge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+ AffineTransform transform = new AffineTransform();
+ Shape arrow = null;
+ Next next = (Next) directedEdge;
+ String text = (String) next.getProperties().get("Alias");
+ g2d.setPaint(Color.black);
+ if (("Broken +".equals(next.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, (originPoint.y + terminusPoint.y) / 2);
+ g2d.drawLine(originPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, (originPoint.y + terminusPoint.y) / 2);
+ g2d.drawLine(terminusPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, terminusPoint.y);
+ midPoint.x = (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = (originPoint.y + terminusPoint.y) / 2;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(
+ calcArrowAngle(
+ originPoint.x,
+ originPoint.x - terminusPoint.x > -5
+ && originPoint.x - terminusPoint.x < 5 ? originPoint.y : (originPoint.y + terminusPoint.y) / 2,
+ terminusPoint.x,
+ originPoint.x - terminusPoint.x > -5
+ && originPoint.x - terminusPoint.x < 5 ? terminusPoint.y : (originPoint.y + terminusPoint.y) / 2));
+ }
+ else if (("Broken -".equals(next.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, originPoint.y);
+ g2d.drawLine(terminusPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(
+ calcArrowAngle(
+ arrowOnY ? terminusPoint.x : originPoint.x,
+ arrowOnY ? originPoint.y : originPoint.y,
+ arrowOnY ? terminusPoint.x : terminusPoint.x,
+ arrowOnY ? terminusPoint.y : originPoint.y));
+ }
+ else if (("Broken |".equals(next.getProperties().get("Type"))))
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, terminusPoint.y);
+ g2d.drawLine(originPoint.x, terminusPoint.y, terminusPoint.x, terminusPoint.y);
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(
+ calcArrowAngle(
+ arrowOnY ? terminusPoint.x : originPoint.x,
+ arrowOnY ? originPoint.y : originPoint.y,
+ arrowOnY ? terminusPoint.x : terminusPoint.x,
+ arrowOnY ? terminusPoint.y : originPoint.y));
+ }
+ else
+ {
+ g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y);
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ transform.translate(midPoint.x, midPoint.y);
+ transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y));
+ }
+ arrow = mArrowTemplate.createTransformedShape(transform);
+ g2d.draw(arrow);
+ if (text != null)
+ g2d.drawString(text, midPoint.x + 10, midPoint.y);
+ }
+ private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY)
+ {
+ double width = terminusX - originX;
+ double height = terminusY - originY;
+ if ((width == 0) && (height > 0))
+ {
+ return Math.PI;
+ }
+ if ((width == 0) && (height < 0))
+ {
+ return 0;
+ }
+ if ((width > 0) && (height == 0))
+ {
+ return Math.PI / 2.0;
+ }
+ if ((width < 0) && (height == 0))
+ {
+ return -1.0 * Math.PI / 2.0;
+ }
+ if ((width > 0) && (height > 0))
+ {
+ return Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width));
+ }
+ if ((width > 0) && (height < 0))
+ {
+ return Math.atan(Math.abs(width) / Math.abs(height));
+ }
+ if ((width < 0) && (height < 0))
+ {
+ return -1.0 * Math.atan(Math.abs(width) / Math.abs(height));
+ }
+ if ((width < 0) && (height > 0))
+ {
+ return -1.0 * (Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width)));
+ }
+ return 0.0;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/WfGraphPanel.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfGraphPanel.java
new file mode 100644
index 0000000..91257cb
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfGraphPanel.java
@@ -0,0 +1,59 @@
+/*Created on 21 nov. 2003 */
+package com.c2kernel.gui.lifecycle.instance;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.DirectedEdge;
+import com.c2kernel.graph.model.GraphPoint;
+import com.c2kernel.gui.graph.view.DirectedEdgeRenderer;
+import com.c2kernel.gui.graph.view.GraphPanel;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.instance.Next;
+
+/** @author XSeb74*/
+public class WfGraphPanel extends GraphPanel
+{
+ public WfGraphPanel(DirectedEdgeRenderer d,VertexRenderer v)
+ {
+ super(d,v);
+ }
+ // Draws the highlight of the specified edge
+ @Override
+ protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge)
+ {
+ GraphPoint originPoint = edge.getOriginPoint();
+ GraphPoint terminusPoint = edge.getTerminusPoint();
+ GraphPoint midPoint = new GraphPoint();
+
+ if ("Straight".equals(((Next)edge).getProperties().get("Type")) || ((Next)edge).getProperties().get("Type") == null)
+ {
+ midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2;
+ midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2;
+ }
+ else if (("Broken +".equals(((Next)edge).getProperties().get("Type"))))
+ {
+ midPoint.x = (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = (originPoint.y + terminusPoint.y) / 2;
+ }
+ else if (("Broken -".equals(((Next)edge).getProperties().get("Type"))))
+ {
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y;
+ }
+ else if (("Broken |".equals(((Next)edge).getProperties().get("Type"))))
+ {
+ boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60);
+ midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2;
+ midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y;
+ }
+ int minX = midPoint.x - 10;
+ int minY = midPoint.y - 10;
+ int maxX = midPoint.x + 10;
+ int maxY = midPoint.y + 10;
+ g2d.drawLine(minX, minY, maxX, minY);
+ g2d.drawLine(maxX, minY, maxX, maxY);
+ g2d.drawLine(maxX, maxY, minX, maxY);
+ g2d.drawLine(minX, maxY, minX, minY);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/lifecycle/instance/WfVertexRenderer.java b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfVertexRenderer.java
new file mode 100644
index 0000000..07a4e29
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/lifecycle/instance/WfVertexRenderer.java
@@ -0,0 +1,23 @@
+package com.c2kernel.gui.lifecycle.instance;
+
+import java.awt.Graphics2D;
+
+import com.c2kernel.graph.model.Vertex;
+import com.c2kernel.gui.graph.view.VertexRenderer;
+import com.c2kernel.lifecycle.instance.Activity;
+import com.c2kernel.lifecycle.instance.Join;
+import com.c2kernel.lifecycle.instance.Split;
+
+public class WfVertexRenderer implements VertexRenderer
+{
+ protected ActivityRenderer mActivityRenderer = new ActivityRenderer();
+ protected SplitJoinRenderer mSplitJoinRenderer = new SplitJoinRenderer();
+
+ @Override
+ public void draw( Graphics2D g2d, Vertex vertex)
+ {
+ if ( vertex instanceof Activity ) { mActivityRenderer.draw( g2d, vertex); }
+ else if ( ( vertex instanceof Split ) || ( vertex instanceof Join ) ) { mSplitJoinRenderer.draw( g2d, vertex ); }
+ }
+}
+
diff --git a/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java b/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java
new file mode 100644
index 0000000..f0ae533
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java
@@ -0,0 +1,51 @@
+package com.c2kernel.gui.tabs;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+
+/**************************************************************************
+ *
+ * $Revision: 1.2 $
+ * $Date: 2005/07/05 11:34:17 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+public class AgentPropertiesPane extends EntityTabPane {
+
+ JTable roleTable;
+ JTextField newPassword;
+ JTextField newPasswordConfirm;
+ JButton changePassword;
+
+ public AgentPropertiesPane() {
+ super("Properties", "Agent Details");
+ initPanel();
+ getGridBagConstraints();
+ c.gridy++;
+ JLabel roleHeader = new JLabel("Roles held");
+ roleHeader.setFont(titleFont);
+ roleHeader.setForeground(headingColor);
+ gridbag.setConstraints(roleHeader, c);
+ add(roleHeader);
+ roleTable = new JTable(1,1);
+ JScrollPane roleScroll = new JScrollPane(roleTable);
+ c.gridy++;
+ gridbag.setConstraints(roleScroll, c);
+ add(roleScroll);
+
+ //JLabel passHeader = new JLabel("Change password");
+ //TODO: Finish agent admin page
+ }
+
+ @Override
+ public void run() {
+
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java b/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java
new file mode 100644
index 0000000..a117df4
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java
@@ -0,0 +1,70 @@
+package com.c2kernel.gui.tabs;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+import javax.swing.Icon;
+
+/**
+ * @author Developpement
+ *
+ * To change this generated comment edit the template variable "typecomment":
+ * Window>Preferences>Java>Templates.
+ * To enable and disable the creation of type comments go to
+ * Window>Preferences>Java>Code Generation.
+ */
+/** * The class which generates the 'X' icon for the tabs. The constructor * accepts an icon which is extra to the 'X' icon, so you can have tabs * like in JBuilder. This value is null if no extra icon is required. */
+class CloseTabIcon implements Icon
+{
+ private int x_pos;
+ private int y_pos;
+ private int width;
+ private int height;
+ private Icon fileIcon;
+ public CloseTabIcon(Icon fileIcon)
+ {
+ this.fileIcon = fileIcon;
+ width = 16;
+ height = 16;
+ }
+ @Override
+ public void paintIcon(Component c, Graphics g, int x, int y)
+ {
+ this.x_pos = x;
+ this.y_pos = y;
+ Color col = g.getColor();
+ g.setColor(Color.black);
+ int y_p = y + 2;
+ g.drawLine(x + 1, y_p, x + 12, y_p);
+ g.drawLine(x + 1, y_p + 13, x + 12, y_p + 13);
+ g.drawLine(x, y_p + 1, x, y_p + 12);
+ g.drawLine(x + 13, y_p + 1, x + 13, y_p + 12);
+ g.drawLine(x + 3, y_p + 3, x + 10, y_p + 10);
+ g.drawLine(x + 3, y_p + 4, x + 9, y_p + 10);
+ g.drawLine(x + 4, y_p + 3, x + 10, y_p + 9);
+ g.drawLine(x + 10, y_p + 3, x + 3, y_p + 10);
+ g.drawLine(x + 10, y_p + 4, x + 4, y_p + 10);
+ g.drawLine(x + 9, y_p + 3, x + 3, y_p + 9);
+ g.setColor(col);
+ if (fileIcon != null)
+ {
+ fileIcon.paintIcon(c, g, x + width, y_p);
+ }
+ }
+ @Override
+ public int getIconWidth()
+ {
+ return width + (fileIcon != null ? fileIcon.getIconWidth() : 0);
+ }
+ @Override
+ public int getIconHeight()
+ {
+ return height;
+ }
+ public Rectangle getBounds()
+ {
+ return new Rectangle(x_pos, y_pos, width, height);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java b/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java
new file mode 100644
index 0000000..4d9092e
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java
@@ -0,0 +1,109 @@
+package com.c2kernel.gui.tabs;
+import java.awt.GridBagConstraints;
+
+import javax.swing.JTabbedPane;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.collection.Collection;
+import com.c2kernel.collection.CollectionMember;
+import com.c2kernel.collection.Dependency;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.gui.tabs.collection.AggregationView;
+import com.c2kernel.gui.tabs.collection.CollectionView;
+import com.c2kernel.gui.tabs.collection.DependencyView;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Logger;
+/**
+ * @version $Revision: 1.36 $ $Date: 2005/10/06 06:51:15 $
+ * @author $Author: abranson $
+ */
+public class CollectionPane extends EntityTabPane implements EntityProxyObserver<Collection<? extends CollectionMember>>
+{
+ JTabbedPane collTabs;
+
+ public CollectionPane()
+ {
+ super("Collection", "Item Collection");
+ createLayout();
+ }
+
+ @Override
+ public void add(Collection<? extends CollectionMember> contents)
+ {
+ Logger.msg(5, "Got "+contents.getName()+": "+contents.getClass().getName());
+ Logger.msg(7, "Looking for existing "+contents.getName());
+ CollectionView<? extends CollectionMember> thisCollView = findTabForCollName(contents.getName());
+ if (thisCollView == null){
+ if (contents instanceof Aggregation) {
+ AggregationView thisAggView = new AggregationView();
+ thisAggView.setCollection((Aggregation)contents);
+ thisCollView = thisAggView;
+ }
+ else if (contents instanceof Dependency) {
+ DependencyView thisDepView = new DependencyView();
+ thisDepView.setCollection((Dependency)contents);
+ thisCollView = thisDepView;
+ }
+ else {
+ Logger.error("Collection type "+contents.getClass().getName()+" not known");
+ return;
+ }
+ Logger.msg(3, "Adding new "+thisCollView.getClass().getName());
+ thisCollView.setItem((ItemProxy)sourceEntity.getEntity());
+ collTabs.add(contents.getName(), thisCollView);
+ }
+ }
+
+ @Override
+ public void remove(String id)
+ {
+
+ }
+
+ private CollectionView<? extends CollectionMember> findTabForCollName(String collName) {
+ CollectionView<? extends CollectionMember> thisCollView = null;
+ for (int i = 0; i < collTabs.getTabCount(); i++) {
+ String tabName = collTabs.getTitleAt(i);
+ if (tabName.equals(collName)) {
+ thisCollView = (CollectionView<? extends CollectionMember>)collTabs.getComponentAt(i);
+ }
+ }
+ return thisCollView;
+ }
+
+ protected void createLayout()
+ {
+ initPanel();
+ // Add the collection tab pane
+ getGridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.fill = GridBagConstraints.BOTH;
+ c.weighty = 2.0;
+ collTabs = new JTabbedPane();
+ gridbag.setConstraints(collTabs, c);
+ add(collTabs);
+ }
+
+ @Override
+ public void run()
+ {
+ Thread.currentThread().setName("Collection Loader");
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Collection<?>>(this, ClusterStorage.COLLECTION, true));
+ }
+
+ @Override
+ public void reload()
+ {
+ Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.COLLECTION);
+ collTabs.removeAll();
+ initForEntity(sourceEntity);
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java b/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java
new file mode 100644
index 0000000..408a32c
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java
@@ -0,0 +1,174 @@
+package com.c2kernel.gui.tabs;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.3 $
+ * $Date: 2004/10/21 08:02:21 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class DomainPathAdmin extends Box implements ActionListener {
+
+ ItemProxy entity;
+ JTable table;
+ DomainPathTableModel model;
+ JButton addButton;
+ JButton removeButton;
+
+ public DomainPathAdmin() {
+ super(BoxLayout.Y_AXIS);
+
+ model = new DomainPathTableModel(this);
+ table = new JTable(model);
+ add(new JScrollPane(table));
+
+ add(Box.createVerticalGlue());
+ Box buttonBox = Box.createHorizontalBox();
+ addButton = new JButton("Add");
+ buttonBox.add(addButton);
+ buttonBox.add(Box.createHorizontalGlue());
+ removeButton = new JButton("Remove");
+ buttonBox.add(removeButton);
+ buttonBox.add(Box.createHorizontalGlue());
+ add(buttonBox);
+
+ addButton.setActionCommand("add");
+ addButton.addActionListener(this);
+ removeButton.setActionCommand("remove");
+ removeButton.addActionListener(this);
+ }
+
+ public void setEntity(ItemProxy entity) {
+ this.entity = entity;
+ model.loadPaths();
+ }
+
+ @Override
+public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("add")) {
+ String newPath = JOptionPane.showInputDialog(this, "Enter new path,", "Add Domain Path", JOptionPane.PLAIN_MESSAGE);
+ addDomainPath(new DomainPath(newPath));
+ model.loadPaths();
+ }
+ else if (e.getActionCommand().equals("remove")) {
+ if (table.getSelectedRow() > -1) {
+ DomainPath oldPath = model.getPath(table.getSelectedRow());
+ removeDomainPath(oldPath);
+ model.loadPaths();
+ }
+ }
+ }
+
+ public boolean removeDomainPath(DomainPath oldPath) {
+ return alterDomainPath(oldPath, "Remove");
+ }
+
+ public boolean addDomainPath(DomainPath newPath) {
+ return alterDomainPath(newPath, "Add");
+ }
+
+ public boolean alterDomainPath(DomainPath path, String action) {
+
+ if (JOptionPane.showConfirmDialog(this,
+ action+" "+path+"?",
+ action+" Domain Path",
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+ return false;
+
+ String[] params = new String[1];
+ params[0] = path.toString();
+ try {
+ MainFrame.userAgent.execute(entity, action+"DomainPath", params);
+ } catch (Exception e) {
+ Logger.exceptionDialog(e);
+ return false;
+ }
+ return true;
+ }
+
+ private class DomainPathTableModel extends AbstractTableModel {
+ ArrayList<DomainPath> domPaths;
+ DomainPathAdmin parent;
+ public DomainPathTableModel(DomainPathAdmin parent) {
+ this.parent = parent;
+ domPaths = new ArrayList<DomainPath>();
+ }
+
+ public void loadPaths() {
+ domPaths.clear();
+ for (Enumeration<?> currentPaths = Gateway.getLDAPLookup().search(new DomainPath(), entity.getName()); currentPaths.hasMoreElements();) {
+ DomainPath thisPath = (DomainPath)currentPaths.nextElement();
+ if (thisPath.getSysKey() == entity.getSystemKey())
+ domPaths.add(thisPath);
+ }
+ fireTableDataChanged();
+ }
+
+ public DomainPath getPath(int rowIndex) {
+ return domPaths.get(rowIndex);
+ }
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ DomainPath oldPath = domPaths.get(rowIndex);
+ DomainPath newPath = new DomainPath((String)aValue);
+ boolean success = parent.addDomainPath(newPath);
+ if (success)
+ success = parent.removeDomainPath(oldPath);
+ if (success) {
+ oldPath.setPath(newPath);
+ fireTableDataChanged();
+ }
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ return String.class;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 1;
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return "Path";
+ }
+
+ @Override
+ public int getRowCount() {
+ return domPaths.size();
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ return domPaths.get(rowIndex).toString();
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java b/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java
new file mode 100644
index 0000000..9a30d59
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java
@@ -0,0 +1,197 @@
+/*
+ * TabbedPane.java
+ *
+ * Created on March 22, 2001, 11:39 AM
+ */
+package com.c2kernel.gui.tabs;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JToggleButton;
+import javax.swing.SwingConstants;
+
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.gui.EntityDetails;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.gui.tabs.outcome.form.OutcomePanel;
+import com.c2kernel.gui.tree.NodeEntity;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+/**
+ * Generic item details tabbed pane.
+ *
+ * @version $Revision: 1.31 $ $Date: 2005/06/08 16:47:44 $
+ * @author $Author: abranson $
+ */
+public class EntityTabPane extends JPanel implements Runnable {
+
+ protected NodeEntity sourceEntity;
+ protected String titleText = null;
+ protected ImageIcon titleIcon = null;
+ private final String tabName;
+ protected GridBagLayout gridbag = new GridBagLayout();
+ protected GridBagConstraints c = null;
+ public static Font titleFont = null;
+ public static Color headingColor = new Color(0, 0, 185);
+ protected EntityDetails parent;
+ protected static ImageIcon mReloadIcon = null;
+ protected Box titleBox;
+ static {
+ try {
+ mReloadIcon = Resource.findImage("reload.gif");
+ } catch (Exception e) {
+ Logger.warning("Couldn't load images: " + e);
+ }
+ }
+
+ public void focusLost(FocusEvent e)
+ {
+ }
+
+ public EntityTabPane(String tabName, String titleText) {
+ this.tabName = Language.translate(tabName);
+ this.titleText =
+ titleText == null ? null : Language.translate(titleText);
+ if (titleFont == null)
+ titleFont =
+ new Font("SansSerif", Font.BOLD, this.getFont().getSize() + 5);
+ Logger.msg(2, "ItemTabPane.<init> - viewing " + tabName);
+ setLayout(gridbag);
+ }
+ public void setParent(EntityDetails parent) {
+ this.parent = parent;
+ }
+ public String getTabName() {
+ return tabName;
+ }
+ protected GridBagConstraints getGridBagConstraints() {
+ if (c == null)
+ c = new GridBagConstraints();
+ return c;
+ }
+ protected void initPanel() {
+ getGridBagConstraints().gridx = 0;
+ getGridBagConstraints().gridy = 0;
+ getGridBagConstraints().anchor = GridBagConstraints.NORTHWEST;
+ getGridBagConstraints().fill = GridBagConstraints.HORIZONTAL;
+ getGridBagConstraints().ipadx = 5;
+ getGridBagConstraints().weightx = 1.0;
+ getGridBagConstraints().ipady = 5;
+ // Help panel
+ if (titleText == null)
+ titleText = tabName;
+ if (titleIcon == null)
+ titleIcon = Resource.findImage("info.png");
+ JLabel title = new JLabel(titleText, titleIcon, SwingConstants.LEFT);
+ title.setFont(titleFont);
+ title.setForeground(headingColor);
+ JButton refreshButton = new JButton(mReloadIcon);
+ refreshButton.setToolTipText(Language.translate("Refresh"));
+ refreshButton.setMargin(new Insets(0, 0, 0, 0));
+ refreshButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ reload();
+ setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ }
+ });
+ String defaultStartTab = MainFrame.getPref("DefaultStartTab", "Properties");
+ JToggleButton defaultStart =
+ new JToggleButton(Resource.findImage("graph/start.png"));
+ defaultStart.setMargin(new Insets(0, 0, 0, 0));
+ defaultStart.setToolTipText(
+ Language.translate("Select this tab to be the default one opened when you double click an item"));
+ defaultStart.setSelected(tabName.equals(defaultStartTab));
+ defaultStart.setActionCommand(tabName);
+ defaultStart.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (((JToggleButton)e.getSource()).isSelected())
+ MainFrame.setPref("DefaultStartTab", e.getActionCommand());
+ }
+ });
+ titleBox = Box.createHorizontalBox();
+ titleBox.add(title);
+ titleBox.add(Box.createHorizontalGlue());
+ titleBox.add(defaultStart);
+ titleBox.add(refreshButton);
+ gridbag.setConstraints(titleBox, c);
+ this.add(titleBox);
+ }
+ public void initForEntity(NodeEntity sourceEntity) {
+ this.sourceEntity = sourceEntity;
+ Thread loader = new Thread(this);
+ loader.start();
+ }
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Default Entity Pane Builder");
+ getGridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.ipadx = 5;
+ c.weightx = 1.0;
+ c.weighty = 1.0;
+ c.ipady = 5;
+ JLabel error = new JLabel("In Development");
+ gridbag.setConstraints(error, c);
+ this.add(error);
+ }
+ public void reload() {
+ }
+ public void runCommand(String command) {
+ }
+
+ public void destroy() {
+ if (sourceEntity != null && this instanceof EntityProxyObserver<?>) {
+ sourceEntity.getEntity().unsubscribe((EntityProxyObserver<?>)this);
+ }
+ parent = null;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ Logger.msg(7, "Reaping "+getClass().getName());
+ }
+
+ static public OutcomeHandler getOutcomeHandler(String schema, int version) {
+ String ohClassName = Gateway.getProperty("OutcomeHandler."+schema+"."+version);
+ try {
+ if (ohClassName != null && ohClassName.length() > 0) {
+ Class<?> ohClass = Class.forName(ohClassName);
+ return (OutcomeHandler) ohClass.newInstance();
+ }
+ } catch (Exception ex) {
+ Logger.error("Error creating handler "+ohClassName+". using default outcome editor");
+ }
+ ohClassName = Gateway.getProperty("OutcomeHandler.*");
+ try {
+ if (ohClassName != null && ohClassName.length() > 0) {
+ Class<?> ohClass = Class.forName(ohClassName);
+ return (OutcomeHandler) ohClass.newInstance();
+ }
+ } catch (Exception ex) {
+ Logger.error("Error creating handler "+ohClassName+". using default outcome editor");
+ Logger.error(ex);
+ }
+ return new OutcomePanel();
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java b/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java
new file mode 100644
index 0000000..a853695
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java
@@ -0,0 +1,208 @@
+package com.c2kernel.gui.tabs;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.swing.Box;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.execution.ActivityItem;
+import com.c2kernel.gui.tabs.execution.ActivityViewer;
+import com.c2kernel.lifecycle.instance.Workflow;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+public class ExecutionPane extends EntityTabPane implements EntityProxyObserver<Workflow> {
+
+ ArrayList<Job> jobList = null;
+ Object jobLock = new Object();
+ ActivityItem emptyAct = new ActivityItem();
+ JLabel noActs = new JLabel(Language.translate("There are currently no activities that you can execute in this item."));
+ JPanel view = new JPanel(new GridLayout(1, 1));
+ ActivityViewer currentActView;
+ JComboBox activitySelector = new JComboBox();
+ Box activityBox = Box.createHorizontalBox();
+ String selAct = null;
+ ArrayList<ActivityItem> activities;
+ String autoRun = null;
+ boolean init = false;
+ boolean formIsActive = false;
+ public ExecutionPane() {
+ super("Execution", "Activity Execution");
+ super.initPanel();
+ // add view panel
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 1; c.weightx = 1.0; c.weighty = 2.0;
+ c.insets = new Insets(5, 5, 5, 5);
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(view, c);
+
+ add(view);
+ // create activity selection box
+ activityBox.add(new JLabel(Language.translate("Select Activity") + ": "));
+ activityBox.add(Box.createHorizontalStrut(5));
+ activitySelector.setEditable(false);
+ activityBox.add(activitySelector);
+ activitySelector.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent selection) {
+ if (selection.getStateChange() == ItemEvent.SELECTED) {
+ selectActivity(selection.getItem());
+ }
+ }
+ });
+ }
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Execution Pane Builder");
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Workflow>(this, ClusterStorage.LIFECYCLE, false));
+ loadJobList();
+ init = true;
+ if (autoRun != null) {
+ runCommand(autoRun);
+ autoRun = null;
+ }
+ }
+ private void loadJobList() {
+ synchronized (jobLock) {
+ activitySelector.removeAllItems();
+ view.removeAll();
+ activities = new ArrayList<ActivityItem>();
+ try {
+ jobList = ((ItemProxy)sourceEntity.getEntity()).getJobList(MainFrame.userAgent);
+ activitySelector.addItem(emptyAct);
+ for (Job thisJob : jobList) {
+ Logger.msg(7, "ExecutionPane - loadJobList " + thisJob.isOutcomeUsed() + "|" + thisJob.getSchemaType() + "|" + thisJob.getSchemaVersion() + "|");
+ ActivityItem newAct = new ActivityItem(thisJob);
+ if (activities.contains(newAct)) {
+ int actIndex = activities.indexOf(newAct);
+ activities.get(actIndex).addJob(thisJob);
+ } else {
+ Logger.msg(2, "ExecutionPane - Adding activity " + thisJob.getStepPath());
+ addActivity(newAct);
+ }
+ }
+ } catch (Exception e) {
+ Logger.debug("Error fetching joblist");
+ Logger.error(e);
+ }
+
+ switch (activities.size()) {
+ case 0 :
+ view.add(noActs);
+ break;
+ case 1 :
+ currentActView = new ActivityViewer(activities.get(0), (ItemProxy)sourceEntity.getEntity(), this);
+ c.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(view, c);
+ view.add(currentActView);
+ currentActView.init();
+ break;
+ default :
+ c.fill = GridBagConstraints.HORIZONTAL;
+ gridbag.setConstraints(view, c);
+ view.add(activityBox);
+ }
+ }
+ revalidate();
+ updateUI();
+ }
+ @Override
+ public void reload() {
+ loadJobList();
+ }
+ private void addActivity(ActivityItem newAct) {
+ if (activities.contains(newAct)) {
+ Logger.msg(6, "ExecutionPane.addActivity(): Already in " + newAct.getStepPath());
+ int actIndex = activities.indexOf(newAct);
+ activitySelector.removeItemAt(actIndex);
+ activitySelector.insertItemAt(newAct, actIndex);
+ activities.set(actIndex, newAct);
+ } else {
+ Logger.msg(6, "ExecutionPane.addActivity(): New " + newAct.getStepPath());
+ activities.add(newAct);
+ activitySelector.addItem(newAct);
+ }
+ }
+ private void selectActivity(Object selObj) {
+ if (selObj.equals(emptyAct))
+ return;
+ view.removeAll();
+ c.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(view, c);
+ currentActView = new ActivityViewer((ActivityItem)selObj, (ItemProxy)sourceEntity.getEntity(), this);
+ view.add(currentActView);
+ revalidate();
+ updateUI();
+ currentActView.init();
+ }
+ @Override
+ public void runCommand(String command) {
+ if (init) {
+ for (ActivityItem act : activities) {
+ if (act.name.equals(command)) {
+ selectActivity(act);
+ }
+ }
+ } else
+ autoRun = command;
+ }
+ /**
+ * when the workflow changes, reload this pane.
+ */
+ @Override
+ public void add(Workflow contents) {
+ if (!formIsActive)
+ reload();
+ else { // look to see if this form is now invalid
+ // get the new joblist
+ try {
+ jobList = ((ItemProxy)sourceEntity.getEntity()).getJobList(MainFrame.userAgent);
+ } catch (Exception ex) {
+ return;
+ }
+ // compare to currently editing jobs
+ ArrayList<?> currentActJobs = currentActView.getActivity().getJobs();
+ boolean allValid = true;
+ for (Iterator<?> iter = currentActJobs.iterator(); iter.hasNext() && allValid;) {
+ Job thisJob = (Job)iter.next();
+ boolean stillValid = false;
+ for (Job newJob : jobList) {
+ if (thisJob.equals(newJob)) {
+ stillValid = true;
+ break;
+ }
+ }
+ allValid &= stillValid;
+ }
+ if (!allValid) { // not all transitions are now valid
+ reload(); // refresh the execution pane
+ }
+ }
+ }
+ /**
+ * Not pertinent for this one
+ */
+ @Override
+ public void remove(String id) {
+ }
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java b/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java
new file mode 100644
index 0000000..5b3d536
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java
@@ -0,0 +1,270 @@
+/*
+ * StatusPane.java
+ *
+ * Created on March 20, 2001, 3:30 PM
+ */
+
+package com.c2kernel.gui.tabs;
+
+/**
+ * @author abranson
+ * @version
+ */
+import java.awt.GridBagConstraints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.events.Event;
+import com.c2kernel.events.History;
+import com.c2kernel.lifecycle.instance.stateMachine.Transitions;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Pane to display all work orders that this agent can execute, and activate
+ * them on request from the user. Subscribes to NodeItem for WorkOrder objects.
+ * @version $Revision: 1.22 $ $Date: 2005/04/26 06:48:13 $
+ * @author $Author: abranson $
+ */
+public class HistoryPane extends EntityTabPane implements ActionListener, EntityProxyObserver<Event> {
+
+ History history;
+ HistoryTableModel model;
+ JTable eventTable;
+ JButton startButton = new JButton("<<");
+ JButton prevButton = new JButton("<");
+ JButton nextButton = new JButton(">");
+ JButton endButton = new JButton(">>");
+ public static final int SIZE = 30;
+ int currentSize = SIZE;
+
+ public HistoryPane() {
+ super("History", "Event History");
+ initPanel();
+
+ // add buttons
+ Box navBox = Box.createHorizontalBox();
+ navBox.add(startButton); navBox.add(prevButton);
+ navBox.add(nextButton); navBox.add(endButton);
+
+ // setup buttons
+ //startButton.setEnabled(false); nextButton.setEnabled(false);
+ //prevButton.setEnabled(false); endButton.setEnabled(false);
+ startButton.setActionCommand("start");
+ startButton.addActionListener(this);
+ prevButton.setActionCommand("prev");
+ prevButton.addActionListener(this);
+ nextButton.setActionCommand("next");
+ nextButton.addActionListener(this);
+ endButton.setActionCommand("end");
+ endButton.addActionListener(this);
+ getGridBagConstraints();
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill=GridBagConstraints.NONE;
+ c.weightx=0; c.weighty=0;
+ gridbag.setConstraints(navBox, c);
+ add(navBox);
+
+
+ // Create table
+ eventTable = new JTable();
+ JScrollPane eventScroll= new JScrollPane(eventTable);
+ c.weightx = 1.0; c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH; c.gridy++;
+ gridbag.setConstraints(eventScroll, c);
+ add(eventScroll);
+
+ }
+
+ @Override
+ public void reload() {
+ history.clear();
+ jumpToEnd();
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("History Pane Builder");
+ try {
+ history = (History)sourceEntity.getEntity().getObject(ClusterStorage.HISTORY);
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Event>(this, ClusterStorage.HISTORY, false));
+ } catch (ObjectNotFoundException e) {
+ Logger.error(e);
+ }
+ model = new HistoryTableModel();
+ eventTable.setModel(model);
+ jumpToEnd();
+ }
+
+ public void jumpToEnd() {
+ int lastEvent = history.getLastId();
+ int firstEvent = 0; currentSize = SIZE;
+ if (lastEvent > currentSize) firstEvent = lastEvent - currentSize + 1;
+ if (lastEvent < currentSize) currentSize = lastEvent + 1;
+ Logger.msg(5, "HistoryPane.run() - init table start "+firstEvent+" for "+currentSize);
+ model.setView(firstEvent, currentSize);
+ }
+
+ @Override
+ public void add(Event contents) {
+ jumpToEnd();
+ }
+
+ @Override
+ public void remove(String id) {
+ // don't have to deal with this normally
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("end")) {
+ jumpToEnd();
+ return;
+ }
+
+ int lastEvent = history.getLastId();
+ int startEvent = model.getStartId();
+ if (e.getActionCommand().equals("start")) {
+ currentSize = SIZE;
+ startEvent = 0;
+ }
+
+ else if (e.getActionCommand().equals("prev")) {
+ currentSize = SIZE;
+ startEvent-=currentSize;
+ if (startEvent<0) startEvent = 0;
+ }
+ else if (e.getActionCommand().equals("next")) {
+ currentSize = SIZE;
+ startEvent+=currentSize;
+ if (startEvent > lastEvent)
+ startEvent = lastEvent - currentSize +1;
+ }
+ else { // unknown action
+ return;
+ }
+
+ model.setView(startEvent, currentSize);
+ }
+
+ private class HistoryTableModel extends AbstractTableModel {
+ Event[] event;
+ Integer[] ids;
+ int loaded = 0;
+ int startId = 0;
+
+ public HistoryTableModel() {
+ event = new Event[0];
+ ids = new Integer[0];
+ }
+
+ public int getStartId() {
+ return startId;
+ }
+
+ public void setView(int startId, int size) {
+ event = new Event[size];
+ ids = new Integer[size];
+ this.startId = startId;
+ for (int i=0; i<size; i++) {
+ event[i] = history.getEvent(startId+i);
+ ids[i] = new Integer(startId+i);
+ loaded = i+1;
+ }
+ fireTableStructureChanged();
+ }
+ /**
+ * @see javax.swing.table.TableModel#getColumnClass(int)
+ */
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ switch(columnIndex) {
+ case 0:
+ return Integer.class;
+ default:
+ return String.class;
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getColumnCount()
+ */
+ @Override
+ public int getColumnCount() {
+ return 6;
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getColumnName(int)
+ */
+ @Override
+ public String getColumnName(int columnIndex) {
+ switch(columnIndex) {
+ case 0: return Language.translate("ID");
+ case 1: return Language.translate("Activity");
+ case 2: return Language.translate("Transition");
+ case 3: return Language.translate("Date");
+ case 4: return Language.translate("Agent Name");
+ case 5: return Language.translate("Agent Role");
+ default: return "";
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getRowCount()
+ */
+ @Override
+ public int getRowCount() {
+ return loaded;
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ if (event.length <= rowIndex || event[rowIndex] == null)
+ return "";
+ try {
+ switch (columnIndex) {
+ case 0: return ids[rowIndex];
+ case 1: return event[rowIndex].getStepName();
+ case 2: return Transitions.getTransitionName(event[rowIndex].getTransition());
+ case 3: return event[rowIndex].getTimeString();
+ case 4: return event[rowIndex].getAgentName();
+ case 5: return event[rowIndex].getAgentRole();
+ default: return "";
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#isCellEditable(int, int)
+ */
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return false;
+ }
+
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java b/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java
new file mode 100644
index 0000000..8f047ca
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java
@@ -0,0 +1,96 @@
+package com.c2kernel.gui.tabs;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.Icon;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import com.c2kernel.gui.EntityDetails;
+
+/**
+ * @author Developpement
+ *
+ * Allows a close icone in JTabbePane
+ */
+public class JTabbedPaneWithCloseIcons extends JTabbedPane implements MouseListener, ChangeListener
+{
+ /**
+ *
+ */
+ public JTabbedPaneWithCloseIcons()
+ {
+ super();
+ addMouseListener(this);
+ addChangeListener(this);
+ }
+ /**
+ * @see javax.swing.JTabbedPane#addTab(String, Icon, Component, String)
+ */
+ @Override
+ public void addTab(String title, Icon arg2, Component component, String arg3)
+ {
+ super.addTab(title, new CloseTabIcon(arg2), component, arg3);
+ }
+ /**
+ * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
+ */
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ int tabNumber = getUI().tabForCoordinate(this, e.getX(), e.getY());
+ Component cp = null;
+ if (tabNumber < 0)
+ return;
+ Rectangle rect = ((CloseTabIcon) getIconAt(tabNumber)).getBounds();
+ if (rect.contains(e.getX(), e.getY())||(e.getModifiers()& InputEvent.CTRL_MASK) != 0)
+ { //the tab is being closed
+ cp = this.getComponent(tabNumber);
+ //if (getComponentCount() != 1)
+ if (cp instanceof EntityDetails)
+ {
+ ((EntityDetails) cp).closeTab();
+ remove(cp);
+ }
+ }
+ stateChanged(new ChangeEvent(this));
+ }
+ /**
+ * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
+ */
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ }
+ /**
+ * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
+ */
+ @Override
+ public void mouseExited(MouseEvent e)
+ {
+ }
+ /**
+ * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
+ */
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ }
+ /**
+ * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
+ */
+ @Override
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+ @Override
+ public void stateChanged(ChangeEvent e)
+ {
+ if (getSelectedComponent()!= null)
+ ((EntityDetails) getSelectedComponent()).refresh();
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/JobListPane.java b/src/main/java/com/c2kernel/gui/tabs/JobListPane.java
new file mode 100644
index 0000000..619a589
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/JobListPane.java
@@ -0,0 +1,312 @@
+/*
+ * StatusPane.java
+ *
+ * Created on March 20, 2001, 3:30 PM
+ */
+
+package com.c2kernel.gui.tabs;
+
+/**
+ * @author abranson
+ * @version
+ */
+import java.awt.GridBagConstraints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Iterator;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.entity.agent.JobList;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.lifecycle.instance.stateMachine.Transitions;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.property.Property;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Pane to display all work orders that this agent can execute, and activate
+ * them on request from the user. Subscribes to NodeItem for WorkOrder objects.
+ * @version $Revision: 1.4 $ $Date: 2004/10/21 08:02:21 $
+ * @author $Author: abranson $
+ */
+public class JobListPane extends EntityTabPane implements ActionListener, EntityProxyObserver<Job> {
+
+ JobList joblist;
+ JoblistTableModel model;
+ JTable eventTable;
+ JButton startButton = new JButton("<<");
+ JButton prevButton = new JButton("<");
+ JButton nextButton = new JButton(">");
+ JButton endButton = new JButton(">>");
+ public static final int SIZE = 30;
+ int currentSize = SIZE;
+
+ public JobListPane() {
+ super("Job List", "Agent Job List");
+ initPanel();
+
+ // add buttons
+ Box navBox = Box.createHorizontalBox();
+ navBox.add(startButton); navBox.add(prevButton);
+ navBox.add(nextButton); navBox.add(endButton);
+
+ // setup buttons
+ //startButton.setEnabled(false); nextButton.setEnabled(false);
+ //prevButton.setEnabled(false); endButton.setEnabled(false);
+ startButton.setActionCommand("start");
+ startButton.addActionListener(this);
+ prevButton.setActionCommand("prev");
+ prevButton.addActionListener(this);
+ nextButton.setActionCommand("next");
+ nextButton.addActionListener(this);
+ endButton.setActionCommand("end");
+ endButton.addActionListener(this);
+ getGridBagConstraints();
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill=GridBagConstraints.NONE;
+ c.weightx=0; c.weighty=0;
+ gridbag.setConstraints(navBox, c);
+ add(navBox);
+
+
+ // Create table
+ eventTable = new JTable();
+ JScrollPane eventScroll= new JScrollPane(eventTable);
+ c.weightx = 1.0; c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH; c.gridy++;
+ gridbag.setConstraints(eventScroll, c);
+ add(eventScroll);
+
+ // detect double clicked jobs
+ eventTable.addMouseListener(new JobListMouseListener());
+ }
+
+ @Override
+ public void reload() {
+ joblist.clear();
+ jumpToEnd();
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Joblist Pane Builder");
+ try {
+ joblist = (JobList)sourceEntity.getEntity().getObject(ClusterStorage.JOB);
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Job>(this, ClusterStorage.JOB, false));
+ } catch (ObjectNotFoundException e) {
+ Logger.error(e);
+ }
+ model = new JoblistTableModel(joblist);
+ eventTable.setModel(model);
+ jumpToEnd();
+ }
+
+
+ public void jumpToEnd() {
+ int lastEvent = joblist.getLastId();
+ int firstEvent = 0; currentSize = SIZE;
+ if (lastEvent > currentSize) firstEvent = lastEvent - currentSize + 1;
+ if (lastEvent < currentSize) currentSize = lastEvent + 1;
+ Logger.msg(5, "JobListPane.run() - init table start "+firstEvent+" for "+currentSize);
+ model.setView(firstEvent, currentSize);
+ }
+
+ @Override
+ public void add(Job contents) {
+ reload();
+ }
+
+ @Override
+ public void remove(String id) {
+ reload();
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("end")) {
+ jumpToEnd();
+ return;
+ }
+
+ int lastEvent = joblist.getLastId();
+ int startEvent = model.getStartId();
+ if (e.getActionCommand().equals("start")) {
+ currentSize = SIZE;
+ startEvent = 0;
+ }
+
+ else if (e.getActionCommand().equals("prev")) {
+ currentSize = SIZE;
+ startEvent-=currentSize;
+ if (startEvent<0) startEvent = 0;
+ }
+ else if (e.getActionCommand().equals("next")) {
+ currentSize = SIZE;
+ startEvent+=currentSize;
+ if (startEvent > lastEvent)
+ startEvent = lastEvent - currentSize +1;
+ }
+ else { // unknown action
+ return;
+ }
+
+ model.setView(startEvent, currentSize);
+ }
+
+ private class JoblistTableModel extends AbstractTableModel {
+ Job[] job;
+ Integer[] ids;
+ String[] itemNames;
+ int loaded = 0;
+ int startId = 0;
+
+ public JoblistTableModel(JobList joblist) {
+ job = new Job[0];
+ ids = new Integer[0];
+ }
+
+ public int getStartId() {
+ return startId;
+ }
+
+ public void setView(int startId, int size) {
+ job = new Job[size];
+ ids = new Integer[size];
+ itemNames = new String[size];
+ this.startId = startId;
+ int count = 0;
+ for (Iterator<?> i = joblist.keySet().iterator(); i.hasNext();) {
+ Integer thisJobId = new Integer((String)i.next());
+ if (count >= startId) {
+ int idx = count-startId;
+ ids[idx] = thisJobId;
+ job[idx] = joblist.getJob(thisJobId.intValue());
+ itemNames[idx] = "Item Not Found";
+ try {
+ itemNames[idx] = ((Property)Gateway.getStorage().get(job[count-startId].getItemSysKey(), ClusterStorage.PROPERTY+"/Name", null)).getValue();
+ } catch (Exception ex) {
+ Logger.error(ex);
+ }
+
+ }
+ count++;
+ loaded = count-startId;
+ if (count > (startId + size)) break;
+ }
+ fireTableStructureChanged();
+ }
+ /**
+ * @see javax.swing.table.TableModel#getColumnClass(int)
+ */
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ switch(columnIndex) {
+ case 0:
+ return Integer.class;
+ default:
+ return String.class;
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getColumnCount()
+ */
+ @Override
+ public int getColumnCount() {
+ return 4;
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getColumnName(int)
+ */
+ @Override
+ public String getColumnName(int columnIndex) {
+ switch(columnIndex) {
+ case 0: return Language.translate("ID");
+ case 1: return Language.translate("Subject");
+ case 2: return Language.translate("Activity");
+ case 3: return Language.translate("Transition");
+ default: return "";
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getRowCount()
+ */
+ @Override
+ public int getRowCount() {
+ return loaded;
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ if (job.length <= rowIndex || job[rowIndex] == null)
+ return "";
+ try {
+ switch (columnIndex) {
+ case 0: return ids[rowIndex];
+ case 1: return itemNames[rowIndex];
+ case 2: return job[rowIndex].getStepName();
+ case 3: return Transitions.getTransitionName(job[rowIndex].getPossibleTransition());
+ default: return "";
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * @see javax.swing.table.TableModel#isCellEditable(int, int)
+ */
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return false;
+ }
+
+ public Job getJobAtRow(int rowIndex) {
+ return job[rowIndex];
+ }
+
+ }
+
+ private class JobListMouseListener extends MouseAdapter {
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ super.mouseClicked(e);
+ if (e.getClickCount() == 2) {
+ Job selectedJob = model.getJobAtRow(eventTable.getSelectedRow());
+ try {
+ MainFrame.itemFinder.pushNewKey(selectedJob.getItemProxy().getName());
+ } catch (Exception ex) {
+ Logger.error(ex);
+ JOptionPane.showMessageDialog(null, "No Item Found", "Job references an unknown item", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java b/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java
new file mode 100644
index 0000000..4a78581
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java
@@ -0,0 +1,200 @@
+/*
+ * StatusPane.java
+ *
+ * Created on March 20, 2001, 3:30 PM
+ */
+
+package com.c2kernel.gui.tabs;
+
+/**
+ * @author abranson
+ * @version
+ */
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tree.NodeAgent;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.property.Property;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Pane to display all work orders that this agent can execute, and activate
+ * them on request from the user. Subscribes to NodeItem for Property objects.
+ * @version $Revision: 1.44 $ $Date: 2005/08/31 07:21:20 $
+ * @author $Author: abranson $
+ */
+public class PropertiesPane extends EntityTabPane implements EntityProxyObserver<Property>, ActionListener {
+
+ Box propertyBox;
+ boolean subbed = false;
+ HashMap<String, JLabel> loadedProps = new HashMap<String, JLabel>();
+ JLabel domTitle;
+ DomainPathAdmin domAdmin;
+
+ public PropertiesPane() {
+ super("Properties", "Properties");
+ initPanel();
+
+ // Create box container for properties
+ getGridBagConstraints();
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 1.0; c.weighty = 2.0;
+ propertyBox = Box.createVerticalBox();
+ gridbag.setConstraints(propertyBox, c);
+ add(propertyBox);
+ if (MainFrame.isAdmin) { // edit dompath
+ c.gridy++;
+ c.fill = GridBagConstraints.NONE;
+ c.weighty=0.0;
+ domTitle = new JLabel("Domain Paths", titleIcon, SwingConstants.LEFT);
+ domTitle.setFont(titleFont);
+ domTitle.setForeground(headingColor);
+ gridbag.setConstraints(domTitle, c);
+ add(domTitle);
+
+ c.gridy++;
+ c.fill = GridBagConstraints.BOTH;
+ c.weighty=1.0;
+ domAdmin = new DomainPathAdmin();
+ gridbag.setConstraints(domAdmin, c);
+ add(domAdmin);
+
+
+ if ("true".equals(Gateway.getProperty("EnableItemErase"))) {
+ c.gridy++;
+ c.fill = GridBagConstraints.NONE;
+ JButton eraseButton = new JButton(Language.translate("Erase!"));
+ eraseButton.addActionListener(this);
+ eraseButton.setActionCommand("Erase Item");
+ gridbag.setConstraints(eraseButton, c);
+ add(eraseButton);
+ }
+ }
+ }
+
+ @Override
+ public void reload() {
+ Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.PROPERTY);
+ loadedProps = new HashMap<String, JLabel>();
+ initForEntity(sourceEntity);
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Property Pane Builder");
+ if (sourceEntity instanceof NodeAgent) {
+ remove(domAdmin);
+ remove(domTitle);
+ }
+ else if (domAdmin != null)
+ domAdmin.setEntity((ItemProxy)sourceEntity.getEntity());
+ propertyBox.removeAll();
+ propertyBox.add(Box.createGlue());
+ revalidate();
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Property>(this, ClusterStorage.PROPERTY, true));
+
+ }
+ /**
+ *
+ */
+ @Override
+ public void add(Property newProp) {
+ JLabel propLabel = loadedProps.get(newProp.getName());
+ if (propLabel == null) { // new prop
+ JPanel summaryPanel = new JPanel(new GridLayout(0,2));
+ summaryPanel.add(new JLabel(Language.translate(newProp.getName()) + ":"));
+ Box valueBox = Box.createHorizontalBox();
+ propLabel = new JLabel(newProp.getValue());
+ loadedProps.put(newProp.getName(), propLabel);
+ valueBox.add(propLabel);
+ if (MainFrame.isAdmin) {
+ JButton editButton = new JButton("...");
+ editButton.setMargin(new Insets(0,0,0,0));
+ editButton.setActionCommand(newProp.getName());
+ editButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e){
+ String oldVal = loadedProps.get(e.getActionCommand()).getText();
+ String newVal = (String)JOptionPane.showInputDialog(null, "Enter new value for "+e.getActionCommand(), "Edit Property",
+ JOptionPane.QUESTION_MESSAGE, null, null, oldVal);
+ if (newVal!=null && !(newVal.equals(oldVal))) {
+ try {
+ ((ItemProxy)sourceEntity.getEntity()).setProperty(MainFrame.userAgent, e.getActionCommand(), newVal);
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+ }
+ });
+ valueBox.add(Box.createVerticalStrut(7));
+ valueBox.add(editButton);
+
+ }
+ summaryPanel.add(valueBox);
+ propertyBox.add(Box.createVerticalStrut(7));
+ propertyBox.add(summaryPanel);
+ }
+ propLabel.setText(newProp.getValue());
+ revalidate();
+ }
+
+ @Override
+ public void remove(String id) {
+ String propName = id.substring(id.lastIndexOf("/")+1);
+ JLabel propbox = loadedProps.get(propName);
+ if (propbox!= null) propbox.setText("DELETED");
+ revalidate();
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String[] params;
+ String predefStep;
+
+ if (JOptionPane.showConfirmDialog(this,
+ "Are you sure?",
+ e.getActionCommand(),
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+ return;
+
+ if (e.getActionCommand().equals("Erase Item")) {
+ params = new String[0];
+ predefStep = "Erase";
+ }
+ else
+ return;
+
+ try {
+ MainFrame.userAgent.execute((ItemProxy)sourceEntity.getEntity(), predefStep, params);
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java b/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java
new file mode 100644
index 0000000..52c9cb3
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java
@@ -0,0 +1,515 @@
+
+package com.c2kernel.gui.tabs;
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.C2KLocalObject;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.events.Event;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.persistency.outcome.Outcome;
+import com.c2kernel.persistency.outcome.Viewpoint;
+import com.c2kernel.utils.CastorXMLUtility;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.LocalObjectLoader;
+import com.c2kernel.utils.Logger;
+
+public class ViewpointPane extends EntityTabPane implements ItemListener, ActionListener, EntityProxyObserver<C2KLocalObject> {
+
+ JComboBox schemas;
+ JComboBox views;
+ JComboBox events;
+ JLabel eventDetails;
+ JButton exportButton;
+ JButton viewButton;
+
+ ArrayList<String> schemaList;
+ ArrayList<Viewpoint> viewpointList;
+ ArrayList<EventItem> eventList;
+ String currentSchema = null;
+ Outcome currentOutcome = null;
+ OutcomeHandler thisOutcome;
+ boolean suspendSelection = false;
+
+ JPanel dataView = new JPanel(new GridLayout(1,1));
+
+ public ViewpointPane() {
+
+ super("Data Viewer", "Outcome Browser");
+ initialize();
+ }
+
+ public void initialize() {
+ initPanel();
+
+ getGridBagConstraints();
+
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.ipadx = 5; c.weightx = 1.0;
+ c.ipady = 5;
+
+ // Set up view box
+
+ Box viewBox = Box.createHorizontalBox();
+
+ JLabel label = new JLabel(Language.translate("Outcome Type")+":", SwingConstants.LEFT);
+ viewBox.add(label);
+ viewBox.add(Box.createHorizontalStrut(7));
+
+ schemas = new JComboBox();
+ viewBox.add(schemas);
+ viewBox.add(Box.createHorizontalGlue());
+ schemas.addItemListener(this);
+
+ label = new JLabel(Language.translate("View")+":", SwingConstants.LEFT);
+ viewBox.add(label);
+ viewBox.add(Box.createHorizontalStrut(7));
+
+ views = new JComboBox();
+ viewBox.add(views);
+ viewBox.add(Box.createHorizontalGlue());
+ views.addItemListener(this);
+
+ gridbag.setConstraints(viewBox, c);
+ this.add(viewBox);
+
+ // Set up event details box
+ c.gridy++;
+ Box eventBox = Box.createHorizontalBox();
+
+ label = new JLabel(Language.translate("Event")+":", SwingConstants.LEFT);
+ eventBox.add(label);
+ eventBox.add(Box.createHorizontalStrut(7));
+
+ events = new JComboBox();
+ eventBox.add(events);
+ eventBox.add(Box.createHorizontalStrut(7));
+ events.addItemListener(this);
+
+ eventDetails = new JLabel();
+ eventBox.add(eventDetails);
+ eventBox.add(Box.createHorizontalGlue());
+
+ if (MainFrame.isAdmin) {
+ viewButton = new JButton(Language.translate("Write View"));
+ viewButton.setMargin(new Insets(0, 0, 0, 0));
+ viewButton.setActionCommand("setview");
+ eventBox.add(viewButton);
+ eventBox.add(Box.createHorizontalStrut(14));
+ viewButton.addActionListener(this);
+ }
+
+ exportButton = new JButton(Language.translate("Export"));
+ exportButton.setMargin(new Insets(0, 0, 0, 0));
+ exportButton.setActionCommand("export");
+ exportButton.addActionListener(this);
+ eventBox.add(exportButton);
+
+ gridbag.setConstraints(eventBox, c);
+ this.add(eventBox);
+
+ // data pane
+ c.gridx = 0; c.gridy = 3;
+ c.anchor = GridBagConstraints.NORTHWEST; c.fill = GridBagConstraints.BOTH;
+ c.weighty = 1.0; c.weightx = 1.0;
+ gridbag.setConstraints(dataView, c);
+ this.add(dataView);
+ }
+
+ @Override
+ public void reload() {
+ // reset boxes
+ schemas.removeAllItems();
+ views.removeAllItems();
+ events.removeAllItems();
+ eventDetails.setText("");
+
+ clearView();
+
+ // reload
+ initForEntity(sourceEntity);
+ }
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Viewpoint Pane Builder");
+ //Local object subscriptions
+ sourceEntity.getEntity().subscribe(new MemberSubscription<C2KLocalObject>(this, ClusterStorage.VIEWPOINT, false));
+ sourceEntity.getEntity().subscribe(new MemberSubscription<C2KLocalObject>(this, ClusterStorage.OUTCOME, false));
+ clearView();
+ schemas.addItem("--");
+ currentSchema = null;
+ schemaList = new ArrayList<String>();
+ try {
+ String outcomeTypes = sourceEntity.getEntity().queryData(ClusterStorage.VIEWPOINT+"/all");
+ StringTokenizer tok = new StringTokenizer(outcomeTypes, ",");
+ while (tok.hasMoreTokens()) {
+ String thisType = tok.nextToken();
+ schemas.addItem(thisType);
+ schemaList.add(thisType);
+ }
+ } catch (Exception e) {
+ Logger.msg(2, "No viewpoints found");
+ }
+ }
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+
+ Object selectedItem = e.getItem();
+ if (e.getStateChange() == ItemEvent.DESELECTED) return;
+ if (suspendSelection) return;
+ if (e.getItem().equals("--")) return;
+
+ if (e.getItemSelectable() == schemas)
+ switchSchema((String)selectedItem);
+ else if (e.getItemSelectable() == views)
+ switchView((Viewpoint)selectedItem);
+ else if (e.getItemSelectable() == events)
+ showEvent((EventItem)selectedItem);
+ }
+
+ public void switchSchema(String schemaName) {
+ clearView();
+ suspendSelection = true;
+ views.removeAllItems();
+ events.removeAllItems();
+ viewpointList = new ArrayList<Viewpoint>();
+ eventList = new ArrayList<EventItem>();
+
+ currentSchema = schemaName;
+
+ try {
+ // populate views
+ String viewNames = sourceEntity.getEntity().queryData(ClusterStorage.VIEWPOINT+"/"+schemaName+"/all");
+ StringTokenizer tok = new StringTokenizer(viewNames, ",");
+ Viewpoint lastView = null;
+ while(tok.hasMoreTokens()) {
+ String viewName = tok.nextToken();
+ Viewpoint thisView = (Viewpoint)sourceEntity.getEntity().getObject(ClusterStorage.VIEWPOINT+"/"+schemaName+"/"+viewName);
+ views.addItem(thisView);
+ if (lastView == null) lastView = thisView;
+ if (thisView.getName().equals("last")) //select
+ lastView = thisView;
+ viewpointList.add(thisView);
+ }
+
+ String ocVersions = sourceEntity.getEntity().queryData(ClusterStorage.OUTCOME+"/"+schemaName+"/all");
+ tok = new StringTokenizer(ocVersions, ",");
+ while(tok.hasMoreTokens()) {
+ int schemaVersion = Integer.parseInt(tok.nextToken());
+ String ocEvents = sourceEntity.getEntity().queryData(ClusterStorage.OUTCOME+"/"+schemaName+"/"+schemaVersion+"/all");
+ StringTokenizer tok2 = new StringTokenizer(ocEvents, ",");
+ while(tok2.hasMoreTokens()) {
+ int eventId = Integer.parseInt(tok2.nextToken());
+ EventItem newEvent = new EventItem(eventId, schemaVersion);
+ for (Viewpoint thisView : viewpointList) {
+ if (thisView.getEventId() == eventId)
+ newEvent.addView(thisView.getName());
+ }
+ eventList.add(newEvent);
+ }
+ Collections.sort(eventList, new Comparator<EventItem>() {
+ @Override
+ public int compare(EventItem o1, EventItem o2) {
+ return o1.compareTo(o2);
+ }
+ });
+ for (EventItem eventItem : eventList)
+ events.addItem(eventItem);
+ }
+
+ if (lastView != null) {
+ suspendSelection = false;
+ views.setSelectedItem(lastView);
+ switchView(lastView);
+ }
+
+ } catch (Exception e) {
+ Logger.error(e);
+ JOptionPane.showMessageDialog(this,
+ "The data structures of this item are incorrect.\nPlease contact your administrator.",
+ "Viewpoint Error" , JOptionPane.ERROR_MESSAGE);
+ }
+ suspendSelection = false;
+ }
+
+ public void switchView(Viewpoint newView) {
+ for (EventItem thisEvent : eventList) {
+ if (thisEvent.eventId == newView.getEventId()) {
+ suspendSelection = true;
+ events.setSelectedItem(thisEvent);
+ showEvent(thisEvent);
+ suspendSelection = false;
+ break;
+ }
+ }
+ }
+
+ public void showEvent(EventItem thisEvent) {
+ eventDetails.setText(thisEvent.getEventDesc());
+ try {
+ setView((Outcome)sourceEntity.getEntity().getObject(
+ ClusterStorage.OUTCOME+"/"+currentSchema+"/"+thisEvent.schemaVersion+"/"+thisEvent.eventId));
+ } catch (Exception ex) {
+ Logger.error(ex);
+ JOptionPane.showMessageDialog(this,
+ "Could not retrieve requested outcome.\nPlease contact your administrator.",
+ "Viewpoint Error" , JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ public void setView(Outcome data) {
+ Logger.msg(6, "ViewpointPane: got outcome type: "+data.getSchemaType()+" version: "+data.getSchemaVersion());
+ String schema;
+ currentOutcome = data;
+ dataView.removeAll();
+ String error = null;
+ try {
+ schema = LocalObjectLoader.getSchema(data.getSchemaType(), data.getSchemaVersion()).schema;
+ thisOutcome = EntityTabPane.getOutcomeHandler(data.getSchemaType(), data.getSchemaVersion());
+ thisOutcome.setDescription(schema);
+ thisOutcome.setOutcome(data.getData());
+ thisOutcome.setReadOnly(true);
+ Thread builder = new Thread(thisOutcome);
+ builder.start();
+ dataView.add(thisOutcome.getPanel());
+ exportButton.setEnabled(true);
+ if (viewButton!=null) viewButton.setEnabled(true);
+ return;
+ } catch (ObjectNotFoundException ex) {
+ error = "Schema not found";
+ } catch (OutcomeException ex) {
+ error = "Outcome was not valid. See log for details: "+ex.getMessage();
+ Logger.error(ex);
+ }
+
+ dataView.add(new JLabel(error));
+ }
+
+ public void clearView() {
+ dataView.removeAll();
+ exportButton.setEnabled(false);
+ if (viewButton!=null) viewButton.setEnabled(false);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("export") && currentOutcome != null)
+ saveOutcomeToFile();
+ if (e.getActionCommand().equals("setview") && currentOutcome != null)
+ overrideView();
+ }
+
+ private void saveOutcomeToFile() {
+
+ MainFrame.xmlChooser.setSelectedFile(new File(currentOutcome.getSchemaType()+".xml"));
+ int returnVal = MainFrame.xmlChooser.showSaveDialog(this);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ File targetFile = MainFrame.xmlChooser.getSelectedFile();
+ if (!(targetFile.getAbsolutePath().endsWith(".xml")))
+ targetFile = new File(targetFile.getAbsolutePath()+".xml");
+
+ Logger.msg(2, "ViewpointPane.actionPerformed() - Exporting outcome to file " + targetFile.getName());
+ try {
+ thisOutcome.export(targetFile);
+ }
+ catch (Exception ex) {
+ Logger.error(ex);
+ Logger.exceptionDialog(ex);
+ }
+ }
+
+ }
+
+ private void overrideView() {
+
+ Viewpoint oldView = (Viewpoint)views.getSelectedItem();
+ EventItem newEvent = (EventItem)events.getSelectedItem();
+
+ if (oldView.getEventId() == newEvent.eventId) {
+ JOptionPane.showMessageDialog(this,
+ "View '"+oldView.getName()+"' is already set to event "+newEvent.eventId,
+ "Viewpoint Already Set" , JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ if (JOptionPane.showConfirmDialog(this,
+ "Are you sure you want to set the '"+oldView.getName()+
+ "' view to event " + newEvent.eventId+ "?",
+ "Overwrite view",
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+ return;
+
+ oldView.setEventId(newEvent.eventId);
+ try {
+ String[] predefParams = new String[1];
+ predefParams[0] = CastorXMLUtility.marshall(oldView);
+ MainFrame.userAgent.execute((ItemProxy)sourceEntity.getEntity(), "AddC2KObject", predefParams);
+ } catch (Exception e) {
+ Logger.error(e);
+ Logger.exceptionDialog(e);
+ }
+ }
+
+ @Override
+ public void add(C2KLocalObject contents) {
+ if (contents instanceof Viewpoint)
+ addViewpoint((Viewpoint)contents);
+ else if (contents instanceof Outcome)
+ addOutcome((Outcome)contents);
+
+ }
+
+ public void addViewpoint(Viewpoint newView) {
+ String schemaName = newView.getSchemaName();
+ Logger.msg(3, "Viewpoint "+newView.getName()+" now points to "+newView.getEventId());
+ if (!(schemaList.contains(schemaName))) {
+ schemaList.add(schemaName);
+ schemas.addItem(schemaName);
+ return;
+ }
+
+
+ if (!(schemaName.equals(schemas.getSelectedItem())))
+ return;
+
+ for (EventItem thisEvent : eventList) {
+ if (thisEvent.eventId == newView.getEventId())
+ thisEvent.addView(newView.getName());
+ else
+ thisEvent.removeView(newView.getName());
+ }
+
+ boolean isSelected = false;
+ for (Viewpoint thisView : viewpointList) {
+ if (thisView.getName().equals(newView.getName())) {
+ isSelected = thisView.equals(views.getSelectedItem());
+ views.removeItem(thisView);
+ viewpointList.remove(thisView);
+ break;
+ }
+ }
+
+ views.addItem(newView);
+ viewpointList.add(newView);
+ if (isSelected) {
+ views.setSelectedItem(newView);
+ }
+
+ }
+
+ public void addOutcome(Outcome contents) {
+ if (!(contents.getSchemaType().equals(currentSchema))) // not interested
+ return;
+ Logger.msg(3, "Adding event "+contents.getID());
+ EventItem newEvent = new EventItem(contents.getID(), contents.getSchemaVersion());
+ eventList.add(newEvent);
+ events.addItem(newEvent);
+ }
+
+ @Override
+ public void remove(String id) {
+ // we don't really remove viewpoints
+ }
+
+ class EventItem implements Comparable<EventItem> {
+ public int eventId;
+ public int schemaVersion;
+ public ArrayList<String> viewNames = new ArrayList<String>();
+ public String viewList = "";
+
+ public EventItem(int eventId, int schemaVersion) {
+ this.eventId = eventId;
+ this.schemaVersion = schemaVersion;
+ }
+
+ public void addView(String viewName) {
+ if (!(viewNames.contains(viewName))) {
+ viewNames.add(viewName);
+ buildViewLabel();
+ }
+ }
+
+ public void removeView(String viewName) {
+ viewNames.remove(viewName);
+ buildViewLabel();
+ }
+
+ private void buildViewLabel() {
+ if (viewNames.size() == 0) {
+ viewList = "";
+ return;
+ }
+
+ StringBuffer newLabel = new StringBuffer(" (");
+ for (Iterator<String> iter = viewNames.iterator(); iter.hasNext();) {
+ String viewName = iter.next();
+ newLabel.append(viewName);
+ if (iter.hasNext())
+ newLabel.append(", ");
+ }
+
+ viewList = newLabel.append(")").toString();
+ }
+
+ @Override
+ public String toString() {
+ return eventId+viewList;
+
+ }
+
+ public String getEventDesc() {
+ try {
+ Event myEvent = (Event)sourceEntity.getEntity().getObject(ClusterStorage.HISTORY+"/"+eventId);
+ return (Language.translate("Recorded on")+" "+myEvent.getTimeString()+" "+
+ Language.translate("by")+" "+myEvent.getAgentName()+" "+
+ Language.translate("using schema v")+schemaVersion);
+ } catch (Exception ex) {
+ Logger.error(ex);
+ return ("Error retrieving event details");
+ }
+ }
+
+ @Override
+ public int compareTo(EventItem other) {
+ if (other.eventId < eventId) return 1;
+ if (other.eventId > eventId) return -1;
+ return 0;
+ }
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java b/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java
new file mode 100644
index 0000000..1ae4d43
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java
@@ -0,0 +1,286 @@
+package com.c2kernel.gui.tabs;
+import java.awt.Cursor;
+import java.awt.GridBagConstraints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JSplitPane;
+
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.graph.layout.DefaultGraphLayoutGenerator;
+import com.c2kernel.graph.model.EdgeFactory;
+import com.c2kernel.graph.model.Selection;
+import com.c2kernel.graph.model.VertexFactory;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.graph.view.EditorPanel;
+import com.c2kernel.gui.graph.view.VertexPropertyPanel;
+import com.c2kernel.gui.lifecycle.instance.TransitionPanel;
+import com.c2kernel.gui.lifecycle.instance.WfDirectedEdgeRenderer;
+import com.c2kernel.gui.lifecycle.instance.WfGraphPanel;
+import com.c2kernel.gui.lifecycle.instance.WfVertexRenderer;
+import com.c2kernel.lifecycle.instance.CompositeActivity;
+import com.c2kernel.lifecycle.instance.Workflow;
+import com.c2kernel.lifecycle.instance.gui.model.WfEdgeFactory;
+import com.c2kernel.lifecycle.instance.gui.model.WfVertexFactory;
+import com.c2kernel.lifecycle.instance.gui.model.WfVertexOutlineCreator;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.CastorXMLUtility;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+public class WorkflowPane extends EntityTabPane implements EntityProxyObserver<Workflow>
+{
+ // Only for the purpose of loading and saving
+ protected Workflow mWorkflow = null;
+ boolean init = false;
+ TransitionPanel transPanel;
+ protected JButton mLoadButton = new JButton(Resource.findImage("graph/load.png"));
+ protected JButton mSaveButton = new JButton(Resource.findImage("graph/save.png"));
+ protected JButton mLayoutButton = new JButton(Resource.findImage("graph/autolayout.png"));
+ protected JButton mZoomOutButton = new JButton(Resource.findImage("graph/zoomout.png"));
+ protected JButton[] mOtherToolBarButtons;
+ // Workflow factories
+ protected EdgeFactory mWfEdgeFactory;
+ protected VertexFactory mWfVertexFactory;
+ // Graph editor panel
+ protected EditorPanel mEditorPanel;
+ // Objects to view/modify the properties of the selected activity
+ protected VertexPropertyPanel mPropertyPanel;
+ protected JSplitPane mSplitPane;
+
+ // Graph editor panel
+ // Objects to view/modify the properties of the selected activity
+ public WorkflowPane()
+ {
+ super("Workflow", "Workflow Viewer");
+ // Workflow factories
+ mWfEdgeFactory = new WfEdgeFactory();
+ mWfVertexFactory = new WfVertexFactory();
+ mZoomOutButton.setToolTipText(Language.translate("Zoom Out"));
+ mLayoutButton.setToolTipText(Language.translate("Auto Layout"));
+ mLoadButton.setToolTipText(Language.translate("Load"));
+ mSaveButton.setToolTipText(Language.translate("Save"));
+ mOtherToolBarButtons = new JButton[] { mZoomOutButton, mLayoutButton, mLoadButton, mSaveButton };
+
+ }
+
+ protected void createListeners()
+ {
+ /**
+ *
+ */
+ mLoadButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ loadWorkflow();
+ }
+ });
+ /**
+ *
+ */
+ mSaveButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ saveWorkflow();
+ setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ }
+ });
+ /**
+ *
+ */
+ mLayoutButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ DefaultGraphLayoutGenerator.layoutGraph(mEditorPanel.mGraphModelManager.getModel());
+ }
+ });
+ /**
+ *
+ */
+ mZoomOutButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ mEditorPanel.mGraphModelManager.zoomOut();
+ }
+ });
+ }
+ /**
+ * Return a single ref on mEditorPanel
+ *
+ * @return EditorPanel
+ */
+ public EditorPanel getEditorPanel()
+ {
+ if (mEditorPanel == null)
+ mEditorPanel =
+ new EditorPanel(
+ mWfEdgeFactory,
+ mWfVertexFactory,
+ new WfVertexOutlineCreator(),
+ true,
+ mOtherToolBarButtons,
+ new WfGraphPanel(new WfDirectedEdgeRenderer(), new WfVertexRenderer()));
+ return mEditorPanel;
+ }
+ public JSplitPane getJSplitPane()
+ {
+ if (mSplitPane == null)
+ {
+ mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, getEditorPanel(), getPropertyPanel());
+ mSplitPane.setDividerSize(5);
+ mSplitPane.setDividerLocation(800);
+ }
+ return mSplitPane;
+ }
+ @Override
+ public void add(Workflow contents)
+ {
+ mWorkflow = contents;
+ addActivity((CompositeActivity) mWorkflow.search("workflow/domain"));
+ }
+ @Override
+ public void remove(String id)
+ {
+ }
+ protected void addActivity(CompositeActivity cAct)
+ {
+ // Resolve any undefined references in the workflow
+ mEditorPanel.mGraphModelManager.replace(cAct.getChildrenGraphModel());
+ // Give the editor panel the edge and vertex types
+ mEditorPanel.updateVertexTypes(cAct.getWf().getVertexTypeNameAndConstructionInfo());
+ mEditorPanel.updateEdgeTypes(cAct.getWf().getEdgeTypeNameAndConstructionInfo());
+ mEditorPanel.enterSelectMode();
+ mWfVertexFactory.setCreationContext(cAct);
+ }
+ @Override
+ public void run()
+ {
+ Thread.currentThread().setName("Workflow Pane Builder");
+ if (!init)
+ {
+ getEditorPanel();
+ createLayout();
+ createListeners();
+ mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager);
+ mEditorPanel.setEditable(MainFrame.isAdmin);
+ init = true;
+ }
+ sourceEntity.getEntity().subscribe(new MemberSubscription<Workflow>(this, ClusterStorage.LIFECYCLE, true));
+ transPanel.setItem((ItemProxy) sourceEntity.getEntity());
+ }
+ @Override
+ public void reload()
+ {
+ Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.LIFECYCLE);
+ initForEntity(sourceEntity);
+ }
+ protected void createLayout()
+ {
+ initPanel();
+ // Add the editor pane
+ getGridBagConstraints().gridx = 0;
+ getGridBagConstraints().gridy = 1;
+ getGridBagConstraints().fill = GridBagConstraints.BOTH;
+ getGridBagConstraints().weighty = 2.0;
+ gridbag.setConstraints(getJSplitPane(), getGridBagConstraints());
+ add(getJSplitPane());
+ validate();
+ }
+ protected void loadWorkflow()
+ {
+ File selectedFile = null;
+ int returnValue = MainFrame.xmlChooser.showOpenDialog(null);
+ switch (returnValue)
+ {
+ case JFileChooser.APPROVE_OPTION :
+ selectedFile = MainFrame.xmlChooser.getSelectedFile();
+ try
+ {
+ String newWf = FileStringUtility.file2String(selectedFile);
+ add((Workflow) CastorXMLUtility.unmarshall(newWf));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ case JFileChooser.CANCEL_OPTION :
+ case JFileChooser.ERROR_OPTION :
+ default :
+ }
+ }
+ protected String marshall() throws Exception
+ {
+ return com.c2kernel.utils.CastorXMLUtility.marshall(mWorkflow.getWf());
+ }
+ protected void saveWorkflow()
+ {
+ try
+ {
+ CompositeActivity cact = (CompositeActivity)mWorkflow.getWf().search("workflow/domain");
+ MainFrame.userAgent.execute(
+ (ItemProxy)sourceEntity.getEntity(),
+ "ReplaceDomainWorkflow",
+ new String[] { com.c2kernel.utils.CastorXMLUtility.marshall(cact)});
+ cact.getChildrenGraphModel().setSelection(new Selection(null,null,0,0,0,0));
+ }
+ catch (Exception e)
+ {
+ Logger.error(e);
+ }
+ }
+
+ public VertexPropertyPanel getPropertyPanel()
+ {
+ if (mPropertyPanel == null) {
+ setNewPropertyPanel();
+ transPanel = new TransitionPanel();
+ mPropertyPanel.createLayout(transPanel);
+ mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager);
+ mPropertyPanel.setEditable(MainFrame.isAdmin);
+ }
+ return mPropertyPanel;
+ }
+
+ public void setNewPropertyPanel()
+ {
+ String wfPanelClass = Gateway.getProperty("WfPropertyPanel");
+ if (wfPanelClass != null)
+ {
+ try
+ {
+ Class<?> panelClass = Class.forName(wfPanelClass);
+ mPropertyPanel = (VertexPropertyPanel) panelClass.newInstance();
+ return;
+ }
+ catch (Exception ex)
+ {
+ Logger.error("Could not load wf props panel:" + wfPanelClass);
+ Logger.error(ex);
+ }
+ }
+ mPropertyPanel = new VertexPropertyPanel();
+ }
+
+ @Override
+ public void control(String control, String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java b/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java
new file mode 100644
index 0000000..bd5e7d0
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java
@@ -0,0 +1,90 @@
+package com.c2kernel.gui.tabs.collection;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JSplitPane;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.collection.AggregationMember;
+import com.c2kernel.collection.Collection;
+import com.c2kernel.collection.gui.model.AggregationVertexFactory;
+import com.c2kernel.collection.gui.model.AggregationVertexOutlineCreator;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.collection.AggregationMemberRenderer;
+import com.c2kernel.gui.collection.PropertyPanel;
+import com.c2kernel.gui.collection.SelectedMemberPanel;
+import com.c2kernel.gui.graph.view.EditorPanel;
+import com.c2kernel.gui.graph.view.GraphPanel;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Resource;
+/**
+ * @version $Revision: 1.5 $ $Date: 2006/09/15 15:02:24 $
+ * @author $Author: abranson $
+ */
+public class AggregationView extends CollectionView<AggregationMember>
+{
+ protected JButton mSaveButton = new JButton(Resource.findImage("graph/save.png"));
+ protected JButton mHistoryButton = new JButton(Resource.findImage("graph/history.png"));
+ protected JButton[] mOtherToolBarButtons = { mSaveButton, mHistoryButton };
+ // Graph editor panel
+ protected EditorPanel mEditorPanel;
+ // Objects to view/modify the properties of the selected activity
+ protected PropertyPanel mPropertyPanel;
+ protected JSplitPane mSplitPane;
+ private final AggregationVertexFactory mAggregationVertexFactory = new AggregationVertexFactory();
+ private final AggregationMemberRenderer mAggregationMemberRenderer = new AggregationMemberRenderer();
+ public AggregationView()
+ {
+ super();
+ setLayout(new GridLayout(1,1));
+ mPropertyPanel = new PropertyPanel();
+ mEditorPanel = new EditorPanel(null, mAggregationVertexFactory, new AggregationVertexOutlineCreator(), false, mOtherToolBarButtons, new GraphPanel(null, mAggregationMemberRenderer));
+ createLayout();
+ createListeners();
+ mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager);
+ mPropertyPanel.createLayout(new SelectedMemberPanel());
+ mEditorPanel.setEditable(MainFrame.isAdmin);
+ }
+
+ @Override
+ public void setCollection(Collection<AggregationMember> contents)
+ {
+ thisColl = contents;
+ Aggregation agg = (Aggregation)thisColl;
+ mPropertyPanel.setCollection(agg);
+ mAggregationMemberRenderer.setAggregation(agg);
+ mEditorPanel.mGraphModelManager.setModel(agg.getLayout());
+ mEditorPanel.updateVertexTypes(agg.getVertexTypeNameAndConstructionInfo());
+ mEditorPanel.enterSelectMode();
+ mAggregationVertexFactory.setCreationContext(agg);
+ }
+ public void createLayout()
+ {
+ mSaveButton.setToolTipText(Language.translate("Save Layout Changes"));
+ mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mEditorPanel, mPropertyPanel);
+ mSplitPane.setDividerSize(5);
+ add(mSplitPane);
+ }
+
+ protected void createListeners()
+ {
+ mSaveButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ saveCollection();
+ }
+ });
+ mHistoryButton.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ new CollectionHistoryWindow(item, (Aggregation)thisColl);
+ }
+ });
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java
new file mode 100644
index 0000000..673f3ac
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java
@@ -0,0 +1,192 @@
+package com.c2kernel.gui.tabs.collection;
+
+import java.awt.HeadlessException;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+import com.c2kernel.collection.Aggregation;
+import com.c2kernel.collection.Collection;
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.proxy.EntityProxy;
+import com.c2kernel.entity.proxy.EntityProxyObserver;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.entity.proxy.MemberSubscription;
+import com.c2kernel.events.Event;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.lifecycle.instance.predefined.PredefinedStep;
+import com.c2kernel.lookup.EntityPath;
+import com.c2kernel.lookup.InvalidEntityPathException;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.persistency.outcome.Outcome;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.CastorXMLUtility;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+public class CollectionHistoryWindow extends JFrame {
+
+ JTable historyTable;
+ HistoryTableModel historyModel;
+
+ public CollectionHistoryWindow(ItemProxy item, Aggregation coll) throws HeadlessException {
+ super("Collection History");
+ historyModel = new HistoryTableModel(item, coll);
+ historyTable = new JTable(historyModel);
+ this.getContentPane().add(new JScrollPane(historyTable));
+ historyTable.addMouseListener(new HistoryTableListener(item));
+ this.pack();
+ super.toFront();
+ this.validate();
+ this.setVisible(true);
+ }
+
+ private class HistoryTableModel extends AbstractTableModel implements EntityProxyObserver<Event> {
+
+ ItemProxy item;
+ ArrayList<Event> collEvents;
+ ArrayList<Object> collEventData;
+ Aggregation coll;
+ public HistoryTableModel(ItemProxy item, Aggregation coll) {
+ this.item = item;
+ this.coll = coll;
+ collEvents = new ArrayList<Event>();
+ collEventData = new ArrayList<Object>();
+ item.subscribe(new MemberSubscription<Event>(this, ClusterStorage.HISTORY, true));
+ }
+ @Override
+ public int getColumnCount() {
+ return 4;
+ }
+
+ @Override
+ public String getColumnName(int columnIndex) {
+ switch(columnIndex) {
+ case 0: return Language.translate("Date");
+ case 1: return Language.translate("Operation");
+ case 2: return Language.translate("Slot");
+ case 3: return Language.translate("Child");
+ default: return "";
+ }
+ }
+ @Override
+ public int getRowCount() {
+ return collEvents.size();
+ }
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ Event ev = collEvents.get(rowIndex);
+ switch (columnIndex) {
+ case 0:
+ return ev.getTimeString();
+ case 1:
+ if (ev.getStepName().equals("AssignItemToSlot"))
+ return "Item Assigned";
+ else
+ return "Collection replaced";
+ case 2:
+ if (ev.getStepName().equals("AssignItemToSlot"))
+ return ((String[])collEventData.get(rowIndex))[1];
+ return "";
+ case 3:
+ if (ev.getStepName().equals("AddC2KObject"))
+ return "Click to view";
+ String name;
+ try {
+ EntityProxy childItem = Gateway.getProxyManager().getProxy(new EntityPath(Integer.parseInt(((String[])collEventData.get(rowIndex))[2])));
+ name = childItem.getName();
+ } catch (NumberFormatException e) {
+ name = "Invalid entity key: "+((String[])collEventData.get(rowIndex))[2];
+ } catch (ObjectNotFoundException e) {
+ name = "Item deleted: "+((String[])collEventData.get(rowIndex))[2];
+ } catch (InvalidEntityPathException e) {
+ name = "Invalid entity key: "+((String[])collEventData.get(rowIndex))[2];
+ }
+ return name;
+ default:
+ return "";
+ }
+ }
+ public Object getEventData(int row) {
+ return collEventData.get(row);
+ }
+ @Override
+ public void add(Event thisEv) {
+ if (thisEv.getStepName().equals("AssignItemToSlot") || thisEv.getStepName().equals("AddC2KObject")) {
+ String[] params;
+ try {
+ Outcome oc = (Outcome)item.getObject(ClusterStorage.OUTCOME+"/PredefinedStepOutcome/0/"+thisEv.getID());
+ params = PredefinedStep.getDataList(oc.getData());
+ } catch (ObjectNotFoundException ex) { return; }
+ if (thisEv.getStepName().equals("AssignItemToSlot")) {
+ if (params[0].equals(coll.getName()))
+ collEventData.add(params);
+ else return;
+ }
+ else {
+ Object obj;
+ try {
+ obj = CastorXMLUtility.unmarshall(params[0]);
+ } catch (Exception e) {
+ Logger.error(e);
+ return;
+ }
+ if (obj instanceof Collection)
+ collEventData.add(obj);
+ else return;
+
+ }
+ }
+ else return;
+ collEvents.add(thisEv);
+ fireTableRowsInserted(collEvents.size()-1, collEvents.size()-1);
+ }
+ @Override
+ public void remove(String id) { }
+ @Override
+ public void control(String control, String msg) {
+ }
+ }
+
+ private class HistoryTableListener extends MouseAdapter {
+
+ ItemProxy item;
+ public HistoryTableListener(ItemProxy item) {
+ this.item = item;
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount()==2) {
+ int row = historyTable.getSelectedRow();
+ Object data = historyModel.getEventData(row);
+ if (data instanceof Aggregation) {
+ showColl((Aggregation)data);
+ }
+ else {
+ String[] params = (String[])data;
+ try {
+ EntityProxy childItem = Gateway.getProxyManager().getProxy(new EntityPath(Integer.parseInt(params[2])));
+ MainFrame.itemFinder.pushNewKey(childItem.getName());
+ } catch (Exception ex) { }
+ }
+ }
+ }
+ public void showColl(Aggregation coll) {
+ JFrame newFrame = new JFrame();
+ AggregationView newView = new AggregationView();
+ newView.setCollection(coll);
+ newView.setItem(item);
+ newFrame.getContentPane().add(newView);
+ newFrame.pack();
+ newFrame.toFront();
+ newFrame.validate();
+ newFrame.setVisible(true);
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java
new file mode 100644
index 0000000..c698430
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java
@@ -0,0 +1,49 @@
+package com.c2kernel.gui.tabs.collection;
+
+import javax.swing.JPanel;
+
+import com.c2kernel.collection.Collection;
+import com.c2kernel.collection.CollectionMember;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.1 $
+ * $Date: 2004/08/10 07:56:08 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+public abstract class CollectionView<M extends CollectionMember> extends JPanel {
+
+ protected Collection<M> thisColl;
+ protected ItemProxy item;
+
+ public CollectionView() {
+ super();
+ }
+
+ public void setItem(ItemProxy entity) {
+ this.item = entity;
+ }
+
+ public abstract void setCollection(Collection<M> coll);
+
+ protected void saveCollection()
+ {
+ try
+ {
+ String[] params = new String[1];
+ params[0] = com.c2kernel.utils.CastorXMLUtility.marshall(thisColl);
+ MainFrame.userAgent.execute(item, "AddC2KObject", params);
+ }
+ catch (Exception e)
+ {
+ Logger.error(e);
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java b/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java
new file mode 100644
index 0000000..e068bdc
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java
@@ -0,0 +1,34 @@
+package com.c2kernel.gui.tabs.collection;
+import java.awt.GridLayout;
+
+import javax.swing.JLabel;
+
+import com.c2kernel.collection.Collection;
+import com.c2kernel.collection.DependencyMember;
+/**
+ * @version $Revision: 1.2 $ $Date: 2005/06/02 12:17:22 $
+ * @author $Author: abranson $
+ */
+public class DependencyView extends CollectionView<DependencyMember>
+{
+ // Objects to view/modify the properties of the selected activity
+
+ public DependencyView()
+ {
+ super();
+ setLayout(new GridLayout(1,1));
+ createLayout();
+ }
+
+ @Override
+ public void setCollection(Collection<DependencyMember> contents)
+ {
+ thisColl = contents;
+ }
+ public void createLayout()
+ {
+ // TODO: design a nice dependency view, with property viewing and modification
+ add(new JLabel("Dependency view not yet implemented. Please browse the tree instead."));
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java
new file mode 100644
index 0000000..6a8f2f7
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java
@@ -0,0 +1,55 @@
+package com.c2kernel.gui.tabs.execution;
+import java.util.ArrayList;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.lifecycle.instance.stateMachine.States;
+
+public class ActivityItem {
+ public String stepPath;
+ public int state;
+ public String name;
+ ArrayList<Job> jobs = new ArrayList<Job>();
+
+ public ActivityItem() {
+ stepPath = "";
+ state = -1;
+ name = "--";
+ }
+
+ public ActivityItem(Job thisJob) {
+ stepPath = thisJob.getStepPath();
+ state = thisJob.getCurrentState();
+ name = thisJob.getStepName();
+ jobs.add(thisJob);
+ }
+
+ public void addJob(Job newJob) {
+ jobs.add(newJob);
+ }
+
+ public ArrayList<Job> getJobs() {
+ return jobs;
+ }
+
+ public String getStepPath() {
+ return stepPath;
+ }
+
+ @Override
+ public String toString() {
+ return name+(state>-1?" ("+States.getStateName(state)+")":"");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityItem)
+ return hashCode() == ((ActivityItem)other).hashCode();
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return stepPath.hashCode();
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java
new file mode 100644
index 0000000..707f311
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java
@@ -0,0 +1,296 @@
+package com.c2kernel.gui.tabs.execution;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.EntityTabPane;
+import com.c2kernel.gui.tabs.ExecutionPane;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.LocalObjectLoader;
+import com.c2kernel.utils.Logger;
+
+public class ActivityViewer extends JPanel implements Runnable {
+
+ ItemProxy item;
+ Box outcomeButtons = Box.createHorizontalBox();
+ OutcomeHandler outcomePanel;
+ JPanel outcomeView = new JPanel(new GridLayout(1,1));
+ ActivityItem thisAct;
+ ArrayList<RequestButton> requestButtons = new ArrayList<RequestButton>();
+ JLabel noOutcome = new JLabel(Language.translate("No outcome data is required for this activity"));
+ ExecutionPane parent;
+ JLabel status;
+ JComboBox executors;
+ JButton saveButton = new JButton("Save");
+ JButton loadButton = new JButton("Load");
+ GridBagLayout gridbag = new GridBagLayout();
+ Job executingJob = null;
+ static JFileChooser chooser = new JFileChooser();
+ static {
+ chooser.addChoosableFileFilter(
+ new javax.swing.filechooser.FileFilter() {
+ @Override
+ public String getDescription() {
+ return "XML Files";
+ }
+ @Override
+ public boolean accept(File f) {
+ if (f.isDirectory() || (f.isFile() && f.getName().endsWith(".xml"))) {
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ public ActivityViewer (ActivityItem newAct, ItemProxy item, ExecutionPane parent){
+ thisAct = newAct;
+ this.item = item;
+ this.parent = parent;
+ setLayout(gridbag);
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx=0; c.gridy=1; c.weightx=1.0; c.weighty=0.0;
+ c.insets = new Insets(5,5,5,5);
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+// activity title
+ JLabel actTitle = new JLabel(Language.translate("Activity")+": "+newAct.name);
+ actTitle.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(actTitle, c);
+ add(actTitle);
+
+ Job firstJob = (thisAct.getJobs().get(0));
+// desc
+ String desc = firstJob.getDescription();
+ if (desc != null && desc.length() > 0) {
+ Box descBox = Box.createHorizontalBox();
+
+ String chopDesc = null;
+ if(desc.length() >= 40) chopDesc = desc.substring(0,40);
+ else chopDesc = desc;
+
+ descBox.add(new JLabel("Description: "+chopDesc));
+ if (desc.length()>chopDesc.length()) {
+ descBox.add(new JLabel(" ..."));
+ descBox.add(Box.createHorizontalStrut(7));
+ JButton descButton = new JButton("View");
+ descButton.setMargin(new Insets(0,0,0,0));
+ descButton.setActionCommand(desc);
+ descButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JTextArea descArea = new JTextArea(e.getActionCommand());
+ descArea.setLineWrap(true);
+ descArea.setWrapStyleWord(true);
+ JScrollPane descScroll = new JScrollPane(descArea);
+ descScroll.setPreferredSize(new Dimension(400,150));
+ JOptionPane.showMessageDialog(null, descScroll, "Activity Description", JOptionPane.PLAIN_MESSAGE);
+ }
+ });
+ descBox.add(descButton);
+ }
+
+ c.gridy++;
+ gridbag.setConstraints(descBox, c);
+ add(descBox);
+ }
+
+
+// agentid
+ String roleName = firstJob.getAgentRole();
+ if (roleName!= null && roleName.length()>0) {
+ c.gridy++;
+ JLabel role = new JLabel(Language.translate("Agent Role")+": "+roleName);
+ gridbag.setConstraints(role, c);
+ add(role);
+ }
+
+ c.gridy++;
+ c.anchor = GridBagConstraints.EAST;
+ gridbag.setConstraints(outcomeButtons, c);
+ add(outcomeButtons);
+
+ executors = MainFrame.getExecutionPlugins();
+ if (executors.getItemCount() > 1) {
+ c.gridx++;
+ gridbag.setConstraints(executors, c);
+ add(executors);
+ c.gridx--;
+ }
+
+ c.gridy++;
+
+ status = new JLabel(Language.translate("Waiting for request"));
+ status.setFont(EntityTabPane.titleFont);
+ gridbag.setConstraints(status, c);
+ add(status);
+
+ c.gridx++;
+ Box fileBox = Box.createHorizontalBox();
+ fileBox.add(saveButton); fileBox.add(Box.createHorizontalGlue()); fileBox.add(loadButton);
+ gridbag.setConstraints(fileBox, c);
+ add(fileBox);
+ saveButton.setEnabled(false);
+ loadButton.setEnabled(false);
+ c.gridx--;
+ c.gridwidth = 2;
+ boolean outcomeEmpty = true;
+ for (Object name2 : thisAct.getJobs()) {
+ Job thisJob = (Job)name2;
+ RequestButton newButton = new RequestButton(thisJob, this);
+ requestButtons.add(newButton);
+ outcomeButtons.add(newButton);
+ outcomeButtons.add(Box.createHorizontalStrut(5));
+
+ if (thisJob.isOutcomeUsed()) {
+ String schema;
+ if (outcomeEmpty) {
+ try {
+ schema = LocalObjectLoader.getSchema(thisJob.getSchemaType(), thisJob.getSchemaVersion()).schema;
+ outcomePanel = EntityTabPane.getOutcomeHandler(thisJob.getSchemaType(), thisJob.getSchemaVersion());
+ outcomePanel.setReadOnly(false);
+ outcomePanel.setDescription(schema);
+ String outcomeString = thisJob.getOutcomeString();
+ if ( outcomeString!= null && outcomeString.length() > 0)
+ outcomePanel.setOutcome(outcomeString);
+ outcomeView = outcomePanel.getPanel();
+ } catch (ObjectNotFoundException ex) {
+ outcomeView.add(new JLabel(Language.translate("Schema not found:")+" "+thisJob.getSchemaType()+" v"+thisJob.getSchemaVersion()));
+ outcomePanel = null;
+ } catch (Exception ex) {
+ outcomeView.add(new JLabel(Language.translate("ERROR loading outcome editor: ")
+ +ex.getClass().getName()+" ("+ex.getMessage()+")"));
+ Logger.error(ex);
+ outcomePanel = null;
+ }
+ }
+ outcomeEmpty = false;
+ if (outcomePanel == null) newButton.setEnabled(false);
+ else {
+ saveButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String output;
+ try {
+ output = outcomePanel.getOutcome();
+ int returnVal = chooser.showSaveDialog(null);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ File targetFile = chooser.getSelectedFile();
+ if (!(targetFile.getAbsolutePath().endsWith(".xml")))
+ targetFile = new File(targetFile.getAbsolutePath()+".xml");
+
+ Logger.msg(2, "ExecutionPane - Exporting outcome to file " + targetFile.getName());
+ FileStringUtility.string2File(targetFile, output);
+ }
+ } catch (Exception ex) {
+ Logger.error(ex);
+ Logger.exceptionDialog(ex);
+ }
+ }
+ });
+ saveButton.setEnabled(true);
+
+ loadButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ int returnVal = chooser.showOpenDialog(null);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ File targetFile = chooser.getSelectedFile();
+
+ Logger.msg(2, "ViewpointPane.actionPerformed() - Reading outcome from file " + targetFile.getName());
+ String outcome = FileStringUtility.file2String(targetFile);
+ outcomePanel.setOutcome(outcome);
+ new Thread(outcomePanel).start();
+ }
+ } catch (Exception ex) {
+ Logger.error(ex);
+ Logger.exceptionDialog(ex);
+ }
+ }
+ });
+ loadButton.setEnabled(true);
+ }
+ }
+ }
+ if (outcomeEmpty)
+ outcomeView.add(noOutcome);
+ c.gridy++; c.weighty=1.0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.BOTH;
+ gridbag.setConstraints(outcomeView, c);
+ add(outcomeView);
+
+ }
+
+ public void init() {
+ if (outcomePanel != null)
+ new Thread(outcomePanel).start();
+ }
+
+ public void execute(Job thisJob) {
+ try{
+ if (thisJob.isOutcomeUsed() && thisJob.getSchemaType().length() > 0)
+ thisJob.setOutcome(outcomePanel.getOutcome());
+ executingJob = thisJob;
+ new Thread(this).start();
+ } catch (OutcomeException ex) {
+ Logger.exceptionDialog(ex);
+ }
+
+ }
+
+ /**
+ * Submits the job to the database
+ */
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Activity Execution");
+ enableAllButtons(false);
+ try {
+ Executor selectedExecutor = (Executor)executors.getSelectedItem();
+ selectedExecutor.execute(executingJob, status);
+ } catch (Exception e) {
+ Logger.error(e);
+ status.setText(Language.translate("Error during execution"));
+ Logger.exceptionDialog(e);
+ }
+ enableAllButtons(true);
+ }
+
+ private void enableAllButtons(boolean enabled) {
+
+ for (RequestButton thisButton : requestButtons) {
+ thisButton.setEnabled(enabled);
+ }
+ }
+
+ public ActivityItem getActivity() {
+ return thisAct;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java b/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java
new file mode 100644
index 0000000..378cc2e
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java
@@ -0,0 +1,35 @@
+package com.c2kernel.gui.tabs.execution;
+
+import javax.swing.JLabel;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.2 $
+ * $Date: 2003/11/04 14:31:30 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class DefaultExecutor implements Executor {
+
+ public DefaultExecutor() {
+ super();
+ }
+
+ @Override
+ public void execute(Job job, JLabel status) throws Exception {
+ status.setText(Language.translate("Requesting, please wait."));
+ MainFrame.userAgent.execute(job);
+ status.setText(Language.translate("Execution complete. Waiting for joblist update."));
+ }
+
+ @Override
+ public String toString() {
+ return "Normal";
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java b/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java
new file mode 100644
index 0000000..6fbde17
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java
@@ -0,0 +1,22 @@
+package com.c2kernel.gui.tabs.execution;
+
+import javax.swing.JLabel;
+
+import com.c2kernel.entity.agent.Job;
+
+/**************************************************************************
+ *
+ * $Revision: 1.1 $
+ * $Date: 2003/09/25 10:28:02 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public interface Executor {
+
+ @Override
+ public String toString();
+
+ public void execute(Job job, JLabel status) throws Exception;
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java b/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java
new file mode 100644
index 0000000..e1372a2
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java
@@ -0,0 +1,34 @@
+package com.c2kernel.gui.tabs.execution;
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.lifecycle.instance.stateMachine.Transitions;
+/**
+ * Each job gets a RequestButton
+ */
+
+ public class RequestButton extends JButton implements ActionListener {
+
+ Job myJob;
+ ActivityViewer parent;
+
+ public RequestButton(Job myJob, ActivityViewer parent) {
+ super();
+ this.myJob = myJob;
+ this.parent = parent;
+ String label = Transitions.getTransitionName(myJob.getPossibleTransition());
+ label = Character.toUpperCase(label.charAt(0))+label.substring(1);
+ if (myJob.isOutcomeUsed()) setBackground(Color.white);
+ super.setText(label);
+ addActionListener(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ parent.execute(myJob);
+ }
+ }
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java b/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java
new file mode 100644
index 0000000..5ab5245
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java
@@ -0,0 +1,112 @@
+package com.c2kernel.gui.tabs.outcome;
+
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.io.File;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.PlainDocument;
+
+import com.c2kernel.utils.FileStringUtility;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/09/07 13:46:31 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+
+
+public class BasicOutcomeEditor extends JPanel implements OutcomeHandler {
+
+ PlainDocument doc;
+ JTextArea textarea;
+ boolean unsaved;
+
+ public BasicOutcomeEditor() {
+ super();
+ this.setLayout(new GridLayout(1,1));
+ doc = new PlainDocument();
+ textarea = new JTextArea(doc);
+ textarea.setTabSize(2);
+ textarea.setFont(Font.decode("monospaced"));
+ add(new JScrollPane(textarea));
+ doc.addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) { unsaved = true; }
+ @Override
+ public void insertUpdate(DocumentEvent e) { unsaved = true; }
+ @Override
+ public void removeUpdate(DocumentEvent e) { unsaved = true; }
+
+ });
+ }
+
+ @Override
+ public void setOutcome(String outcome) throws InvalidOutcomeException {
+ try {
+ doc.insertString(0, outcome, null);
+ unsaved = false;
+ } catch (Exception ex) {
+ throw new InvalidOutcomeException(ex.getMessage());
+ }
+ }
+
+ @Override
+ public void setDescription(String description) throws InvalidSchemaException { }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ textarea.setEditable(!readOnly);
+ }
+
+
+ @Override
+ public JPanel getPanel() throws OutcomeNotInitialisedException {
+ return this;
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public String getOutcome() throws OutcomeException {
+ try {
+ return doc.getText(0, doc.getLength());
+ } catch (Exception ex) {
+ throw new OutcomeException(ex.getMessage());
+ }
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void run() {
+ }
+
+
+ @Override
+ public boolean isUnsaved() {
+ return unsaved;
+ }
+
+ @Override
+ public void saved() {
+ unsaved = false;
+ }
+
+ @Override
+ public void export(File targetFile) throws Exception {
+ FileStringUtility.string2File(targetFile, getOutcome());
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java
new file mode 100644
index 0000000..bab9050
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.tabs.outcome;
+
+public class InvalidOutcomeException extends OutcomeException {
+
+ public InvalidOutcomeException() {
+ super();
+ }
+ public InvalidOutcomeException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java
new file mode 100644
index 0000000..5edbcbf
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.tabs.outcome;
+
+public class InvalidSchemaException extends OutcomeException {
+
+ public InvalidSchemaException() {
+ super();
+ }
+ public InvalidSchemaException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java
new file mode 100644
index 0000000..fd608d0
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.tabs.outcome;
+
+public class OutcomeException extends Exception {
+
+ public OutcomeException() {
+ super();
+ }
+ public OutcomeException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java
new file mode 100644
index 0000000..0d6dc74
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java
@@ -0,0 +1,16 @@
+package com.c2kernel.gui.tabs.outcome;
+import java.io.File;
+
+import javax.swing.JPanel;
+
+public interface OutcomeHandler extends Runnable {
+
+ public void setOutcome(String outcome) throws InvalidOutcomeException;
+ public void setDescription(String description) throws InvalidSchemaException;
+ public void setReadOnly(boolean readOnly);
+ public JPanel getPanel() throws OutcomeNotInitialisedException;
+ public boolean isUnsaved();
+ public void saved();
+ public String getOutcome() throws OutcomeException;
+ public void export(File targetFile) throws Exception;
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java
new file mode 100644
index 0000000..7b54f33
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java
@@ -0,0 +1,11 @@
+package com.c2kernel.gui.tabs.outcome;
+
+public class OutcomeNotInitialisedException extends OutcomeException {
+
+ public OutcomeNotInitialisedException() {
+ super();
+ }
+ public OutcomeNotInitialisedException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java
new file mode 100644
index 0000000..7d15452
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java
@@ -0,0 +1,160 @@
+package com.c2kernel.gui.tabs.outcome.form;
+
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.exolab.castor.xml.schema.AttributeDecl;
+import org.exolab.castor.xml.schema.ComplexType;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+
+import com.c2kernel.gui.tabs.outcome.form.field.StringEditField;
+import com.c2kernel.utils.Logger;
+
+public class AttributeList extends JPanel {
+
+ ArrayList<StringEditField> attrSet = new ArrayList<StringEditField>();
+ ElementDecl model;
+ Element myElement;
+ boolean readOnly;
+ static Font labelFont;
+
+ public AttributeList(ElementDecl model, boolean readOnly, HelpPane helpPane) {
+ super();
+ AttributeDecl thisDecl;
+ this.model = model;
+ this.readOnly = readOnly;
+
+ // set up panel
+ GridBagLayout gridbag = new java.awt.GridBagLayout();
+ setLayout(gridbag);
+ if (labelFont == null)
+ labelFont = this.getFont().deriveFont((float)(this.getFont().getSize()-3.0));
+ // retrieve attributes
+ if (!model.getType().isComplexType()) {
+ // simple types have no attributes
+ return;
+ }
+
+ ComplexType content = (ComplexType)model.getType();
+
+ // place on panel
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0; c.weighty = 1.0; c.gridx = 0;
+ c.ipadx = 5; c.ipady = 0;
+
+ for (Enumeration<?> fields = content.getAttributeDecls(); fields.hasMoreElements();) {
+ c.gridy = 0;
+ thisDecl = (AttributeDecl)fields.nextElement();
+ Logger.msg(8, "Includes Attribute "+thisDecl.getName());
+
+ // Add Label
+ JLabel heading = new JLabel(thisDecl.getName());
+ heading.setFont(labelFont);
+ heading.setVerticalAlignment(SwingConstants.BOTTOM);
+ gridbag.setConstraints(heading, c);
+ this.add(heading);
+
+ // read help
+ String helpText;
+ String doc = OutcomeStructure.extractHelp(thisDecl);
+ if (doc.length() > 0)
+ helpText = doc.toString();
+ else
+ helpText = "<i>No help is available for this attribute</i>";
+
+
+ c.gridy++;
+
+ // Add entry
+ try {
+ StringEditField entry = StringEditField.getEditField(thisDecl);
+ entry.setHelp(helpPane, helpText);
+ attrSet.add(entry);
+ if (readOnly) entry.setEditable(false);
+ gridbag.setConstraints(entry.getControl(), c);
+ this.add(entry.getControl());
+ } catch (StructuralException e) {
+ JLabel entry = new JLabel("Error");
+ entry.setToolTipText(e.getMessage());
+ gridbag.setConstraints(entry, c);
+ this.add(entry);
+ }
+
+
+ c.gridx++;
+ }
+ }
+
+ public void setInstance(Element data) throws StructuralException {
+ this.myElement = data;
+ for (StringEditField thisField : attrSet) {
+ Logger.msg(8, "Populating Attribute "+thisField.getName());
+ Attr thisAttr = myElement.getAttributeNode(thisField.getName());
+ if (thisAttr == null)
+ thisAttr = newAttribute(myElement, (AttributeDecl)thisField.getModel());
+ thisField.setData(thisAttr);
+ }
+ }
+
+ public Attr newAttribute(Element parent, AttributeDecl attr) {
+
+ parent.setAttribute(attr.getName(), attr.getFixedValue()!=null?attr.getFixedValue():attr.getDefaultValue());
+ return parent.getAttributeNode(attr.getName());
+ }
+
+ public String validateAttributes() {
+ if (model.getType().isComplexType()) {
+ ComplexType content = (ComplexType)model.getType();
+ for (Enumeration<?> fields = content.getAttributeDecls(); fields.hasMoreElements();) {
+ AttributeDecl thisDecl = (AttributeDecl)fields.nextElement();
+ String attrVal = myElement.getAttribute(thisDecl.getName());
+ if (attrVal.length() == 0 && thisDecl.isOptional()) {
+ myElement.removeAttribute(thisDecl.getName());
+ }
+ }
+ }
+ return null;
+ }
+
+ public void initNew(Element parent) {
+ AttributeDecl thisDecl;
+ StringEditField thisField;
+ Attr thisAttr;
+ this.myElement = parent;
+
+ if (model.getType().isSimpleType()) return; // no attributes in simple types
+
+ ComplexType content = (ComplexType)model.getType();
+
+ for (Iterator<StringEditField> e = attrSet.iterator(); e.hasNext();) {
+ thisField = e.next();
+
+ thisDecl = content.getAttributeDecl(thisField.getName());
+ // HACK: if we don't resolve the reference, the type will be null
+ if (thisDecl.isReference()) thisDecl = thisDecl.getReference();
+ thisAttr = newAttribute(myElement, thisDecl);
+ // add into parent - fill in field
+ try {
+ thisField.setData(thisAttr);
+ } catch (Exception ex) { } // impossible name mismatch
+ }
+ }
+ @Override
+ public void grabFocus() {
+ if (attrSet.size() > 0)
+ attrSet.get(0).grabFocus();
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java
new file mode 100644
index 0000000..bb6d039
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java
@@ -0,0 +1,14 @@
+package com.c2kernel.gui.tabs.outcome.form;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+
+public class CardinalException extends OutcomeException {
+
+ public CardinalException() {
+ super();
+ }
+
+ public CardinalException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java
new file mode 100644
index 0000000..3bfe3fd
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java
@@ -0,0 +1,252 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JLabel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.exolab.castor.xml.schema.ComplexType;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.utils.Logger;
+
+public class DataRecord extends OutcomeStructure implements ChangeListener {
+
+ AttributeList myAttributes;
+ JTabbedPane DRPanel = null;
+ boolean deferred;
+ Document parentDoc;
+ GridBagConstraints position;
+ GridBagLayout gridbag;
+
+ public DataRecord(ElementDecl model, boolean readOnly, HelpPane help, boolean deferred) throws OutcomeException {
+ super(model, readOnly, help);
+ this.deferred = deferred;
+ if (!deferred) setupPanel();
+ }
+
+ public synchronized void activate() {
+ deferred = false;
+ try {
+ setupPanel();
+ if (myElement!=null) populateInstance();
+ } catch (OutcomeException ex) {
+ removeAll();
+ setLayout(new FlowLayout());
+ add(new JLabel("Error displaying outcome segment: "+ex.getMessage()));
+ }
+ validate();
+ }
+
+ private void setupPanel() throws OutcomeException {
+ // set up panel
+ gridbag = new java.awt.GridBagLayout();
+ setLayout(gridbag);
+ position = new GridBagConstraints();
+ position.anchor = GridBagConstraints.NORTHWEST;
+ position.fill = GridBagConstraints.NONE;
+ position.weightx = 1.0; position.weighty = 1.0;
+ position.gridx = 0; position.gridy = 0;
+ position.ipadx = 5; position.ipady = 5;
+ position.insets = new Insets(5,5,0,0);
+
+ // attributes at the top
+ myAttributes = new AttributeList(model, readOnly, helpPane);
+ position.gridwidth=3;
+ gridbag.setConstraints(myAttributes, position);
+ add(myAttributes);
+
+ ComplexType elementType;
+ try {
+ elementType = (ComplexType)model.getType();
+ }
+ catch (ClassCastException e) {
+ throw new StructuralException("DataRecord created with non-ComplexType");
+ }
+
+ //loop through all schema sub-elements
+ try {
+ enumerateElements(elementType);
+ } catch (OutcomeException e) {
+ throw new OutcomeException("Element "+model.getName()+" could not be created: "+e.getMessage());
+ }
+ }
+
+ @Override
+ public void addStructure(OutcomeStructure newElement) throws OutcomeException {
+ super.addStructure(newElement);
+ if (newElement == null) return;
+ if (newElement instanceof DataRecord) {
+ DataRecord newRecord = (DataRecord)newElement;
+ // set up enclosing tabbed pane for child drs
+ if (DRPanel == null) {
+ DRPanel = new JTabbedPane();
+ position.gridy++;
+ position.weightx=1.0;
+ position.fill=GridBagConstraints.HORIZONTAL;
+ position.gridwidth=3;
+ gridbag.setConstraints(DRPanel, position);
+ add(DRPanel);
+ // defer further tabs in this pane
+ deferChild = true;
+ }
+ DRPanel.addTab(newRecord.getName(), newRecord);
+ DRPanel.addChangeListener(newRecord);
+ }
+ else {
+ DRPanel = null;// have to make a new tabbed pane now
+ deferChild = false;
+ if (newElement instanceof Field) {
+ Field newField = (Field)newElement;
+ // make some nice columns
+ position.gridwidth=1;
+ position.gridy++;
+ position.gridx=0;
+ position.weightx=2;
+ position.weighty=0;
+ position.fill=GridBagConstraints.NONE;
+ gridbag.setConstraints(newField.getLabel(), position);
+ this.add(newField.getLabel());
+ position.gridy++;
+ position.weighty=1;
+ position.fill = GridBagConstraints.HORIZONTAL;
+ gridbag.setConstraints(newField.getCData(), position);
+ this.add(newField.getCData());
+ position.gridx++;
+ position.gridy--;
+ position.gridheight=2;
+ position.weightx=0;
+ position.fill=GridBagConstraints.NONE;
+ gridbag.setConstraints(newField.getAttributes(), position);
+ this.add(newField.getAttributes());
+ position.gridx=0;
+ position.gridheight=1;
+ position.gridy++;
+ }
+ else {
+ position.fill=GridBagConstraints.HORIZONTAL;
+ position.gridwidth=3;
+ position.weightx=1.0;
+ position.gridy++;
+ position.weighty=1.0;
+ gridbag.setConstraints(newElement, position);
+ add(newElement);
+ }
+ }
+ }
+
+ @Override
+ public void addInstance(Element myElement, Document parentDoc) throws OutcomeException {
+ Logger.msg(8, "Accepting DR "+myElement.getTagName());
+
+ if (this.myElement != null) throw new CardinalException("DataRecord "+this.getName()+" cannot repeat.");
+ this.myElement = myElement;
+ this.parentDoc = parentDoc;
+
+ if (!deferred)
+ populateInstance();
+ }
+
+ public void populateInstance() throws OutcomeException {
+ myAttributes.setInstance(myElement);
+
+ NodeList childElements = myElement.getChildNodes();
+
+ for (int i=0; i<childElements.getLength();i++) {
+ if (!(childElements.item(i) instanceof Element)) // ignore chardata here
+ continue;
+ Element thisElement = (Element) childElements.item(i);
+
+ // find the child structure with this name
+ OutcomeStructure thisStructure = subStructure.get(thisElement.getTagName());
+ if (thisStructure == null)
+ throw new StructuralException("DR "+model.getName()+" not expecting "+thisElement.getTagName());
+ thisStructure.addInstance(thisElement, parentDoc);
+ }
+
+ // make sure any dimensions have the minimum
+ for (Object name2 : subStructure.keySet()) {
+ String structureName = (String)name2;
+ OutcomeStructure thisStructure = subStructure.get(structureName);
+ int count = 0;
+
+ if (thisStructure instanceof Dimension) {
+ Dimension thisDimension = (Dimension)thisStructure;
+ thisDimension.setParentElement(myElement);
+ count = thisDimension.getChildCount();
+ }
+ else
+ count = thisStructure.getElement()==null?0:1;
+
+ int total = thisStructure.getModel().getMinOccurs();
+ //if (total == 0) total++;
+ for (int i = count;i<total;i++) {
+ myElement.appendChild(thisStructure.initNew(parentDoc));
+ }
+ }
+ }
+
+ @Override
+ public Element initNew(Document parent) {
+ Logger.msg(6, "Creating DR "+model.getName());
+ if (deferred) activate();
+
+ // make a new Element
+ myElement = parent.createElement(model.getName());
+ // populate
+ for (Object name2 : order) {
+ String structureName = (String)name2;
+ OutcomeStructure thisStructure = subStructure.get(structureName);
+ if (thisStructure instanceof Dimension)
+ ((Dimension)thisStructure).setParentElement(myElement);
+ int count = 0;
+ while (count < thisStructure.getModel().getMinOccurs()) {
+ myElement.appendChild(thisStructure.initNew(parent));
+ count++;
+ }
+ }
+
+ // set up attributes
+ myAttributes.initNew(myElement);
+
+ return myElement;
+
+ }
+
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ JTabbedPane targetPane = (JTabbedPane)e.getSource();
+ DataRecord targetTab = (DataRecord)targetPane.getSelectedComponent();
+ if (targetTab == this) {
+ helpPane.setHelp(getName(), getHelp());
+ if (deferred) SwingUtilities.invokeLater(
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ activate();
+ }
+ }
+ ));
+ }
+ }
+
+ /**
+ * sets focus to first editable child
+ */
+ @Override
+ public void grabFocus() {
+ if (myAttributes.attrSet.size() > 0)
+ myAttributes.grabFocus();
+ else if (order.size()> 0)
+ subStructure.get(order.get(0)).grabFocus();
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java
new file mode 100644
index 0000000..c91c5df
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java
@@ -0,0 +1,395 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.EtchedBorder;
+import javax.swing.table.JTableHeader;
+
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Particle;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.c2kernel.gui.DomainKeyConsumer;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.utils.Logger;
+
+public class Dimension extends OutcomeStructure implements ActionListener {
+
+ DimensionTableModel tableModel;
+ Element parent;
+ GridBagConstraints position;
+ GridBagLayout gridbag;
+ JTabbedPane tabs;
+ JLabel msg;
+ DomKeyPushTable table;
+ Box tableBox;
+ ArrayList<DimensionInstance> instances = new ArrayList<DimensionInstance>(); // stores DimensionInstances if tabs
+ ArrayList<Element> elements = new ArrayList<Element>(); // stores current children
+
+ JButton addButton;
+ JButton delButton;
+
+ short mode;
+ protected static final short TABLE = 1;
+ protected static final short TABS = 2;
+
+
+ public Dimension(ElementDecl model, boolean readOnly, HelpPane help) {
+ super(model, readOnly, help);
+ // set up panel
+ gridbag = new java.awt.GridBagLayout();
+ setLayout(gridbag);
+ position = new GridBagConstraints();
+ position.anchor = GridBagConstraints.NORTHWEST;
+ position.fill = GridBagConstraints.HORIZONTAL;
+ position.weightx = 1.0; position.weighty = 0.0;
+ position.gridx = 0; position.gridy = 0;
+ position.ipadx = 0; position.ipady = 0;
+ position.insets = new Insets(0,0,0,0);
+
+ // TODO: an element or attribute of the dimension can be flagged as an index, so it can be used as a title for a tab
+
+ // set up the border
+ setBorder(BorderFactory.createTitledBorder(
+ BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), model.getName()));
+
+ msg = new JLabel("No elements");
+ msg.setFont(new Font("SansSerif", Font.ITALIC, msg.getFont().getSize()));
+ gridbag.setConstraints(msg, position);
+ add(msg);
+ position.gridy++;
+
+ // decide whether a table or tabs
+ try {
+ tableModel = new DimensionTableModel(model, readOnly);
+ Logger.msg(8, "DIM "+model.getName()+" - Will be a table");
+ mode = TABLE;
+ tableBox = Box.createVerticalBox();
+ table = new DomKeyPushTable(tableModel, this);
+ new MultiLinePasteAdapter(table, this);
+ if (readOnly) table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+ table.setColumnSelectionAllowed(readOnly);
+ JTableHeader tableHeader = table.getTableHeader();
+ tableHeader.setReorderingAllowed(false);
+ tableBox.add(tableHeader);
+ tableBox.add(table);
+ gridbag.setConstraints(tableBox, position);
+ add(tableBox);
+ tableBox.setVisible(false);
+
+ } catch (StructuralException e) {
+ // use tabs
+ Logger.msg(8, "DIM "+model.getName()+" - Will be tabs: "+e.getMessage());
+ mode = TABS;
+ tabs = new JTabbedPane();
+ gridbag.setConstraints(tabs, position);
+ add(tabs);
+ tabs.setVisible(false);
+ }
+ if (!readOnly) {
+ JPanel rowAdjust = new JPanel(new FlowLayout());
+ addButton = new JButton("+");
+ addButton.setActionCommand("add");
+ addButton.addActionListener(this);
+ rowAdjust.add(addButton);
+
+ delButton = new JButton("-");
+ delButton.setActionCommand("del");
+ delButton.addActionListener(this);
+ delButton.setEnabled(false);
+ rowAdjust.add(delButton);
+
+
+ position.gridy++; position.weighty=0; position.weightx=0;
+ gridbag.setConstraints(rowAdjust, position);
+ this.add(rowAdjust);
+ }
+
+ }
+
+ public void setParentElement(Element parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public void addInstance(Element myElement, Document parentDoc) throws OutcomeException {
+ if (Logger.doLog(6))
+ Logger.msg(6, "DIM - adding instance "+ (elements.size()+1) +" for "+myElement.getTagName());
+ if (parent == null) setParentElement((Element)myElement.getParentNode());
+ // if table, pass to table model
+ if (mode == TABLE) {
+ tableModel.addInstance(myElement, -1);
+ elements.add(myElement);
+ }
+ else {
+ DimensionInstance target;
+ elements.add(myElement);
+ if (instances.size() < elements.size())
+ target = newInstance();
+ else
+ target = instances.get(elements.size()-1);
+ target.addInstance(myElement, parentDoc);
+ }
+ checkButtons();
+ }
+
+ public int getChildCount() {
+ return elements.size();
+ }
+
+ public DimensionInstance newInstance() {
+ DimensionInstance newInstance = null;
+ try {
+ newInstance = new DimensionInstance(model, readOnly, helpPane, deferChild);
+ instances.add(newInstance);
+ newInstance.setTabNumber(instances.size());
+ newInstance.setParent(this);
+ deferChild = true;
+ tabs.addTab(newInstance.getName(), newInstance);
+ tabs.addChangeListener(newInstance);
+ } catch (OutcomeException e) {
+ // shouldn't happen, we've already done it once
+ Logger.error(e);
+ }
+ return newInstance;
+ }
+
+ @Override
+ public String validateStructure() {
+ if (mode == TABLE)
+ return table.validateStructure();
+ else {
+ StringBuffer errors = new StringBuffer();
+ for (Iterator<DimensionInstance> iter = instances.iterator(); iter.hasNext();) {
+ OutcomeStructure element = iter.next();
+ errors.append(element.validateStructure());
+ }
+ return errors.toString();
+ }
+ }
+
+ public void checkButtons() {
+ // check if data visible
+ boolean dataVisible = elements.size() > 0;
+ if (mode == TABS) tabs.setVisible(dataVisible);
+ else tableBox.setVisible(dataVisible);
+ msg.setVisible(!dataVisible);
+
+ if (readOnly) return;
+
+ if (elements.size() <= model.getMinOccurs() || elements.size() == 0) {
+ delButton.setEnabled(false);
+ delButton.setToolTipText("Minimum row count of "+model.getMinOccurs()+" reached.");
+ } else {
+ delButton.setEnabled(true);
+ delButton.setToolTipText(null);
+ }
+
+ if (elements.size() < model.getMaxOccurs() || model.getMaxOccurs() == Particle.UNBOUNDED) {
+ addButton.setEnabled(true);
+ addButton.setToolTipText(null);
+ } else {
+ addButton.setEnabled(false);
+ addButton.setToolTipText("Maximum row count of "+model.getMaxOccurs()+" reached.");
+ }
+ }
+
+ @Override
+ public Element initNew(Document parent) {
+ Element newElement;
+
+ if (mode == TABLE) {
+ newElement = tableModel.initNew(parent, -1);
+ elements.add(newElement);
+ checkButtons();
+ return newElement;
+ }
+ else {
+ DimensionInstance newTab = null;
+ if (instances.size() < elements.size()+1)
+ newTab = newInstance();
+ else
+ newTab = instances.get(elements.size()-1);
+ newElement = newTab.initNew(parent);
+ elements.add(newElement);
+ checkButtons();
+ return newElement;
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int index;
+ if (mode == TABS) index = tabs.getSelectedIndex();
+ else {
+ index = table.getSelectedRow();
+ if (index == -1) index = tableModel.getRowCount();
+ }
+ try {
+ if (table == null || table.getCellEditor() == null || table.getCellEditor().stopCellEditing()) {
+ if (e.getActionCommand().equals("add"))
+ addRow(index);
+ else if (e.getActionCommand().equals("del"))
+ removeRow(index);
+ }
+ } catch (CardinalException ex) {
+ JOptionPane.showMessageDialog(null, ex.getMessage(), "Table error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ public void addRow(int index) throws CardinalException {
+ if (elements.size() == model.getMaxOccurs())
+ throw new CardinalException("Maximum size of table reached");
+
+ if (mode == TABLE) {
+ Element newRow = tableModel.initNew(parent.getOwnerDocument(), index);
+ elements.add(index, newRow);
+ try {
+ Element following = elements.get(index+1);
+ parent.insertBefore(newRow, following);
+ } catch (IndexOutOfBoundsException ex) {
+ parent.appendChild(newRow);
+ }
+ table.clearSelection();
+ table.setRowSelectionInterval(index, index);
+ }
+ else {
+ Element newTab = initNew(parent.getOwnerDocument());
+ parent.appendChild(newTab);
+ }
+ checkButtons();
+
+ }
+
+ public void removeRow(int index) throws CardinalException {
+ if (elements.size() <= model.getMinOccurs())
+ throw new CardinalException("Minimum size of table reached");
+ if (mode == TABLE) {
+ parent.removeChild(tableModel.removeRow(index));
+ int selectRow = index;
+ if (index >= tableModel.getRowCount()) selectRow--;
+ if (tableModel.getRowCount() > 0) {
+ table.clearSelection();
+ table.setRowSelectionInterval(selectRow, selectRow);
+ }
+ }
+ else {
+ Element elementToGo = elements.get(index);
+ parent.removeChild(elementToGo);
+ instances.remove(index);
+ tabs.remove(index);
+ for (int i = index; i<instances.size(); i++) {
+ DimensionInstance thisInstance = instances.get(i);
+ thisInstance.setTabNumber(i+1);
+ tabs.setTitleAt(i, thisInstance.getName());
+ }
+ }
+ elements.remove(index);
+ checkButtons();
+ }
+
+ private class DomKeyPushTable extends JTable implements DomainKeyConsumer, FocusListener {
+
+ Dimension dim;
+ public DomKeyPushTable(DimensionTableModel model, Dimension parent) {
+ super(model);
+ addFocusListener(this);
+ this.dim = parent;
+ }
+
+ @Override
+ public void push(DomainPath key) {
+ push(key.getName());
+ }
+
+ @Override
+ public void push(String name) {
+ int col = getSelectedColumn();
+ int row = getSelectedRow();
+ if (cellEditor != null)
+ cellEditor.stopCellEditing();
+ Logger.msg(8, "Pushing "+name+" to table at "+row+","+col);
+ if (col > -1 && row > -1) {
+ if (dataModel.getValueAt(row, col).toString().length()==0)
+ dataModel.setValueAt(name, row, col);
+ else {
+ if (row+1 == getRowCount()) {
+ try {
+ dim.addRow(row+1);
+ dataModel.setValueAt(name, row+1, col);
+ } catch (CardinalException ex) {
+ JOptionPane.showMessageDialog(null, ex.getMessage(), "Table error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ if (row+1 < getRowCount()) {
+ Logger.msg(8, "Shifting selection to row "+(row+1));
+ changeSelection(row+1, col, false, false);
+ }
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (!readOnly)
+ MainFrame.itemFinder.setConsumer(this, "Insert");
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ // release the itemFinder
+ if (!readOnly)
+ MainFrame.itemFinder.clearConsumer(this);
+ }
+
+ public String validateStructure() {
+ if (cellEditor != null)
+ cellEditor.stopCellEditing();
+ return null;
+ }
+
+ @Override
+ public void changeSelection( int rowIndex, int columnIndex, boolean toggle, boolean extend) {
+ super.changeSelection(rowIndex, columnIndex, toggle, extend);
+ DimensionTableModel dimModel = (DimensionTableModel)dataModel;
+ helpPane.setHelp(dimModel.getColumnName(columnIndex), dimModel.getHelp(columnIndex));
+ }
+
+ }
+
+ @Override
+ public void grabFocus() {
+ if (mode == TABLE) {
+ if (table.getSelectedRow() == -1 && table.getRowCount() > 0) {
+ table.changeSelection(0, 0, false, false);
+ table.editCellAt(0,0);
+ }
+ table.requestFocus();
+ }
+ else if (instances.size()> 0)
+ instances.get(0).grabFocus();
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java
new file mode 100644
index 0000000..649886b
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java
@@ -0,0 +1,33 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import org.exolab.castor.xml.schema.ElementDecl;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+
+public class DimensionInstance extends DataRecord {
+
+ //probably will be needed to synch edits later
+ Dimension parentDimension;
+ int tabNumber;
+ String tabName = null;
+
+ public DimensionInstance(ElementDecl model, boolean readOnly , HelpPane help, boolean deferred) throws OutcomeException {
+ super(model, readOnly, help, deferred);
+ }
+
+ public void setTabNumber(int tabNumber) {
+ this.tabNumber=tabNumber;
+ }
+
+ public void setParent(Dimension parent) {
+ this.parentDimension = parent;
+ }
+
+ @Override
+ public String getName() {
+ //TODO appinfo for picking out attributes or child elements for tab name
+ if (tabName == null)
+ return Integer.toString(tabNumber);
+ else
+ return tabName;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java
new file mode 100644
index 0000000..ac6a9f2
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java
@@ -0,0 +1,332 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+import javax.swing.table.AbstractTableModel;
+
+import org.exolab.castor.xml.schema.Annotated;
+import org.exolab.castor.xml.schema.AttributeDecl;
+import org.exolab.castor.xml.schema.ComplexType;
+import org.exolab.castor.xml.schema.ContentModelGroup;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Group;
+import org.exolab.castor.xml.schema.Order;
+import org.exolab.castor.xml.schema.Particle;
+import org.exolab.castor.xml.schema.SimpleType;
+import org.exolab.castor.xml.schema.SimpleTypesFactory;
+import org.exolab.castor.xml.schema.XMLType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+public class DimensionTableModel extends AbstractTableModel {
+
+ ElementDecl model;
+ ArrayList<String> columnHeadings = new ArrayList<String>();
+ ArrayList<Class<?>> columnClasses = new ArrayList<Class<?>>();
+ ArrayList<Annotated> columnDecls = new ArrayList<Annotated>();
+ ArrayList<Boolean> colReadOnly = new ArrayList<Boolean>();
+ ArrayList<String> colHelp = new ArrayList<String>();
+ ArrayList<Object[]> rows = new ArrayList<Object[]>();
+ ArrayList<Element> elements = new ArrayList<Element>();
+ boolean readOnly;
+
+ public DimensionTableModel(ElementDecl model, boolean readOnly) throws StructuralException {
+ XMLType modelContent = model.getType();
+ this.model = model;
+ this.readOnly = readOnly;
+ // use text node for simple types
+ if (modelContent.isSimpleType()) {
+ SimpleType elementType = (SimpleType)modelContent;
+ SimpleType baseType = elementType.getBuiltInBaseType();
+ addColumn(model.getName(), baseType, baseType.getTypeCode(), new Boolean(model.getFixedValue() != null));
+ }
+ else if (modelContent.isComplexType()) { // if complex type, process child elements
+ ComplexType elementType = (ComplexType)modelContent;
+
+ // find out if a CDATA type is used for this complex type
+ XMLType baseType = elementType.getBaseType();
+ while (!(baseType instanceof SimpleType) && baseType != null) {
+ baseType = baseType.getBaseType();
+ }
+ if (baseType != null) {
+ int typeCode = ((SimpleType)baseType).getTypeCode();
+ addColumn(model.getName(), baseType, typeCode, new Boolean(model.getFixedValue() != null));
+ }
+ // process attributes
+ for (Enumeration<?> e = elementType.getAttributeDecls(); e.hasMoreElements();) {
+ AttributeDecl thisAttr = (AttributeDecl)e.nextElement();
+ // HACK: if we don't resolve the reference, the type will be null
+ if (thisAttr.isReference()) thisAttr = thisAttr.getReference();
+ if (thisAttr.getSimpleType() == null)
+ throw new StructuralException("Attribute "+thisAttr.getName()+" in "+model.getName()+" has no type");
+ addColumn(thisAttr.getName(), thisAttr, thisAttr.getSimpleType().getTypeCode(), new Boolean(thisAttr.isFixed()));
+ }
+
+ // enumerate child elements
+ enumerateElements(elementType);
+ }
+ }
+
+ public synchronized void addColumn(String heading, Annotated decl, int typeCode, Boolean readOnly) {
+ Logger.msg(8, "Column "+heading+" contains "+decl.getClass().getName()+" readOnly="+readOnly.toString());
+ columnHeadings.add(heading);
+ columnDecls.add(decl);
+ columnClasses.add(OutcomeStructure.getJavaClass(typeCode));
+ colReadOnly.add(readOnly);
+
+ // read help
+ String helpText;
+ if (decl instanceof SimpleType)
+ helpText = OutcomeStructure.extractHelp(model);
+ else
+ helpText = OutcomeStructure.extractHelp(decl);
+
+ if (helpText.length() == 0)
+ helpText = "<i>"+Language.translate("No help is available for this cell")+"</i>";
+
+ colHelp.add(helpText);
+
+ }
+
+
+ public void enumerateElements(ContentModelGroup group) throws StructuralException {
+ for (Enumeration<?> childElements = group.enumerate(); childElements.hasMoreElements(); ) {
+ Particle thisParticle = (Particle)childElements.nextElement();
+ String extraHeader = "";
+ if (thisParticle instanceof Group) {
+ Group thisGroup = (Group)thisParticle;
+ Order order = thisGroup.getOrder();
+ if (order == Order.sequence || order == Order.all)
+ enumerateElements(thisGroup);
+ else // we only support sequences in data structures such as these
+ throw new StructuralException("Element "+thisGroup.getName()+". Expecting sequence or all. Got "+thisGroup.getOrder());
+ }
+ else if (thisParticle instanceof ElementDecl) {
+ ElementDecl thisElement = (ElementDecl)thisParticle;
+ int typeCode = SimpleTypesFactory.INVALID_TYPE;
+ //make sure not too complex
+ if (thisElement.getType() != null) {
+ if (thisElement.getType().isComplexType()) {
+ ComplexType elementType = (ComplexType)thisElement.getType();
+ if (elementType.getParticleCount() > 0 ||
+ thisElement.getMaxOccurs() > 1)
+ throw new StructuralException("Too deep for a table");
+ for (Enumeration<?> attrs = elementType.getAttributeDecls(); attrs.hasMoreElements();) {
+ AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement();
+ if (!thisAttr.isFixed())
+ throw new StructuralException("Non-fixed attributes of child elements not supported in tables.");
+ else
+ extraHeader=extraHeader+" ("+thisAttr.getName()+":"+(thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue())+")";
+ }
+ // find type
+ XMLType parentType = thisElement.getType();
+ while (!(parentType instanceof SimpleType) && parentType != null) {
+ parentType = parentType.getBaseType();
+ if (parentType != null) typeCode = ((SimpleType)parentType).getTypeCode();
+ }
+ }
+ else
+ typeCode = ((SimpleType)thisElement.getType()).getTypeCode();
+ }
+
+ //add to list
+ addColumn(thisElement.getName()+extraHeader, thisElement, typeCode, new Boolean(thisElement.getFixedValue() != null));
+ }
+ else throw new StructuralException("Particle "+thisParticle.getClass()+" not implemented");
+ }
+ }
+
+ public void addInstance(Element myElement, int index) throws OutcomeException {
+ if (index == -1) index = elements.size();
+ Object[] newRow = new Object[columnHeadings.size()];
+ for (int i=0; i<columnDecls.size(); i++) {
+ if (columnDecls.get(i) instanceof ElementDecl) { // sub element - get the node from it
+ ElementDecl thisElementDecl = (ElementDecl)columnDecls.get(i);
+ NodeList childElements = myElement.getElementsByTagName(thisElementDecl.getName());
+ switch (childElements.getLength()) {
+ case 1: // element exists - read the contents
+ Element childElement = (Element)childElements.item(0);
+ if (childElement.hasChildNodes()) {
+ Node thisNode = childElement.getFirstChild();
+ if (thisNode.getNodeType() == Node.TEXT_NODE)
+ newRow[i] = OutcomeStructure.getTypedValue(((Text)thisNode).getData(), columnClasses.get(i));
+ else
+ throw new StructuralException("First child of Field " + thisElementDecl.getName() + " was not Text. (NodeType:"+thisNode.getNodeType()+")");
+ }
+ else { // create text node
+ newRow[i] = this.setupDefaultElement(thisElementDecl, childElement, columnClasses.get(i));
+ }
+ break;
+ case 0: // element is missing - create it
+ Element newElement = myElement.getOwnerDocument().createElement(thisElementDecl.getName());
+ myElement.appendChild(newElement); //TODO: not in the right place in sequence. should insert it
+ newRow[i] = setupDefaultElement(thisElementDecl, newElement, columnClasses.get(i));
+ break;
+ default:
+ throw new CardinalException("Element "+thisElementDecl.getName()+" appeared more than once.");
+ }
+ }
+ else if (columnDecls.get(i) instanceof AttributeDecl) { //attribute
+ AttributeDecl thisAttrDecl = (AttributeDecl)columnDecls.get(i);
+ newRow[i] = OutcomeStructure.getTypedValue(myElement.getAttribute(thisAttrDecl.getName()), columnClasses.get(i));
+ }
+ else { // first child node
+ Node thisNode = myElement.getFirstChild();
+ if (thisNode == null) {
+ thisNode = myElement.getOwnerDocument().createTextNode("");
+ myElement.appendChild(thisNode);
+ }
+ if (thisNode.getNodeType() == Node.TEXT_NODE || thisNode.getNodeType() == Node.CDATA_SECTION_NODE)
+ newRow[i] = OutcomeStructure.getTypedValue(((Text)thisNode).getData(), columnClasses.get(i));
+ else
+ throw new StructuralException("First child of Column " + myElement.getTagName() + " was not Text");
+ }
+ }
+ elements.add(index, myElement);
+ rows.add(index, newRow);
+ fireTableRowsInserted(index, index);
+ }
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ return columnClasses.get(columnIndex);
+ }
+
+ @Override
+ public String getColumnName(int columnIndex) {
+ return columnHeadings.get(columnIndex);
+ }
+
+ @Override
+ public int getRowCount() {
+ return rows.size();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return columnHeadings.size();
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ boolean isReadOnly = readOnly || colReadOnly.get(columnIndex).booleanValue();
+ return !isReadOnly;
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ Object[] thisRow = rows.get(rowIndex);
+ thisRow[columnIndex]=aValue;
+ Element myElement = elements.get(rowIndex);
+ // update node
+ if (columnDecls.get(columnIndex) instanceof ElementDecl) { // sub element
+ ElementDecl thisDecl = (ElementDecl)columnDecls.get(columnIndex);
+ NodeList childElements = myElement.getElementsByTagName(thisDecl.getName());
+ // depend on one element with a Text child - this should have been enforced on init.
+ Text childNode = (Text)(childElements.item(0).getFirstChild());
+ childNode.setData(aValue.toString());
+ }
+ else if (columnDecls.get(columnIndex) instanceof AttributeDecl) { //attribute
+ AttributeDecl thisDecl = (AttributeDecl) columnDecls.get(columnIndex);
+ myElement.setAttribute(thisDecl.getName(), aValue.toString());
+ }
+ else { // first child node
+ Text textNode = (Text)myElement.getFirstChild();
+ textNode.setData(aValue.toString());
+ }
+ fireTableCellUpdated(rowIndex, columnIndex);
+ }
+
+ public Element removeRow(int rowIndex) {
+ Element elementToGo = elements.get(rowIndex);
+ elements.remove(rowIndex);
+ rows.remove(rowIndex);
+ fireTableRowsDeleted(rowIndex,rowIndex);
+ return elementToGo;
+ }
+
+ public Object setupDefaultElement(ElementDecl thisDecl, Element parent, Class<?> type) {
+ Object newValue;
+ String defaultValue = thisDecl.getFixedValue();
+ if (defaultValue == null)
+ defaultValue = thisDecl.getDefaultValue();
+ if (readOnly)
+ newValue = "";
+ else
+ newValue = OutcomeStructure.getTypedValue(defaultValue, type);
+
+ Text newNode = parent.getOwnerDocument().createTextNode(newValue.toString());
+ parent.appendChild(newNode);
+ // fixed attributes
+ try {
+ ComplexType content = (ComplexType)thisDecl.getType();
+ for (Enumeration<?> attrs = content.getAttributeDecls(); attrs.hasMoreElements();) {
+ AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement();
+ parent.setAttribute(thisAttr.getName(), thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue());
+ }
+ } catch (ClassCastException ex) { } // only complex types have attributes
+ return newValue;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ Object[] thisRow = rows.get(rowIndex);
+ if (!(getColumnClass(columnIndex).equals(thisRow[columnIndex].getClass())))
+ Logger.warning(thisRow[columnIndex]+" should be "+getColumnClass(columnIndex)+" is a "+thisRow[columnIndex].getClass().getName());
+ return thisRow[columnIndex];
+ }
+
+ public String validateStructure() { // remove empty rows
+ for (int j=0; j < rows.size(); j++) {
+ Object[] elems = rows.get(j);
+ boolean empty = true;
+ for (int i = 0; i < elems.length && empty; i++)
+ empty &= OutcomeStructure.isEmpty(elems[i]);
+ if (empty)
+ if (model.getMinOccurs() < rows.size())
+ removeRow(j);
+ else
+ return "Too many empty rows in table "+model.getName();
+ }
+ return null;
+ }
+
+ public Element initNew(Document parent, int index) {
+ if (index == -1) index = elements.size();
+ Object[] newRow = new Object[columnHeadings.size()];
+ Element myElement = parent.createElement(model.getName());
+ for (int i=0; i<columnDecls.size(); i++) {
+ if (columnDecls.get(i) instanceof ElementDecl) { // sub element
+ ElementDecl childElementDecl = (ElementDecl)columnDecls.get(i);
+ Element childElement = parent.createElement(childElementDecl.getName());
+ Object newValue = setupDefaultElement(childElementDecl, childElement, columnClasses.get(i));
+ myElement.appendChild(childElement);
+ newRow[i] = newValue;
+ }
+ else if (columnDecls.get(i) instanceof AttributeDecl) { //attribute
+ AttributeDecl thisAttrDecl = (AttributeDecl)columnDecls.get(i);
+ String newValue = thisAttrDecl.getFixedValue()!=null?thisAttrDecl.getFixedValue():thisAttrDecl.getDefaultValue();
+ newRow[i] = OutcomeStructure.getTypedValue(newValue, columnClasses.get(i));
+ myElement.setAttribute(thisAttrDecl.getName(), newRow[i].toString());
+ }
+ else { // first child node
+ newRow[i] = setupDefaultElement(model, myElement, columnClasses.get(i));
+ }
+ }
+ elements.add(index,myElement);
+ rows.add(index, newRow);
+ fireTableRowsInserted(index,index);
+ return myElement;
+ }
+
+ public String getHelp(int i) {
+ return colHelp.get(i);
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java
new file mode 100644
index 0000000..9d21c97
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java
@@ -0,0 +1,142 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.Component;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.form.field.StringEditField;
+import com.c2kernel.utils.Logger;
+
+
+public class Field extends OutcomeStructure {
+
+ StringEditField myElementPanel = null;
+ AttributeList myAttributes;
+ JLabel tagName;
+ Text textNode;
+ boolean fixed;
+ public static final JPanel nullPanel = new JPanel();
+
+ public Field(ElementDecl model, boolean readOnly, HelpPane helpPane) {
+ super(model, readOnly, helpPane);
+
+ try {
+ myElementPanel = StringEditField.getEditField(model);
+ Logger.msg(6, "Field type: "+myElementPanel.getClass().getName());
+ myElementPanel.setHelp(helpPane, help);
+ if (readOnly) myElementPanel.setEditable(false);
+
+ } catch (StructuralException e) { // no base type for field - only attributes
+ myElementPanel = null;
+ }
+
+ myAttributes = new AttributeList(model, readOnly, helpPane);
+
+ tagName = new JLabel(model.getName());
+ tagName.setVerticalAlignment(SwingConstants.BOTTOM);
+ }
+
+ public JComponent getLabel() {
+ return tagName;
+ }
+
+ public Component getCData() {
+ if (myElementPanel == null)
+ return nullPanel;
+ return myElementPanel.getControl();
+ }
+
+ public JComponent getAttributes() {
+ return myAttributes;
+ }
+
+ @Override
+ public void addStructure(OutcomeStructure newElement) throws StructuralException {
+ throw new StructuralException("Field "+model.getName()+" cannot have child structures");
+ }
+
+ @Override
+ public void addInstance(Element myElement, Document parentDoc) throws OutcomeException {
+ Logger.msg(6, "Accepting Field "+myElement.getTagName());
+ if (this.myElement != null) throw new CardinalException("Field "+this.getName()+" cannot repeat");
+ this.myElement = myElement;
+
+ try {
+ if (myElementPanel == null)
+ Logger.error("Field should be empty. Discarding contents.");
+ else {
+ if (myElement.hasChildNodes())
+ textNode = (Text)myElement.getFirstChild();
+ else {
+ textNode = parentDoc.createTextNode(getDefaultValue());
+ myElement.appendChild(textNode);
+ }
+
+ myElementPanel.setData(textNode);
+ }
+ } catch (ClassCastException ex) {
+ throw new StructuralException("First child node of Field " + this.getName() + " was not Text: "+myElement.getFirstChild().getNodeType());
+ }
+ myAttributes.setInstance(myElement);
+ }
+
+ // check if valid
+
+ @Override
+ public String validateStructure() {
+ myAttributes.validateAttributes();
+ if (myElementPanel != null) myElementPanel.updateNode();
+ Text contents = (Text)myElement.getFirstChild();
+ if (!myElement.hasAttributes() && model.getMinOccurs() < 1 &&
+ (contents == null || contents.getData().length() == 0))
+ // empty - should remove if optional
+ myElement.getParentNode().removeChild(myElement);
+ return null;
+ }
+
+ @Override
+ public Element initNew(Document parent) {
+ Logger.msg(6, "Creating Field "+this.getName());
+
+ // make a new Element
+ myElement = parent.createElement(this.getName());
+
+ // see if there is a default/fixed value
+ if (myElementPanel != null) {
+ // populate
+ String defaultVal = readOnly?"":getDefaultValue();
+ textNode = parent.createTextNode(defaultVal);
+ myElement.appendChild(textNode);
+ myElementPanel.setData(textNode);
+ }
+
+ // set up attributes
+ myAttributes.initNew(myElement);
+
+ return myElement;
+ }
+
+ private String getDefaultValue() {
+ String defaultValue = model.getFixedValue();
+ if (defaultValue == null) defaultValue = model.getDefaultValue();
+ if (defaultValue == null) defaultValue = myElementPanel.getDefaultValue();
+ return defaultValue;
+ }
+
+ @Override
+ public void grabFocus() {
+ if (myElementPanel != null)
+ myElementPanel.grabFocus();
+ else
+ myAttributes.grabFocus();
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java
new file mode 100644
index 0000000..aa8e13e
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java
@@ -0,0 +1,55 @@
+package com.c2kernel.gui.tabs.outcome.form;
+
+import javax.swing.JEditorPane;
+import javax.swing.text.html.HTMLEditorKit;
+
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.3 $
+ * $Date: 2004/08/24 12:44:02 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class HelpPane extends JEditorPane {
+
+ public static final String header = "<h2><font color=\"blue\">"+Language.translate("Help")+"</font></h2>";
+
+ public HelpPane() {
+ super();
+ setEditable(false);
+ setEditorKit(new HTMLEditorKit());
+ setContentType("text/html");
+ setPreferredSize(new java.awt.Dimension(200,400));
+ }
+
+ public void setHelp(String title, String helpText) {
+ setText(header+"<h3>"+title+"</h3><br>"+toHTML(helpText));
+ }
+
+
+ /**
+ * Unfortunately JEditorPane will only display HTML3.2, whereas to embed HTML in an xsd we must
+ * use XHTML so it will be valid XML. This method does a quick and dirty removal of stuff that
+ * the JEditorPane cannot display
+ *
+ * @param xhtml
+ * @return
+ */
+ public static String toHTML(String xhtml) {
+ int startPos, endPos;
+ //remove xml header
+ while((startPos = xhtml.indexOf("<?")) != -1 &&
+ (endPos = xhtml.indexOf("?>")) != -1) {
+ xhtml = xhtml.substring(0,startPos)+xhtml.substring(endPos+2);
+ }
+ // remove slash in <tags/>
+ while ((startPos = xhtml.indexOf("/>")) != -1) {
+ xhtml = xhtml.substring(0, startPos)+xhtml.substring(startPos+1);
+ }
+ return xhtml;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java
new file mode 100644
index 0000000..3c5da27
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java
@@ -0,0 +1,141 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.util.StringTokenizer;
+
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+
+import com.c2kernel.utils.Logger;
+/**
+* ExcelAdapter enables Copy-Paste Clipboard functionality on JTables.
+* The clipboard data format used by the adapter is compatible with
+* the clipboard format used by Excel. This provides for clipboard
+* interoperability between enabled JTables and Excel.
+*/
+public class MultiLinePasteAdapter implements ActionListener {
+ private String rowstring, value;
+ private Clipboard system;
+ private StringSelection stsel;
+ private JTable jTable1;
+ private Dimension parent;
+ /**
+ * The Excel Adapter is constructed with a
+ * JTable on which it enables Copy-Paste and acts
+ * as a Clipboard listener.
+ */
+ public MultiLinePasteAdapter(JTable myJTable, Dimension parent) {
+ jTable1 = myJTable;
+ this.parent = parent;
+ KeyStroke copy =
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK, false);
+ // Identifying the copy KeyStroke user can modify this
+ // to copy on some other Key combination.
+ KeyStroke paste =
+ KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK, false);
+ // Identifying the Paste KeyStroke user can modify this
+ //to copy on some other Key combination.
+ jTable1.registerKeyboardAction(
+ this,
+ "Copy",
+ copy,
+ JComponent.WHEN_FOCUSED);
+ jTable1.registerKeyboardAction(
+ this,
+ "Paste",
+ paste,
+ JComponent.WHEN_FOCUSED);
+ system = Toolkit.getDefaultToolkit().getSystemClipboard();
+ }
+ /**
+ * Public Accessor methods for the Table on which this adapter acts.
+ */
+ public JTable getJTable() {
+ return jTable1;
+ }
+ public void setJTable(JTable jTable1) {
+ this.jTable1 = jTable1;
+ }
+ /**
+ * This method is activated on the Keystrokes we are listening to
+ * in this implementation. Here it listens for Copy and Paste ActionCommands.
+ * Selections comprising non-adjacent cells result in invalid selection and
+ * then copy action cannot be performed.
+ * Paste is done by aligning the upper left corner of the selection with the
+ * 1st element in the current selection of the JTable.
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().compareTo("Copy") == 0) {
+ StringBuffer sbf = new StringBuffer();
+ // Check to ensure we have selected only a contiguous block of
+ // cells
+ int numcols = jTable1.getSelectedColumnCount();
+ int numrows = jTable1.getSelectedRowCount();
+ int[] rowsselected = jTable1.getSelectedRows();
+ int[] colsselected = jTable1.getSelectedColumns();
+ if (!((numrows - 1
+ == rowsselected[rowsselected.length - 1] - rowsselected[0]
+ && numrows == rowsselected.length)
+ && (numcols - 1
+ == colsselected[colsselected.length - 1] - colsselected[0]
+ && numcols == colsselected.length))) {
+ JOptionPane.showMessageDialog(
+ null,
+ "Invalid Copy Selection",
+ "Invalid Copy Selection",
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ for (int i = 0; i < numrows; i++) {
+ for (int j = 0; j < numcols; j++) {
+ sbf.append(
+ jTable1.getValueAt(rowsselected[i], colsselected[j]));
+ if (j < numcols - 1)
+ sbf.append("\t");
+ }
+ sbf.append("\n");
+ }
+ stsel = new StringSelection(sbf.toString());
+ system = Toolkit.getDefaultToolkit().getSystemClipboard();
+ system.setContents(stsel, stsel);
+ }
+ if (e.getActionCommand().compareTo("Paste") == 0) {
+ Logger.msg(5, "Trying to Paste");
+ int startRow = (jTable1.getSelectedRows())[0];
+ int startCol = (jTable1.getSelectedColumns())[0];
+ try {
+ String trstring =
+ (String) (system.getContents(this).getTransferData(DataFlavor.stringFlavor));
+ Logger.msg(8, "String is:" + trstring);
+ StringTokenizer st1 = new StringTokenizer(trstring, "\n\r");
+ for (int i = 0; st1.hasMoreTokens(); i++) {
+ rowstring = st1.nextToken();
+ StringTokenizer st2 = new StringTokenizer(rowstring, "\t");
+ for (int j = 0; st2.hasMoreTokens(); j++) {
+ value = st2.nextToken();
+ if (startRow + i == jTable1.getRowCount())
+ parent.addRow(startRow+i);
+ if (startRow + i < jTable1.getRowCount()
+ && startCol + j < jTable1.getColumnCount())
+ jTable1.setValueAt(
+ value,
+ startRow + i,
+ startCol + j);
+ Logger.msg(5, "Putting "+value+" at row="+(startRow+i)+" column="+(startCol+j));
+ }
+ }
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java
new file mode 100644
index 0000000..566d7c5
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java
@@ -0,0 +1,218 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import com.c2kernel.persistency.outcome.OutcomeValidator;
+import com.c2kernel.persistency.outcome.Schema;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Logger;
+
+
+class OutcomeEditor extends JFrame implements ActionListener {
+
+ boolean readOnly = false;
+ File schemaFile = null;
+ File instanceFile = null;
+ JFileChooser chooser;
+ OutcomePanel outcome;
+ OutcomeValidator thisValid;
+
+ public OutcomeEditor(File schema, File instance, boolean readOnly) {
+ URL schemaURL = null;
+ URL instanceURL = null;
+ schemaFile = schema;
+ instanceFile = instance;
+ this.readOnly = readOnly;
+
+ try {
+ chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File(new File(".").getCanonicalPath()));
+ } catch (IOException e) {
+ System.out.println("Could not initialise file dialog");
+ System.exit(0);
+ }
+
+
+ this.setTitle("Outcome Editor");
+ GridBagLayout gridbag = new GridBagLayout();
+ getContentPane().setLayout(gridbag);
+
+ addWindowListener(
+ new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ System.exit(0);
+ }
+ }
+ );
+ // select files if url is empty
+
+ if (schemaFile == null) { // prompt for schema
+ schemaFile = getFile("Choose Schema File", "xsd");
+ if (schemaFile == null) {
+ System.out.println("Cannot function without a schema");
+ System.exit(1);
+ }
+ }
+
+ try {
+ schemaURL = schemaFile.toURI().toURL();
+ } catch (Exception e) {
+ System.out.println("Invalid schema URL");
+ System.exit(1);
+ }
+
+ if (instanceFile == null) { // prompt for schema
+ instanceFile = getFile("Choose Instance File", "xml");
+ }
+
+ try {
+ instanceURL = instanceFile.toURI().toURL();
+ } catch (Exception e) { }
+
+ try {
+ if (instanceFile != null && instanceFile.exists())
+ outcome = new OutcomePanel(schemaURL, instanceURL, readOnly);
+ else
+ outcome = new OutcomePanel(schemaURL, readOnly);
+
+ Schema thisSchema = new Schema();
+ thisSchema.docType = schemaURL.getFile();
+ thisSchema.docVersion = -1;
+ thisSchema.schema = FileStringUtility.url2String(schemaURL);
+ thisValid = OutcomeValidator.getValidator(thisSchema);
+
+ } catch (Exception e) { e.printStackTrace(); System.exit(0);}
+
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0; c.weighty = 1.0;
+ c.gridwidth = 2; c.ipadx = 5; c.ipady = 5;
+ gridbag.setConstraints(outcome, c);
+ this.getContentPane().add(outcome);
+
+ JButton saveButton = new JButton("Save");
+ saveButton.setActionCommand("save");
+ saveButton.addActionListener(this);
+ c.gridy++; c.weighty = 0; c.gridwidth = 1;
+ gridbag.setConstraints(saveButton, c);
+ this.getContentPane().add(saveButton);
+ if (readOnly) saveButton.setEnabled(false);
+
+ JButton saveAsButton = new JButton("Save As");
+ saveAsButton.setActionCommand("saveas");
+ saveAsButton.addActionListener(this);
+ c.gridx++; c.weighty = 0;
+ gridbag.setConstraints(saveAsButton, c);
+ this.getContentPane().add(saveAsButton);
+ if (readOnly) saveAsButton.setEnabled(false);
+ System.out.println("Building Outcome Panel. Please wait . . .");
+ outcome.run();
+ pack();
+ setVisible(true);
+ super.toFront();
+
+ }
+
+ public File getFile(String title, String fileType) {
+ File targetFile = null;
+ chooser.setFileFilter(new SimpleFilter(fileType));
+ chooser.setDialogTitle(title);
+ int returnVal = chooser.showDialog(this, "Select");
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ targetFile = chooser.getSelectedFile();
+ }
+ try {
+ System.out.println(fileType+"="+targetFile.toURL());
+ } catch (Exception ex) { }
+ return targetFile;
+ }
+
+ public static void usage() {
+ System.out.println("-schema file:///schema.xsd");
+ System.out.println("-inst file:///instance.xml");
+ System.out.println("Leave one out to get a file open box.");
+ System.exit(0);
+ }
+ public static void main( String[] argv ) {
+ Logger.addLogStream(System.out, 6);
+ File instance = null;
+ File schema = null;
+ boolean readOnly = false;
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equals("-schema"))
+ schema = new File(argv[++i]);
+ if (argv[i].equals("-inst"))
+ instance = new File(argv[++i]);
+ if (argv[i].equals("-readOnly"))
+ readOnly = true;
+ if (argv[i].equals("-help") || argv[i].equals("-h"))
+ usage();
+ }
+ new OutcomeEditor(schema, instance, readOnly);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().indexOf("save") == 0) {
+ String output;
+ output = outcome.getOutcome();
+
+ String errors = thisValid.validate(output);
+ if (errors != null && errors.length() > 0) {
+ int choice = JOptionPane.showConfirmDialog(null, errors+"\n\nSave anyway?", "Errors validating document", JOptionPane.YES_NO_OPTION);
+ if (choice != JOptionPane.YES_OPTION)
+ return;
+ }
+
+ if (instanceFile == null || e.getActionCommand().equals("saveas")) {
+ instanceFile = getFile("Choose Instance File", "xml");
+ if (instanceFile == null) {
+ System.out.println(output);
+ return;
+ }
+ }
+ try {
+ FileOutputStream targetStream = new FileOutputStream(instanceFile);
+ targetStream.write(output.getBytes());
+ targetStream.close();
+ } catch (Exception ex) {ex.printStackTrace();}
+ }
+ }
+
+ private class SimpleFilter extends javax.swing.filechooser.FileFilter {
+ String extension;
+
+ public SimpleFilter(String extension) {
+ super();
+ this.extension = extension;
+ }
+
+ @Override
+ public String getDescription() {
+ return extension.toUpperCase()+" Files";
+ }
+
+ @Override
+ public boolean accept(File f) {
+ if ((f.isFile() && f.getName().endsWith(extension.toLowerCase())) || f.isDirectory()) {
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java
new file mode 100644
index 0000000..63c1d3d
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java
@@ -0,0 +1,370 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+
+import javax.swing.Box;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.serialize.Method;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Schema;
+import org.exolab.castor.xml.schema.reader.SchemaReader;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException;
+import com.c2kernel.gui.tabs.outcome.InvalidSchemaException;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.OutcomeHandler;
+import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException;
+import com.c2kernel.utils.FileStringUtility;
+import com.c2kernel.utils.Logger;
+
+// will load the outcome as instructed by other bits of the gui
+// provides the 'save' button and creates the trees of objects to feed to the outcome form
+
+public class OutcomePanel extends JPanel implements OutcomeHandler
+{
+
+ Schema schemaSOM;
+ //ASModel schemaASModel;
+ Document outcomeDOM;
+ OutcomeStructure documentRoot;
+ DocumentBuilder parser;
+ boolean readOnly;
+ boolean useForm = true;
+ boolean panelBuilt = false;
+ boolean unsaved = false;
+ JScrollPane scrollpane = new JScrollPane();
+ HelpPane help = new HelpPane();
+
+ JTextArea basicView;
+
+ public OutcomePanel()
+ {
+ GridBagLayout gridbag = new java.awt.GridBagLayout();
+ setLayout(gridbag);
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setValidating(false);
+ dbf.setNamespaceAware(false);
+ try
+ {
+ parser = dbf.newDocumentBuilder();
+ }
+ catch (ParserConfigurationException e)
+ {
+ e.printStackTrace();
+ }
+
+ // Set up panel
+
+ JComponent pane;
+ if (!MainFrame.getPref("ShowHelp", "true").equals("true"))
+ pane = scrollpane;
+ else {
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, scrollpane, help);
+ splitPane.setOneTouchExpandable(true);
+ splitPane.setDividerSize(9);
+ pane = splitPane;
+ }
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0;
+ c.weighty = 1.0;
+ c.ipadx = 5;
+ c.ipady = 5;
+
+ gridbag.setConstraints(pane, c);
+ this.add(pane);
+ }
+
+ public OutcomePanel(boolean readOnly)
+ {
+ this();
+ setReadOnly(readOnly);
+ }
+
+ public OutcomePanel(String schema, boolean readOnly) throws OutcomeException
+ {
+ this(readOnly);
+ this.setDescription(schema);
+ }
+
+ public OutcomePanel(String schema, String outcome, boolean readOnly) throws OutcomeException
+ {
+ this(readOnly);
+ this.setDescription(schema);
+ this.setOutcome(outcome);
+ }
+
+ // Parse from URLS
+ public void setOutcome(URL outcomeURL) throws InvalidOutcomeException
+ {
+
+ try
+ {
+ setOutcome(new InputSource(outcomeURL.openStream()));
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidOutcomeException("Error creating instance DOM tree: " + ex);
+ }
+ }
+
+ public void setDescription(URL schemaURL) throws InvalidSchemaException
+ {
+ Logger.msg(7, "OutcomePanel.setDescription() - schemaURL:" + schemaURL.toString());
+ try
+ {
+ setDescription(new InputSource(schemaURL.openStream()));
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidSchemaException("Error creating exolab schema object: " + ex);
+ }
+
+ }
+
+ public OutcomePanel(URL schemaURL, boolean readOnly) throws OutcomeException
+ {
+ this(readOnly);
+ this.setDescription(schemaURL);
+ }
+
+ public OutcomePanel(URL schemaURL, URL outcomeURL, boolean readOnly) throws OutcomeException
+ {
+ this(readOnly);
+ this.setDescription(schemaURL);
+ this.setOutcome(outcomeURL);
+ }
+
+ // Parse from Strings
+ @Override
+ public void setOutcome(String outcome) throws InvalidOutcomeException
+ {
+
+ try
+ {
+ setOutcome(new InputSource(new StringReader(outcome)));
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidOutcomeException("Error creating instance DOM tree: " + ex);
+ }
+ }
+
+ @Override
+ public void setDescription(String schema) throws InvalidSchemaException
+ {
+ if (schema == null)
+ throw new InvalidSchemaException("Null schema supplied");
+ try
+ {
+ setDescription(new InputSource(new StringReader(schema)));
+ }
+ catch (Exception ex)
+ {
+ Logger.error(ex);
+ }
+
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly)
+ {
+ this.readOnly = readOnly;
+ }
+
+ public void setDescription(InputSource schemaSource) throws InvalidSchemaException, IOException
+ {
+
+ SchemaReader mySchemaReader = new SchemaReader(schemaSource);
+ this.schemaSOM = mySchemaReader.read();
+ }
+
+ public void setOutcome(InputSource outcomeSource) throws InvalidOutcomeException, IOException
+ {
+ try
+ {
+ outcomeDOM = parser.parse(outcomeSource);
+ }
+ catch (SAXException ex)
+ {
+ throw new InvalidOutcomeException("Sax error parsing Outcome " + ex);
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ Thread.currentThread().setName("Outcome Panel Builder");
+ try
+ {
+ makeDisplay();
+ }
+ catch (Exception oe)
+ {
+ scrollpane.setViewportView(new JLabel("Outcome View Generation Failed: " + oe.getMessage()));
+ Logger.error(oe);
+ }
+ }
+
+ public void makeDisplay()
+ {
+ try
+ {
+ initPanel();
+ }
+ catch (OutcomeException ex)
+ {
+ // something went wrong
+ useForm = false;
+ Box textPanel = Box.createVerticalBox();
+ JLabel errorMsg = new JLabel("Could not create outcome view: " + ex.getMessage());
+ errorMsg.setHorizontalAlignment(SwingConstants.LEFT);
+ textPanel.add(errorMsg);
+ textPanel.add(Box.createVerticalGlue());
+ if (outcomeDOM!=null) {
+ basicView = new JTextArea(serialize(outcomeDOM, true));
+ basicView.setEnabled(!readOnly);
+ textPanel.add(basicView);
+ }
+ scrollpane.setViewportView(textPanel);
+ }
+ }
+
+ public void initPanel() throws OutcomeException
+ {
+ Element docElement;
+ /*if (panelBuilt)
+ return;*/
+ Logger.msg(5, "Initialising Panel..");
+ scrollpane.setViewportView(new JLabel("Building outcome. Please hang on two ticks . . ."));
+ if (schemaSOM == null)
+ throw new InvalidSchemaException("A valid schema has not been supplied.");
+ // create root panel with element declaration and maybe root document element node
+
+ //find the root element declaration in the schema - may need to look for annotation??
+ ElementDecl rootElementDecl = null;
+ docElement = (outcomeDOM == null) ? null : outcomeDOM.getDocumentElement();
+
+ for (ElementDecl elementDecl: schemaSOM.getElementDecls())
+ {
+ rootElementDecl = elementDecl;
+ // REVISIT: We don't detect which is the most likely root element if there is more than one root decl
+ // xmlspy looks for an element not referenced elsewhere. simple but hard
+ // if we already have a document then use its root element to find the right decl
+ if (docElement != null && docElement.getTagName().equals(rootElementDecl.getName()))
+ break;
+ }
+
+ if (rootElementDecl == null)
+ throw new InvalidSchemaException("No root elements defined");
+ documentRoot = new DataRecord(rootElementDecl, readOnly, help, false);
+
+ Logger.msg(5, "Finished structure. Populating...");
+ if (docElement == null)
+ {
+ outcomeDOM = parser.newDocument();
+ docElement = documentRoot.initNew(outcomeDOM);
+ outcomeDOM.appendChild(docElement);
+ }
+ else
+ documentRoot.addInstance(docElement, outcomeDOM);
+
+ // got a fully rendered Outcome! put it in the scrollpane
+ // initialise container panel
+
+ JTabbedPane outcomeTab = new JTabbedPane();
+ outcomeTab.addTab(rootElementDecl.getName(), documentRoot);
+ outcomeTab.setSelectedIndex(0);
+
+ scrollpane.setViewportView(outcomeTab);
+ panelBuilt = true;
+
+ revalidate();
+ doLayout();
+ if (!readOnly)
+ documentRoot.grabFocus();
+ }
+
+ @Override
+ public JPanel getPanel() throws OutcomeNotInitialisedException
+ {
+ return this;
+ }
+
+ @Override
+ public String getOutcome()
+ {
+ if (useForm)
+ {
+ documentRoot.validateStructure();
+ return serialize(outcomeDOM, false);
+ }
+ else
+ {
+ return basicView.getText();
+ }
+ }
+
+ static public String serialize(Document doc, boolean prettyPrint)
+ {
+ String serializedDoc = null;
+ OutputFormat format = new OutputFormat(Method.XML, null, prettyPrint);
+ StringWriter stringOut = new StringWriter();
+ XMLSerializer serial = new XMLSerializer(stringOut, format);
+ try
+ {
+ serial.asDOMSerializer();
+ serial.serialize(doc);
+ }
+ catch (java.io.IOException ex)
+ {
+ Logger.error(ex.toString());
+ }
+ serializedDoc = stringOut.toString();
+ return serializedDoc;
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return unsaved;
+ }
+
+ @Override
+ public void saved() {
+ unsaved = false;
+ }
+
+ @Override
+ public void export(File targetFile) throws Exception {
+ FileStringUtility.string2File(targetFile, getOutcome());
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java
new file mode 100644
index 0000000..aee09df
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java
@@ -0,0 +1,283 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+import org.exolab.castor.types.AnyNode;
+import org.exolab.castor.xml.schema.Annotated;
+import org.exolab.castor.xml.schema.Annotation;
+import org.exolab.castor.xml.schema.ComplexType;
+import org.exolab.castor.xml.schema.ContentModelGroup;
+import org.exolab.castor.xml.schema.Documentation;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Group;
+import org.exolab.castor.xml.schema.ModelGroup;
+import org.exolab.castor.xml.schema.Order;
+import org.exolab.castor.xml.schema.Particle;
+import org.exolab.castor.xml.schema.SimpleType;
+import org.exolab.castor.xml.schema.SimpleTypesFactory;
+import org.exolab.castor.xml.schema.XMLType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+// contains child outcome elements - creates new ones
+public abstract class OutcomeStructure extends JPanel {
+
+ ElementDecl model;
+ Element myElement = null;
+ boolean readOnly;
+ HashMap<String, OutcomeStructure> subStructure = new HashMap<String, OutcomeStructure>();
+ ArrayList<String> order = new ArrayList<String>();
+ String help = "<i>"+Language.translate("No help is available for this element")+"</i>";
+ HelpPane helpPane;
+ boolean deferChild = false;
+
+ public OutcomeStructure(ElementDecl model, boolean readOnly , HelpPane helpPane) {
+ this.model = model;
+ this.readOnly = readOnly;
+ this.helpPane = helpPane;
+ subStructure = new HashMap<String, OutcomeStructure>();
+ Logger.msg(8, "Creating " + model.getName() + " structure as " +
+ this.getClass().getName().substring(this.getClass().getName().lastIndexOf('.') + 1));
+
+ String doc = extractHelp(model);
+ if (doc.length() > 0) help = doc;
+ }
+
+ public boolean getReadOnly() {
+ return readOnly;
+ }
+ /** Contains the rules for deciding which OutcomeStructure will represent a chosen Element Declaration.
+ * In this order
+ * <ol>
+ * <li>if maxOccurs>1 then Dimension
+ * <li> SimpleTypes are Fields
+ * <li> No element children is a Field
+ * <li> Everything else is a DataRecord
+ * </ol>
+ */
+ public OutcomeStructure createStructure(ElementDecl model, boolean readOnly, HelpPane help) throws OutcomeException {
+ XMLType elementType = model.getType();
+ ComplexType elementComplexType;
+
+ if (model.getMaxOccurs() == 0) return null;
+
+ // if more than one can occur - dimension
+ if (model.getMaxOccurs() > 1
+ || model.getMaxOccurs() == Particle.UNBOUNDED
+ || model.getMinOccurs() == 0)
+ return new Dimension(model, readOnly, help);
+
+ // must have a type from now on
+ if (elementType == null)
+ throw new StructuralException("Element "+model.getName()+" is elementary yet has no type.");
+ // simple types will be fields
+ if (elementType instanceof SimpleType) return new Field(model, readOnly, help);
+
+ // otherwise is a complex type
+ try {
+ elementComplexType = (ComplexType)elementType;
+ }
+ catch (ClassCastException e) {
+ throw new StructuralException("Unknown XMLType for element " + model.getName());
+ }
+
+ //when no element children - field
+ if (elementComplexType.getParticleCount() == 0) return new Field(model, readOnly, help);
+
+ //everything else is a data record
+ return new DataRecord(model, readOnly, help, deferChild);
+ }
+
+ /** Extracts child Element declarations from a content group and recursively from any group
+ * (not Element) of that group. calls createStructure() to find the corresponding OutcomeStructure
+ * then adds it to this structure.
+ */
+ public void enumerateElements(ContentModelGroup group) throws OutcomeException {
+
+ // process base types first if complex type
+ //HACK: castor does not include elements from basetype, so we do it manually. if they fix it, this will duplicate child elements.
+ if (group instanceof ComplexType) {
+ XMLType base = ((ComplexType)group).getBaseType();
+ if (base instanceof ComplexType)
+ enumerateElements((ComplexType)base);
+ }
+
+ for (Enumeration<?> elements = group.enumerate(); elements.hasMoreElements(); ) {
+ Particle thisParticle = (Particle)elements.nextElement();
+ if (thisParticle instanceof Group) {
+ Group thisGroup = (Group)thisParticle;
+ if (thisGroup instanceof ModelGroup) {
+ // HACK: Castor strangeness - model groups don't seem to resolve their own references. If fixed, this will still work
+ ModelGroup thisModel = (ModelGroup)thisGroup;
+ if (thisModel.hasReference()) thisGroup = thisModel.getReference();
+ }
+ Order thisOrder = thisGroup.getOrder();
+ if (thisOrder == Order.sequence || thisOrder == Order.all) enumerateElements(thisGroup);
+ else // we only support sequences in data structures such as these
+ throw new StructuralException("The '"+thisGroup.getOrder()+"' group is not supported");
+ }
+ else if (thisParticle instanceof ElementDecl) {
+ ElementDecl thisElement = (ElementDecl)thisParticle;
+ addStructure(createStructure(thisElement, readOnly, helpPane));
+ }
+ else throw new StructuralException("Particle " + thisParticle.getClass() + " not implemented");
+ }
+ }
+
+ /** Adds a generated OutcomeStructure as a child of this one. A separate structure as is often overridden.
+ */
+ public void addStructure(OutcomeStructure newElement) throws OutcomeException {
+ if (newElement == null) return;
+ subStructure.put(newElement.getName(), newElement);
+ order.add(newElement.getName());
+ }
+
+ /** After schema processing, addInstance() propogates the XML instance document down the layout.
+ * Most OutcomeStructures will throw an exception if called more than once, except Dimension, which is the only
+ * Outcome Structure to support maxOccurs>1
+ */
+ public abstract void addInstance(Element myElement, Document parentDoc) throws OutcomeException;
+
+ public Element getElement() {
+ return myElement;
+ }
+
+ @Override
+ public String getName() {
+ if (model == null) return null;
+ return model.getName();
+ }
+
+ public ElementDecl getModel() {
+ return model;
+ }
+
+ public String getHelp() {
+ return help;
+ }
+
+ public String validateStructure() {
+ StringBuffer errors = new StringBuffer();
+ for (OutcomeStructure element : subStructure.values()) {
+ errors.append(element.validateStructure());
+ }
+ return errors.toString();
+ }
+
+ public abstract Element initNew(Document parent);
+
+ public static String extractHelp(Annotated model) {
+ Enumeration<?> e = model.getAnnotations();
+ StringBuffer doc = new StringBuffer();
+ if (e.hasMoreElements()) { // look for HTML
+ Annotation note = (Annotation)e.nextElement();
+ for (Enumeration<?> g = note.getDocumentation(); g.hasMoreElements();) {
+ Documentation thisDoc = (Documentation)g.nextElement();
+ for (Enumeration<?> h = thisDoc.getObjects(); h.hasMoreElements();) {
+ AnyNode node = (AnyNode)h.nextElement();
+ String line = node.toString();
+ if (line.length() == 0)
+ line = node.getStringValue();
+ if (line.length() > 0) {
+ doc.append(line).append("\n");
+ }
+ }
+ }
+ }
+
+ return doc.toString();
+ }
+
+ @Override
+ public abstract void grabFocus();
+
+ public static Class<?> getJavaClass(int typeCode) {
+ switch (typeCode) {
+
+ // boolean
+ case SimpleTypesFactory.BOOLEAN_TYPE:
+ return Boolean.class;
+
+ // integers
+ case SimpleTypesFactory.INTEGER_TYPE:
+ case SimpleTypesFactory.NON_POSITIVE_INTEGER_TYPE:
+ case SimpleTypesFactory.NEGATIVE_INTEGER_TYPE:
+ case SimpleTypesFactory.NON_NEGATIVE_INTEGER_TYPE:
+ case SimpleTypesFactory.POSITIVE_INTEGER_TYPE:
+ case SimpleTypesFactory.INT_TYPE:
+ case SimpleTypesFactory.UNSIGNED_INT_TYPE:
+ case SimpleTypesFactory.SHORT_TYPE:
+ case SimpleTypesFactory.UNSIGNED_SHORT_TYPE:
+ case SimpleTypesFactory.LONG_TYPE:
+ case SimpleTypesFactory.UNSIGNED_LONG_TYPE:
+ case SimpleTypesFactory.BYTE_TYPE:
+ case SimpleTypesFactory.UNSIGNED_BYTE_TYPE:
+ return BigInteger.class;
+ // floats
+ case SimpleTypesFactory.FLOAT_TYPE:
+ case SimpleTypesFactory.DOUBLE_TYPE:
+ case SimpleTypesFactory.DECIMAL_TYPE:
+ return BigDecimal.class;
+
+ // images
+ case SimpleTypesFactory.BASE64BINARY_TYPE:
+ case SimpleTypesFactory.HEXBINARY_TYPE:
+ return ImageIcon.class;
+
+ // everything else is a string for now
+ default:
+ return String.class;
+ }
+ }
+
+ public static Object getTypedValue(String value, Class<?> type) {
+ try {
+ if (type.equals(Boolean.class))
+ if (value == null || value.equals(""))
+ return Boolean.FALSE;
+ else
+ return Boolean.valueOf(value);
+ else if (type.equals(BigInteger.class))
+ if (value == null || value.equals(""))
+ return new BigInteger("0");
+ else
+ return new BigInteger(value);
+ else if (type.equals(BigDecimal.class))
+ if (value == null || value.equals(""))
+ return new BigDecimal(0);
+ else
+ return new BigDecimal(value);
+ } catch (Exception ex) {
+ Logger.error("Cannot convert value '"+value+"' to a "+type.getName());
+ }
+ return value==null?"":value;
+ }
+
+ public static boolean isEmpty(Object value) {
+ if (value == null) return true;
+
+ if (value instanceof String) {
+ if (((String)value).length() == 0) return true;
+ }
+ else if (value instanceof Boolean) {
+ if (((Boolean)value).booleanValue() == false) return true;
+ }
+ else if (value instanceof BigInteger) {
+ if (((BigInteger)value).intValue() == 0) return true;
+ }
+ else if (value instanceof BigDecimal) {
+ if (((BigDecimal)value).floatValue() == 0.0) return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java
new file mode 100644
index 0000000..5aff436
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java
@@ -0,0 +1,12 @@
+package com.c2kernel.gui.tabs.outcome.form;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+
+public class StructuralException extends OutcomeException {
+
+ public StructuralException() {
+ super();
+ }
+ public StructuralException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java
new file mode 100644
index 0000000..742d1b4
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java
@@ -0,0 +1,173 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.text.JTextComponent;
+
+import org.exolab.castor.xml.schema.SimpleType;
+
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.7 $
+ * $Date: 2006/05/24 07:51:51 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class ArrayEditField extends StringEditField implements ActionListener {
+
+ Box arrayBox;
+ Box expandBox;
+ Box editBox;
+ JScrollPane arrayView;
+ JButton arrayButton;
+ JButton expandButton;
+ JButton contractButton;
+ JButton addButton;
+ JButton removeButton;
+ ArrayTableModel arrayModel;
+ JLabel arrayLabel = new JLabel("Array");
+ boolean panelShown = false;
+ boolean readOnly = false;
+
+ public ArrayEditField(SimpleType type) {
+ arrayBox = Box.createVerticalBox();
+ arrayBox.add(arrayLabel);
+ arrayButton = new JButton(Language.translate("Show"));
+ arrayButton.addActionListener(this);
+ arrayButton.setActionCommand("toggle");
+ arrayBox.add(arrayButton);
+
+ expandBox = Box.createHorizontalBox();
+ expandButton = new JButton(">>");
+ expandButton.setToolTipText("Increase the number of columns displaying this array");
+ expandButton.addActionListener(this);
+ expandButton.setActionCommand("extend");
+
+ contractButton = new JButton("<<");
+ contractButton.setToolTipText("Decrease the number of columns displaying this array");
+ contractButton.addActionListener(this);
+ contractButton.setActionCommand("contract");
+
+ expandBox.add(contractButton);
+ expandBox.add(Box.createHorizontalGlue());
+ expandBox.add(expandButton);
+
+ arrayModel = new ArrayTableModel(type);
+ if (arrayModel.getColumnCount() < 2) contractButton.setEnabled(false);
+ arrayView = new JScrollPane(new JTable(arrayModel));
+
+ editBox = Box.createHorizontalBox();
+ addButton = new JButton("+");
+ addButton.setToolTipText("Add a field to the end of this array");
+ addButton.addActionListener(this);
+ addButton.setActionCommand("add");
+ removeButton = new JButton("-");
+ removeButton.setToolTipText("Remove the last field from this array");
+ removeButton.addActionListener(this);
+ removeButton.setActionCommand("remove");
+ editBox.add(addButton);
+ editBox.add(Box.createHorizontalGlue());
+ editBox.add(removeButton);
+ }
+ /**
+ *
+ */
+ @Override
+ public String getDefaultValue() {
+ return "";
+ }
+ /**
+ *
+ */
+ @Override
+ public String getText() {
+ return arrayModel.getData();
+ }
+ /**
+ *
+ */
+ @Override
+ public void setText(String text) {
+ arrayModel.setData(text);
+ arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)");
+ }
+ /**
+ *
+ */
+ @Override
+ public Component getControl() {
+ return arrayBox;
+ }
+ /**
+ *
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("toggle")) {
+ arrayBox.removeAll();
+ if (panelShown) {
+ arrayBox.add(arrayLabel);
+ arrayBox.add(Box.createVerticalStrut(7));
+ arrayBox.add(arrayButton);
+ arrayButton.setText("Show");
+ }
+ else {
+ arrayBox.add(arrayLabel);
+ arrayBox.add(Box.createVerticalStrut(7));
+ arrayBox.add(arrayButton);
+ arrayBox.add(Box.createVerticalStrut(7));
+ arrayBox.add(expandBox);
+ arrayBox.add(Box.createVerticalStrut(7));
+ arrayBox.add(arrayView);
+ if (!readOnly) arrayBox.add(editBox);
+ arrayButton.setText("Hide");
+ }
+ panelShown = !panelShown;
+ arrayBox.validate();
+ }
+ else if (e.getActionCommand().equals("add")) {
+ arrayModel.addField();
+ arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)");
+ }
+ else if (e.getActionCommand().equals("remove")) {
+ arrayModel.removeField();
+ arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)");
+ }
+ else {
+ int currentCols = arrayModel.getColumnCount();
+ if (e.getActionCommand().equals("extend"))
+ currentCols++;
+ else if (e.getActionCommand().equals("contract"))
+ currentCols--;
+ arrayModel.setColumnCount(currentCols);
+ contractButton.setEnabled(currentCols > 1);
+ }
+
+ }
+
+ /**
+ *
+ */
+ @Override
+ public JTextComponent makeTextField() {
+ // not used by array
+ return null;
+ }
+ @Override
+ public void setEditable(boolean editable) {
+ readOnly = !editable;
+ arrayModel.setReadOnly(!readOnly);
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java
new file mode 100644
index 0000000..341c33a
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java
@@ -0,0 +1,113 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import javax.swing.table.AbstractTableModel;
+
+import org.exolab.castor.xml.schema.SimpleType;
+
+import com.c2kernel.gui.tabs.outcome.form.OutcomeStructure;
+import com.c2kernel.utils.Language;
+
+/**************************************************************************
+ *
+ * $Revision: 1.2 $
+ * $Date: 2006/05/24 07:51:53 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class ArrayTableModel extends AbstractTableModel {
+
+ ArrayList<Object> contents = new ArrayList<Object>();
+ Class<?> type;
+ int numCols = 1;
+ boolean readOnly = false;
+
+ public ArrayTableModel(SimpleType type) {
+ super();
+ this.type = OutcomeStructure.getJavaClass(type.getTypeCode());
+ }
+
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
+ public void setData(String data) {
+ contents.clear();
+ StringTokenizer tok = new StringTokenizer(data);
+ while(tok.hasMoreTokens())
+ contents.add(OutcomeStructure.getTypedValue(tok.nextToken(), type));
+ fireTableStructureChanged();
+ }
+
+ public String getData() {
+ if (contents.size() == 0) return "";
+ Iterator<Object> iter = contents.iterator();
+ StringBuffer result = new StringBuffer(iter.next().toString());
+ while (iter.hasNext())
+ result.append(" ").append(iter.next().toString());
+ return result.toString();
+ }
+
+ public void addField() {
+ contents.add(OutcomeStructure.getTypedValue("", type));
+ fireTableStructureChanged();
+ }
+
+ public void removeField() {
+ contents.remove(contents.size()-1);
+ fireTableStructureChanged();
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ return type;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return numCols;
+ }
+
+ public int getArrayLength() {
+ return contents.size();
+ }
+
+ public void setColumnCount(int newCols) {
+ numCols = newCols;
+ fireTableStructureChanged();
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return Language.translate("Value");
+ }
+
+ @Override
+ public int getRowCount() {
+ return (contents.size()/numCols)+1;
+ }
+
+ @Override
+ public Object getValueAt(int arg0, int arg1) {
+ int index = arg1+(arg0 * numCols);
+ if (index >= contents.size())
+ return null;
+ return contents.get(arg1+(arg0 * numCols));
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ if (columnIndex+(rowIndex*numCols) > contents.size()-1) return false;
+ return !readOnly;
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ contents.set(columnIndex+(rowIndex*numCols), aValue);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java
new file mode 100644
index 0000000..c831eb4
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java
@@ -0,0 +1,75 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Component;
+import java.awt.event.FocusEvent;
+
+import javax.swing.JCheckBox;
+import javax.swing.text.JTextComponent;
+
+import com.c2kernel.utils.Logger;
+
+/**************************************************************************
+ *
+ * $Revision: 1.7 $
+ * $Date: 2005/08/16 13:59:56 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+public class BooleanEditField extends StringEditField {
+
+ JCheckBox checkbox;
+
+ public BooleanEditField() {
+ checkbox = new JCheckBox();
+ checkbox.setSelected(false);
+ checkbox.addFocusListener(this);
+ }
+
+ @Override
+ public String getText() {
+ return String.valueOf(checkbox.isSelected());
+ }
+
+ @Override
+ public void setText(String text) {
+ boolean newState = false;
+ try {
+ newState = Boolean.valueOf(text).booleanValue();
+ } catch (Exception ex) {
+ Logger.error("Invalid value for checkbox: "+text);
+ }
+ checkbox.setSelected(newState);
+ }
+
+ @Override
+ public void setEditable(boolean editable) {
+ super.setEditable(editable);
+ checkbox.setEnabled(editable);
+ }
+
+ @Override
+ public Component getControl() {
+ return checkbox;
+ }
+
+ @Override
+ public String getDefaultValue() {
+ return "false";
+ }
+
+ /** don't reserve the item finder for a boolean */
+ @Override
+ public void focusGained(FocusEvent e) {
+ helpPane.setHelp(name, helpText);
+ }
+
+ /**
+ *
+ */
+ @Override
+ public JTextComponent makeTextField() {
+ // not used by boolean
+ return null;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java
new file mode 100644
index 0000000..2c4ce05
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java
@@ -0,0 +1,144 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Component;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.text.JTextComponent;
+
+import org.exolab.castor.types.AnyNode;
+import org.exolab.castor.xml.schema.AttributeDecl;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Facet;
+import org.exolab.castor.xml.schema.SimpleType;
+
+import com.c2kernel.gui.tabs.outcome.form.StructuralException;
+import com.c2kernel.scripting.Script;
+import com.c2kernel.utils.Logger;
+
+/*******************************************************************************
+ *
+ * $Revision: 1.4 $ $Date: 2005/08/16 13:59:56 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research All
+ * rights reserved.
+ ******************************************************************************/
+
+public class ComboField extends StringEditField {
+
+ JComboBox comboField;
+ ListOfValues vals;
+ DefaultComboBoxModel comboModel;
+ AnyNode listNode;
+
+ public ComboField(SimpleType type, AnyNode listNode) {
+ super();
+ comboField = new JComboBox();
+ content = type;
+ this.listNode = listNode;
+ createLOV();
+ }
+
+ @Override
+ public String getDefaultValue() {
+ if (vals.getDefaultKey() != null)
+ return vals.get(vals.getDefaultKey()).toString();
+ else
+ return "";
+ }
+
+ @Override
+ public String getText() {
+ return vals.get(comboModel.getSelectedItem()).toString();
+ }
+
+ @Override
+ public JTextComponent makeTextField() {
+ // not used by this control
+ return null;
+ }
+
+ @Override
+ public void setText(String text) {
+ comboModel.setSelectedItem(text);
+ }
+
+ @Override
+ public Component getControl() {
+ return comboField;
+ }
+
+ private void createLOV() {
+ vals = new ListOfValues();
+
+ if (listNode != null) { // schema instructions for list building
+ String lovType = listNode.getLocalName();
+ String param = listNode.getFirstChild().getStringValue();
+ if (lovType.equals("ScriptList"))
+ populateLOVFromScript(param);
+ if (lovType.equals("PathList"))
+ populateLOVFromLDAP(param);
+ }
+
+ // handle enumerations
+ // TODO: should be ANDed with above results
+ if (content.hasFacet(Facet.ENUMERATION)) {
+ //ListOfValues andList = new ListOfValues();
+ Enumeration<Facet> enums = content.getFacets(Facet.ENUMERATION);
+ while (enums.hasMoreElements()) {
+ Facet thisEnum = enums.nextElement();
+ vals.put(thisEnum.getValue(), thisEnum.getValue(), false);
+ }
+ }
+
+ String[] keyArray = new String[vals.keySet().size()];
+ comboModel = new DefaultComboBoxModel(vals.keySet().toArray(keyArray));
+ comboModel.setSelectedItem(vals.getDefaultKey());
+ comboField.setModel(comboModel);
+ }
+
+ /**
+ * @param param
+ */
+ private void populateLOVFromLDAP(String param) {
+ // TODO List of Values from LDAP properties, eg '/root/path;prop=val;prop=val'
+
+
+ }
+
+ private void populateLOVFromScript(String scriptName) {
+ try {
+ StringTokenizer tok = new StringTokenizer(scriptName, "_");
+ if (tok.countTokens() != 2)
+ throw new Exception("Invalid LOVScript name");
+ Script lovscript = new Script(tok.nextToken(), Integer.parseInt(tok.nextToken()));
+ lovscript.setInputParamValue("LOV", vals);
+ lovscript.execute();
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+
+ @Override
+ public void setDecl(AttributeDecl model) throws StructuralException {
+ super.setDecl(model);
+ createLOV();
+ }
+
+ @Override
+ public void setDecl(ElementDecl model) throws StructuralException {
+ super.setDecl(model);
+ createLOV();
+ }
+
+ /**
+ *
+ */
+
+ @Override
+ public void setEditable(boolean editable) {
+ comboField.setEditable(editable);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java
new file mode 100644
index 0000000..fabaed8
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java
@@ -0,0 +1,122 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Toolkit;
+import java.math.BigDecimal;
+
+import javax.swing.JTextField;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.PlainDocument;
+
+/**************************************************************************
+ *
+ * $Revision: 1.3 $
+ * $Date: 2005/08/16 13:59:56 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+public class DecimalEditField extends StringEditField {
+
+ public DecimalEditField() {
+ super();
+ field.addFocusListener(this);
+ field.setToolTipText("This field must contains a decimal number e.g. 3.14159265");
+ }
+
+ @Override
+ public String getText() {
+ return field.getText();
+ }
+
+ @Override
+ public void setText(String text) {
+ field.setText(text);
+ }
+
+ @Override
+ public String getDefaultValue() {
+ return "0.0";
+ }
+
+ @Override
+ public JTextComponent makeTextField() {
+ return new DecimalTextField();
+ }
+
+ private class DecimalTextField extends JTextField {
+
+ public DecimalTextField() {
+ super();
+ setHorizontalAlignment(RIGHT);
+ }
+ @Override
+ protected Document createDefaultModel() {
+ return new Decimal();
+ }
+ }
+
+ private class Decimal extends PlainDocument {
+
+ BigDecimal currentVal = new BigDecimal(0.0);
+
+
+ @Override
+ public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+
+ if (str == null || str.equals("")) {
+ return;
+ }
+
+ String proposedResult = null;
+
+ if (getLength() == 0) {
+ proposedResult = str;
+ } else {
+ StringBuffer currentBuffer = new StringBuffer( this.getText(0, getLength()) );
+ currentBuffer.insert(offs, str);
+ proposedResult = currentBuffer.toString();
+ }
+
+ try {
+ currentVal = parse(proposedResult);
+ super.insertString(offs, str, a);
+ } catch (Exception e) {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ }
+
+ @Override
+ public void remove(int offs, int len) throws BadLocationException {
+
+ String currentText = this.getText(0, getLength());
+ String beforeOffset = currentText.substring(0, offs);
+ String afterOffset = currentText.substring(len + offs, currentText.length());
+ String proposedResult = beforeOffset + afterOffset;
+
+ if (proposedResult.length() == 0) { // empty is ok
+ super.remove(offs, len);
+ return;
+ }
+ try {
+ currentVal = parse(proposedResult);
+ super.remove(offs, len);
+ } catch (Exception e) {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ }
+
+ public BigDecimal parse(String proposedResult) throws NumberFormatException {
+
+ BigDecimal value = new BigDecimal(0);
+ if ( proposedResult.length() != 0) {
+ value = new BigDecimal(proposedResult);
+ }
+ return value;
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java
new file mode 100644
index 0000000..716a073
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java
@@ -0,0 +1,112 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.reflect.Array;
+
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+
+import org.apache.xerces.impl.dv.util.Base64;
+
+import com.c2kernel.utils.Logger;
+
+public class ImageEditField extends StringEditField {
+
+ JLabel imageLabel;
+
+ Box imagePanel;
+
+ JButton browseButton;
+
+ String encodedImage;
+
+ static JFileChooser chooser = new JFileChooser();
+ static {
+ chooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter() {
+ @Override
+ public String getDescription() {
+ return "Image Files";
+ }
+
+ @Override
+ public boolean accept(File f) {
+ return (f.isDirectory() || (f.isFile() && (f.getName()
+ .endsWith(".gif")
+ || f.getName().endsWith(".jpg")
+ || f.getName().endsWith(".jpeg")
+ || f.getName().endsWith(".png"))));
+ }
+ });
+ }
+
+ public ImageEditField() {
+ super();
+ imageLabel = new JLabel();
+ imagePanel = Box.createVerticalBox();
+ browseButton = new JButton("Browse");
+ browseButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int returnVal = chooser.showOpenDialog(null);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ File file = chooser.getSelectedFile();
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ byte[] bArray = (byte[]) Array.newInstance(byte.class,
+ (int) file.length());
+ fis.read(bArray, 0, (int) file.length());
+ fis.close();
+
+ ImageIcon newImage = new ImageIcon(Toolkit
+ .getDefaultToolkit().createImage(bArray));
+ imageLabel.setIcon(newImage);
+ encodedImage = Base64.encode(bArray);
+ } catch (Exception ex) {
+ Logger.exceptionDialog(ex);
+ }
+ }
+ }
+ });
+ imagePanel.add(imageLabel);
+ imagePanel.add(Box.createVerticalStrut(5));
+ imagePanel.add(browseButton);
+ }
+
+ @Override
+ public String getDefaultValue() {
+ return "";
+ }
+
+ @Override
+ public Component getControl() {
+ return imagePanel;
+ }
+
+ @Override
+ public String getText() {
+ return encodedImage == null ? "" : encodedImage;
+ }
+
+ @Override
+ public void setText(String text) {
+ encodedImage = text;
+ if (text != null && text.length() > 0) {
+ byte[] decodedImage = Base64.decode(encodedImage);
+ imageLabel.setIcon(new ImageIcon(Toolkit.getDefaultToolkit()
+ .createImage(decodedImage)));
+ }
+ }
+
+ @Override
+ public void setEditable(boolean editable) {
+ browseButton.setVisible(false);
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java
new file mode 100644
index 0000000..e2c3df4
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java
@@ -0,0 +1,120 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Toolkit;
+import java.math.BigInteger;
+
+import javax.swing.JTextField;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.PlainDocument;
+
+/**************************************************************************
+ *
+ * $Revision: 1.4 $
+ * $Date: 2005/08/16 13:59:56 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+public class IntegerEditField extends StringEditField {
+
+ public IntegerEditField() {
+ super();
+ field.setToolTipText("This field must contains a whole number e.g. 3");
+ }
+
+ @Override
+ public String getText() {
+ return field.getText();
+ }
+
+ @Override
+ public void setText(String text) {
+ field.setText(text);
+ }
+
+ @Override
+ public String getDefaultValue() {
+ return "0";
+ }
+
+ @Override
+ public JTextComponent makeTextField() {
+ return new IntegerTextField();
+ }
+
+ private class IntegerTextField extends JTextField {
+
+ public IntegerTextField() {
+ super();
+ setHorizontalAlignment(RIGHT);
+ }
+ @Override
+ protected Document createDefaultModel() {
+ return new IntegerDocument();
+ }
+ }
+
+ private class IntegerDocument extends PlainDocument {
+
+ BigInteger currentVal = new BigInteger("0");
+
+ @Override
+ public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+
+ if (str == null || str.equals("")) {
+ return;
+ }
+
+ String proposedResult = null;
+
+ if (getLength() == 0) {
+ proposedResult = str;
+ } else {
+ StringBuffer currentBuffer = new StringBuffer( this.getText(0, getLength()) );
+ currentBuffer.insert(offs, str);
+ proposedResult = currentBuffer.toString();
+ }
+
+ try {
+ currentVal = parse(proposedResult);
+ super.insertString(offs, str, a);
+ } catch (Exception e) {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ }
+
+ @Override
+ public void remove(int offs, int len) throws BadLocationException {
+
+ String currentText = this.getText(0, getLength());
+ String beforeOffset = currentText.substring(0, offs);
+ String afterOffset = currentText.substring(len + offs, currentText.length());
+ String proposedResult = beforeOffset + afterOffset;
+ if (proposedResult.length() == 0) { // empty is ok
+ super.remove(offs, len);
+ return;
+ }
+
+ try {
+ currentVal = parse(proposedResult);
+ super.remove(offs, len);
+ } catch (Exception e) {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ }
+
+ public BigInteger parse(String proposedResult) throws NumberFormatException {
+
+ BigInteger value = new BigInteger("0");
+ if ( proposedResult.length() != 0) {
+ value = new BigInteger(proposedResult);
+ }
+ return value;
+ }
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java
new file mode 100644
index 0000000..f95c5c9
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java
@@ -0,0 +1,31 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.util.HashMap;
+
+/**************************************************************************
+ *
+ * $Revision: 1.2 $
+ * $Date: 2005/04/26 06:48:12 $
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+
+public class ListOfValues extends HashMap<String, Object> {
+
+ String defaultKey = null;
+
+ public ListOfValues() {
+ super();
+ }
+
+ public String put(String key, String value, boolean isDefaultKey) {
+ if (isDefaultKey) defaultKey = key;
+ return (String)super.put(key, value);
+ }
+
+ public String getDefaultKey() {
+ return defaultKey;
+ }
+
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java
new file mode 100644
index 0000000..140d7f2
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java
@@ -0,0 +1,40 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+
+import java.awt.Component;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.text.JTextComponent;
+
+import com.c2kernel.utils.Language;
+
+
+/**************************************************************************
+ *
+ * $Revision$
+ * $Date$
+ *
+ * Copyright (C) 2003 CERN - European Organization for Nuclear Research
+ * All rights reserved.
+ **************************************************************************/
+public class LongStringEditField extends StringEditField {
+
+ JTextArea bigText;
+ JScrollPane bigScroller;
+ public LongStringEditField() {
+ super();
+ field.setToolTipText(Language.translate("This field can contain any string."));
+ }
+
+ @Override
+ public JTextComponent makeTextField() {
+ return new JTextArea();
+ }
+ @Override
+ public Component getControl() {
+ if (bigScroller == null) {
+ bigScroller = new JScrollPane(field);
+ }
+ return bigScroller;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java
new file mode 100644
index 0000000..0e5fee9
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java
@@ -0,0 +1,257 @@
+package com.c2kernel.gui.tabs.outcome.form.field;
+import java.awt.Component;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTextField;
+import javax.swing.text.JTextComponent;
+
+import org.exolab.castor.types.AnyNode;
+import org.exolab.castor.xml.schema.Annotation;
+import org.exolab.castor.xml.schema.AppInfo;
+import org.exolab.castor.xml.schema.AttributeDecl;
+import org.exolab.castor.xml.schema.ElementDecl;
+import org.exolab.castor.xml.schema.Facet;
+import org.exolab.castor.xml.schema.SimpleType;
+import org.exolab.castor.xml.schema.Structure;
+import org.exolab.castor.xml.schema.XMLType;
+import org.exolab.castor.xml.schema.simpletypes.ListType;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import com.c2kernel.gui.DomainKeyConsumer;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.gui.tabs.outcome.OutcomeException;
+import com.c2kernel.gui.tabs.outcome.form.HelpPane;
+import com.c2kernel.gui.tabs.outcome.form.OutcomeStructure;
+import com.c2kernel.gui.tabs.outcome.form.StructuralException;
+import com.c2kernel.lookup.DomainPath;
+
+/** Superclass for the entry field for Field and AttributeList.
+ */
+public class StringEditField implements FocusListener, DomainKeyConsumer {
+
+ Node data;
+ Structure model;
+ protected SimpleType content;
+ HelpPane helpPane;
+ String helpText;
+ protected JTextComponent field;
+
+ boolean isValid = true;
+ boolean editable = true;
+ String name;
+
+
+ public StringEditField() {
+ field = makeTextField();
+ if (field != null)
+ field.addFocusListener(this);
+ }
+
+ private static StringEditField getFieldForType(SimpleType type) {
+ // handle lists special
+ if (type instanceof ListType)
+ return new ArrayEditField(type.getBuiltInBaseType());
+
+ // is a combobox
+ if (type.hasFacet(Facet.ENUMERATION))
+ return new ComboField(type, null);
+ //find LOVscript TODO: Implement LOV
+ Enumeration<Annotation> e = type.getAnnotations();
+ while (e.hasMoreElements()) {
+ Annotation note = e.nextElement();
+ for (Enumeration<AppInfo> f = note.getAppInfo(); f.hasMoreElements();) {
+ AppInfo thisAppInfo = f.nextElement();
+ for (Enumeration<?> g = thisAppInfo.getObjects(); g.hasMoreElements();) {
+ AnyNode appInfoNode = (AnyNode)g.nextElement();
+ if (appInfoNode.getLocalName().equals("ScriptList")
+ || appInfoNode.getLocalName().equals("LDAPList")) {
+ return new ComboField(type, appInfoNode);
+ }
+ }
+ }
+ }
+ // find info on length before we go to the base type
+ long length = -1;
+ if (type.getLength()!=null) length = type.getLength().longValue();
+ else if (type.getMaxLength()!=null) length = type.getMaxLength().longValue();
+ else if (type.getMinLength()!=null) length = type.getMinLength().longValue();
+
+ // find base type if derived
+ if (!(type.isBuiltInType()))
+ type = type.getBuiltInBaseType();
+ // else derive the class
+ Class<?> contentClass = OutcomeStructure.getJavaClass(type.getTypeCode());
+ // disable list edits for the moment
+ if (contentClass.equals(Boolean.class))
+ return new BooleanEditField();
+ else if (contentClass.equals(BigInteger.class))
+ return new IntegerEditField();
+ else if (contentClass.equals(BigDecimal.class))
+ return new DecimalEditField();
+ else if (contentClass.equals(ImageIcon.class))
+ return new ImageEditField();
+ else if (length > 60)
+ return new LongStringEditField();
+ else return new StringEditField();
+ }
+
+ public static StringEditField getEditField(AttributeDecl model) throws StructuralException {
+ if (model.isReference()) model = model.getReference();
+ StringEditField newField = getFieldForType(model.getSimpleType());
+ newField.setDecl(model);
+ return newField;
+ }
+
+ public static StringEditField getEditField(ElementDecl model) throws StructuralException {
+ try {
+ XMLType baseType = model.getType();
+ while (!(baseType instanceof SimpleType))
+ baseType = baseType.getBaseType();
+ StringEditField newField = getFieldForType((SimpleType)baseType);
+ newField.setDecl(model);
+ return newField;
+ } catch (Exception ex) {
+ throw new StructuralException("No type defined in model");
+ }
+ }
+
+ public void setDecl(AttributeDecl model) throws StructuralException {
+ this.model=model;
+ this.content=model.getSimpleType();
+ this.name = model.getName();
+ if (model.isFixed()) setEditable(false);
+ }
+
+ public void setDecl(ElementDecl model) throws StructuralException {
+ this.model=model;
+ this.name = model.getName();
+ XMLType type = model.getType();
+
+ // derive base type
+ if (type.isSimpleType())
+ this.content = (SimpleType)type;
+ else
+ this.content = (SimpleType)(type.getBaseType());
+
+ if (this.content == null) throw new StructuralException("No declared base type of element");
+
+ //
+ if (model.getFixedValue() != null) setEditable(false);
+
+ }
+
+ public void setData(Attr newData) throws StructuralException {
+ if (!(newData.getName().equals(name)))
+ throw new StructuralException("Tried to add a "+newData.getName()+" into a "+name+" attribute.");
+
+ this.data = newData;
+ setText(newData.getValue());
+ }
+
+ public void setData(Text newData) {
+ String contents = newData.getData();
+ this.data = newData;
+ setText(contents);
+ }
+
+ public void setData(String newData) throws OutcomeException {
+ if (data == null) throw new OutcomeException("No node exists");
+ setText(newData);
+ updateNode();
+
+ }
+
+ public Structure getModel() {
+ return model;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Node getData() {
+ return data;
+ }
+
+ public String getDefaultValue() {
+ return "";
+ }
+
+ public void setHelp(HelpPane helpPane, String helpText) {
+ this.helpPane = helpPane;
+ this.helpText = helpText;
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (MainFrame.itemFinder != null)
+ MainFrame.itemFinder.clearConsumer(this);
+ updateNode();
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ helpPane.setHelp(name, helpText);
+ if (editable && MainFrame.itemFinder != null)
+ MainFrame.itemFinder.setConsumer(this, "Insert");
+ }
+
+ public void updateNode() {
+ if (data == null) return;
+ if (data instanceof Text) {
+ ((Text)data).setData(getText());
+ }
+ else { //attribute
+ ((Attr)data).setValue(getText());
+ }
+ }
+
+ /**
+ * Read domkey from barcode input
+ */
+ @Override
+ public void push(DomainPath key) {
+ setText(key.getName());
+ }
+
+ /**
+ * Read string from barcode input
+ */
+ @Override
+ public void push(String key) {
+ setText(key);
+ }
+
+ public void setEditable(boolean editable) {
+ this.editable = editable;
+ if (field != null)
+ field.setEditable(editable);
+ }
+
+ public String getText() {
+ return field.getText();
+ }
+
+ public void setText(String text) {
+ field.setText(text);
+ }
+
+ public JTextComponent makeTextField() {
+ return new JTextField();
+ }
+
+ public Component getControl() {
+ return field;
+ }
+
+ public void grabFocus() {
+ getControl().requestFocus();
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/Node.java b/src/main/java/com/c2kernel/gui/tree/Node.java
new file mode 100644
index 0000000..470eeba
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/Node.java
@@ -0,0 +1,232 @@
+package com.c2kernel.gui.tree;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.gui.DynamicTreeBuilder;
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.lookup.AgentPath;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+import com.c2kernel.utils.Resource;
+
+public abstract class Node implements Runnable {
+
+ protected Path binding;
+ protected DefaultMutableTreeNode treeNode;
+ protected String name; // domain key
+ protected int sysKey; // target item
+ // attributes
+ protected String type = "";
+ protected Icon icon;
+ protected boolean isExpandable = false;
+ protected HashMap<Path, Node> childNodes = new HashMap<Path, Node>();
+ protected ArrayList<NodeSubscriber> subscribers = new ArrayList<NodeSubscriber>();
+ protected DynamicTreeBuilder loader = null;
+ private boolean loaded = false;
+ private String iconName;
+ protected EntityTabManager desktop;
+ static ImageIcon folder = Resource.findImage("folder.png");
+ static ImageIcon emptyLeaf = Resource.findImage("leaf.png");
+
+ public Node() {
+ }
+
+ protected void createTreeNode() {
+ this.treeNode = new DefaultMutableTreeNode(this);
+ }
+
+ public Node(Path path, EntityTabManager desktop) {
+ this.binding = path;
+ this.desktop = desktop;
+ this.sysKey = path.getSysKey();
+ // get the name of this node (last path element)
+ String[] pathComponents = path.getPath();
+ if (pathComponents.length > 0)
+ this.name = pathComponents[pathComponents.length-1];
+ else
+ this.name = Gateway.getProperty("Name");
+ }
+
+ public EntityTabManager getDesktop() {
+ return desktop;
+ }
+
+ public Node newNode(Path path)
+ {
+ try {
+ if (path.getEntity() instanceof AgentPath)
+ return new NodeAgent(path, desktop);
+ else
+ return new NodeItem(path, desktop);
+ } catch (ObjectNotFoundException ex) {
+ return new NodeContext(path, desktop);
+ }
+
+ }
+
+ /** Inserts a tree builder as the first child of the node, so it can be opened in the tree
+ */
+ public void makeExpandable() {
+ if (isExpandable) return;
+ loader = new DynamicTreeBuilder(this.treeNode);
+ this.treeNode.insert(loader.getTreeNode(),0);
+ isExpandable = true;
+ }
+
+
+ public DefaultMutableTreeNode getTreeNode() {
+ return treeNode;
+ }
+
+ public void setTreeNode(DefaultMutableTreeNode treeNode) {
+ this.treeNode = treeNode;
+ treeNode.setUserObject(this);
+ }
+
+ /** Subscription for loading node children.
+ * Note this is separate from the itemproxy subscription as it included query of the naming service
+ * and eventually should not require access to the item at all for higher performance */
+ public void subscribeNode(NodeSubscriber target) {
+ subscribers.add(target);
+ if (loaded == false) {
+ loaded = true;
+ loadMore();
+ }
+ else {
+ synchronized (childNodes) {
+ Node newNode;
+ for (Iterator<Node> nodes = childNodes.values().iterator(); nodes.hasNext();) {
+ newNode = nodes.next();
+ Logger.msg("subscribeNode target.add("+newNode.name+")");
+ target.add(newNode);
+ }
+ }
+ }
+ }
+
+ public void loadMore() {
+ Thread loading = new Thread(this);
+ loading.start();
+ }
+
+ public void unsubscribeNode(NodeSubscriber target) {
+ subscribers.remove(target);
+ }
+
+ public void add(Node newNode) {
+ synchronized(childNodes) {
+ childNodes.put(newNode.getPath(), newNode);
+ for (NodeSubscriber thisSub : subscribers) {
+ thisSub.add(newNode);
+ }
+ }
+ }
+
+ public void remove(Path oldPath) {
+ synchronized(childNodes) {
+ childNodes.remove(oldPath);
+ for (NodeSubscriber thisSub : subscribers) {
+ thisSub.remove(oldPath);
+ }
+ }
+ }
+
+ public void removeAllChildren() {
+ synchronized(childNodes) {
+ while (childNodes.keySet().iterator().hasNext()) {
+ remove(childNodes.keySet().iterator().next());
+ }
+ }
+ }
+
+ public Node getChildNode(Path itsPath) {
+ for (Iterator<Path> i = childNodes.keySet().iterator(); i.hasNext();) {
+ Object next = i.next();
+ if ( next.equals(itsPath) ) return childNodes.get(next);
+ }
+ return null;
+ }
+
+ // end of current batch
+ public void end(boolean more) {
+ for (NodeSubscriber thisSub : subscribers) {
+ thisSub.end(more);
+ }
+ }
+
+
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Node Loader: "+name);
+ loadChildren();
+ }
+
+ public abstract void loadChildren();
+
+ public void refresh() {
+ removeAllChildren();
+ loadChildren();
+ }
+
+ // Getters and Setters
+
+ public int getSysKey() { return sysKey; }
+// public void setSysKey( int sysKey ) { this.sysKey = sysKey; }
+
+ public String getName() { return name; }
+// public void setName( String name ) { this.name = name; }
+
+ public String getType() { return type; }
+// public void setType( String type ) { this.type = type; }
+
+ public Path getPath() { return binding; }
+
+ public DynamicTreeBuilder getTreeBuilder() { return loader; }
+
+ @Override
+ public String toString() {
+ if (this.name.length() > 0) {
+ return this.name;
+ }
+ else { return "Cristal"; }
+ }
+
+ public Icon getIcon() {
+ if (icon != null) return icon;
+ return(isExpandable?folder:emptyLeaf);
+ }
+
+ public String getIconName() {
+ return iconName;
+ }
+
+ public void setIcon(String icon) {
+ iconName = icon;
+ this.icon = Resource.findImage("typeicons/"+icon+"_16.png");
+ }
+
+ public JPopupMenu getPopupMenu() {
+ JPopupMenu popup = new JPopupMenu();
+ JMenuItem menuItem = new JMenuItem(Language.translate("Refresh"));
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (isExpandable) refresh();
+ }
+ });
+ popup.add(menuItem);
+ return popup;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeAgent.java b/src/main/java/com/c2kernel/gui/tree/NodeAgent.java
new file mode 100644
index 0000000..45ffb07
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeAgent.java
@@ -0,0 +1,33 @@
+
+package com.c2kernel.gui.tree;
+
+
+import java.util.ArrayList;
+
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.lookup.Path;
+
+/**
+ * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory.
+ * @author $Author: abranson $
+ * @version $Version$
+ */
+public class NodeAgent extends NodeEntity {
+
+ public NodeAgent(Path path, EntityTabManager desktop) {
+ super(path, desktop);
+ }
+
+ @Override
+ public void loadChildren() {
+ }
+
+ @Override
+ public ArrayList<String> getTabs() {
+
+ ArrayList<String> requiredTabs = super.getTabs();
+ requiredTabs.add("AgentProperties");
+ requiredTabs.add("JobList");
+ return requiredTabs;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeCollection.java b/src/main/java/com/c2kernel/gui/tree/NodeCollection.java
new file mode 100644
index 0000000..631ed8b
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeCollection.java
@@ -0,0 +1,68 @@
+package com.c2kernel.gui.tree;
+
+import java.util.ArrayList;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import com.c2kernel.collection.CollectionMember;
+import com.c2kernel.collection.Parent2ChildCollection;
+import com.c2kernel.common.ObjectNotFoundException;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.lookup.EntityPath;
+import com.c2kernel.lookup.InvalidEntityPathException;
+import com.c2kernel.utils.Logger;
+
+public class NodeCollection extends Node {
+
+ ItemProxy parent;
+ Parent2ChildCollection<CollectionMember> thisCollection;
+ String path;
+
+ public NodeCollection(ItemProxy parent, String name, EntityTabManager desktop) {
+ this.desktop = desktop;
+ this.parent = parent;
+ this.name = name;
+ this.path = parent.getSystemKey()+"/Collection/"+name;
+ createTreeNode();
+ this.makeExpandable();
+ }
+
+ @Override
+ public void loadChildren() {
+ Logger.msg(8, "NodeCollection::loadChildren()");
+ try {
+ thisCollection = (Parent2ChildCollection<CollectionMember>)parent.getObject("Collection/"+name);
+ } catch (ObjectNotFoundException ex) {
+ end(false);
+ return;
+ }
+
+ this.type = thisCollection.getClass().getName();
+ int lastDot = this.type.lastIndexOf('.');
+ if (lastDot > -1) this.type = this.type.substring(lastDot+1);
+ ArrayList<CollectionMember> collectionMembers = thisCollection.getMembers().list;
+ for (int i=0; i<collectionMembers.size(); i++)
+ {
+ CollectionMember aMember = collectionMembers.get(i);
+ if (aMember!=null)
+ try
+ {
+ EntityPath entityPath = new EntityPath(aMember.getEntityKey());
+ add(new NodeItem(entityPath, desktop));
+ }
+ catch (InvalidEntityPathException ex)
+ {
+ Logger.error("InvalidEntityPathException::NodeCollection::loadChildren() " + ex.toString());
+ }
+ }
+
+ end(false);
+
+ }
+
+ @Override
+ public DefaultMutableTreeNode getTreeNode() {
+ return treeNode;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeContext.java b/src/main/java/com/c2kernel/gui/tree/NodeContext.java
new file mode 100644
index 0000000..b2d215c
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeContext.java
@@ -0,0 +1,65 @@
+package com.c2kernel.gui.tree;
+
+import java.util.Enumeration;
+
+import com.c2kernel.entity.proxy.DomainPathSubscriber;
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.lookup.DomainPath;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Logger;
+
+
+public class NodeContext extends Node implements DomainPathSubscriber {
+ Enumeration<? extends Path> children;
+
+ public NodeContext(Path path, EntityTabManager desktop) {
+ super(path, desktop);
+ this.sysKey=Path.INVALID;
+ createTreeNode();
+ this.makeExpandable();
+ this.type = "Cristal Context";
+ }
+
+
+ @Override
+ public void loadChildren() {
+ if (children == null) {
+ Gateway.getProxyManager().subscribeTree(this, (DomainPath)binding);
+ children = binding.getChildren();
+ }
+
+ int batch = 75;
+ while (children.hasMoreElements() && batch > 0) {
+ Path newPath = children.nextElement();
+ if (newPath == null) break;
+ Logger.msg(2, "Subscription.run() - new node: " + newPath );
+ add( newNode(newPath));
+ batch--;
+ }
+ end(children.hasMoreElements());
+ }
+
+ @Override
+ public void pathAdded(DomainPath path) {
+ add(newNode(path));
+ }
+
+ @Override
+ public void refresh() {
+ children = null;
+ super.refresh();
+ }
+ @Override
+ public void pathRemoved(DomainPath path) {
+ remove(path);
+ }
+
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeEntity.java b/src/main/java/com/c2kernel/gui/tree/NodeEntity.java
new file mode 100644
index 0000000..bc16a6c
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeEntity.java
@@ -0,0 +1,82 @@
+package com.c2kernel.gui.tree;
+
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import com.c2kernel.entity.proxy.EntityProxy;
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.process.Gateway;
+import com.c2kernel.utils.Language;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory.
+ * @author $Author: abranson $
+ * @version $Version$
+ */
+public abstract class NodeEntity extends Node {
+
+ protected EntityProxy myEntity = null;
+
+ public NodeEntity(Path path, EntityTabManager desktop) {
+ super(path, desktop);
+ Logger.msg(2,"NodeEntity.<init> - Creating item for '"+path.toString()+"'.");
+
+ try {
+ // if an item - resolve the item and get its properties
+ myEntity = Gateway.getProxyManager().getProxy(path);
+ this.sysKey = path.getSysKey();
+ Logger.msg(2,"NodeEntity.<init> - System key is "+this.sysKey);
+
+ // Name should be the alias if present
+ String alias = myEntity.getName();
+ if (alias != null) this.name = alias;
+
+ this.type = myEntity.getProperty("Type");
+ String iconString = this.type;
+ if (type.equals("ActivityDesc")) iconString = myEntity.getProperty("Complexity")+iconString;
+ iconString = iconString.toLowerCase();
+ this.setIcon(iconString);
+ createTreeNode();
+ } catch (Exception e) {
+ Logger.msg(2, "NodeEntity.<init> - "+sysKey+" failed to resolve:");
+ Logger.error(e);
+ }
+ }
+
+ public EntityProxy getEntity() {
+ return myEntity;
+ }
+ /**
+ *
+ */
+ @Override
+ public JPopupMenu getPopupMenu() {
+ JPopupMenu popup = super.getPopupMenu();
+ JMenuItem openItem = new JMenuItem(Language.translate("Open"));
+ openItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ openItem();
+ }
+ });
+ popup.addSeparator();
+ popup.add(openItem);
+ return popup;
+ }
+
+ public void openItem() {
+ desktop.add(this);
+ }
+
+ public ArrayList<String> getTabs() {
+ ArrayList<String> requiredTabs = new ArrayList<String>();
+ return requiredTabs;
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeItem.java b/src/main/java/com/c2kernel/gui/tree/NodeItem.java
new file mode 100644
index 0000000..5d1f618
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeItem.java
@@ -0,0 +1,112 @@
+package com.c2kernel.gui.tree;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import com.c2kernel.entity.agent.Job;
+import com.c2kernel.entity.proxy.ItemProxy;
+import com.c2kernel.gui.EntityDetails;
+import com.c2kernel.gui.EntityTabManager;
+import com.c2kernel.gui.MainFrame;
+import com.c2kernel.lookup.Path;
+import com.c2kernel.persistency.ClusterStorage;
+import com.c2kernel.utils.Logger;
+
+/**
+ * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory.
+ * @author $Author: abranson $
+ * @version $Version$
+ */
+public class NodeItem extends NodeEntity {
+
+ public NodeItem(Path path, EntityTabManager desktop) {
+ super(path, desktop);
+ try {
+ makeExpandable();
+ } catch (Exception e) {
+ Logger.error(e);
+ }
+ }
+
+ @Override
+ public void loadChildren() {
+ try {
+ String collections = myEntity.queryData("Collection/all");
+ StringTokenizer tok = new StringTokenizer(collections, ",");
+ while (tok.hasMoreTokens()) {
+ NodeCollection newCollection = new NodeCollection((ItemProxy)myEntity, tok.nextToken(), desktop);
+ add(newCollection);
+ }
+ end(false);
+ } catch (Exception e) {
+ Logger.error(e);
+ }
+ }
+
+ @Override
+ public JPopupMenu getPopupMenu() {
+ JPopupMenu popup = super.getPopupMenu();
+ popup.addSeparator();
+ try {
+ ArrayList<Job> jobList = ((ItemProxy)myEntity).getJobList(MainFrame.userAgent);
+ ArrayList<String> already = new ArrayList<String>();
+ if (jobList.size() > 0) {
+ for (Job thisJob : jobList) {
+ String stepName = thisJob.getStepName();
+ if (already.contains(stepName))
+ continue;
+ already.add(stepName);
+ JMenuItem menuItem = new JMenuItem(stepName);
+ menuItem.setActionCommand(stepName);
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ execute(e.getActionCommand());
+ }
+ });
+ popup.add(menuItem);
+
+ }
+ }
+ else {
+ JMenuItem noAct = new JMenuItem("No activities");
+ noAct.setEnabled(false);
+ popup.add(noAct);
+ }
+ } catch (Exception ex) {
+ JMenuItem error = new JMenuItem("Error querying jobs");
+ error.setEnabled(false);
+ popup.add(error);
+ }
+
+ return popup;
+ }
+
+ public void execute(String stepName) {
+ EntityDetails thisDetail = desktop.add(this);
+ thisDetail.runCommand("Execution", stepName);
+ }
+
+ @Override
+ public ArrayList<String> getTabs() {
+
+ ArrayList<String> requiredTabs = super.getTabs();
+ requiredTabs.add("Properties");
+ try {
+ String collNames = myEntity.queryData(ClusterStorage.COLLECTION+"/all");
+ if (collNames.length() > 0)
+ requiredTabs.add("Collection");
+ } catch (Exception e) { }
+ requiredTabs.add("Execution");
+ requiredTabs.add("History");
+ requiredTabs.add("Viewpoint");
+ requiredTabs.add("Workflow");
+ return requiredTabs;
+
+ }
+}
diff --git a/src/main/java/com/c2kernel/gui/tree/NodeSubscriber.java b/src/main/java/com/c2kernel/gui/tree/NodeSubscriber.java
new file mode 100644
index 0000000..55f8aa9
--- /dev/null
+++ b/src/main/java/com/c2kernel/gui/tree/NodeSubscriber.java
@@ -0,0 +1,13 @@
+package com.c2kernel.gui.tree;
+
+import com.c2kernel.lookup.Path;
+
+
+public interface NodeSubscriber {
+
+ public void add(Node newNode);
+
+ public void remove(Path path);
+
+ public void end(boolean more);
+}