From b086f57f56bf0eb9dab9cf321a0f69aaaae84347 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Wed, 30 May 2012 08:37:45 +0200 Subject: Initial Maven Conversion --- .../com/c2kernel/gui/tabs/AgentPropertiesPane.java | 51 ++ .../java/com/c2kernel/gui/tabs/CloseTabIcon.java | 70 +++ .../java/com/c2kernel/gui/tabs/CollectionPane.java | 109 +++++ .../com/c2kernel/gui/tabs/DomainPathAdmin.java | 174 +++++++ .../java/com/c2kernel/gui/tabs/EntityTabPane.java | 197 ++++++++ .../java/com/c2kernel/gui/tabs/ExecutionPane.java | 208 +++++++++ .../java/com/c2kernel/gui/tabs/HistoryPane.java | 270 +++++++++++ .../gui/tabs/JTabbedPaneWithCloseIcons.java | 96 ++++ .../java/com/c2kernel/gui/tabs/JobListPane.java | 312 +++++++++++++ .../java/com/c2kernel/gui/tabs/PropertiesPane.java | 200 ++++++++ .../java/com/c2kernel/gui/tabs/ViewpointPane.java | 515 +++++++++++++++++++++ .../java/com/c2kernel/gui/tabs/WorkflowPane.java | 286 ++++++++++++ .../gui/tabs/collection/AggregationView.java | 90 ++++ .../tabs/collection/CollectionHistoryWindow.java | 192 ++++++++ .../gui/tabs/collection/CollectionView.java | 49 ++ .../gui/tabs/collection/DependencyView.java | 34 ++ .../c2kernel/gui/tabs/execution/ActivityItem.java | 55 +++ .../gui/tabs/execution/ActivityViewer.java | 296 ++++++++++++ .../gui/tabs/execution/DefaultExecutor.java | 35 ++ .../com/c2kernel/gui/tabs/execution/Executor.java | 22 + .../c2kernel/gui/tabs/execution/RequestButton.java | 34 ++ .../gui/tabs/outcome/BasicOutcomeEditor.java | 112 +++++ .../gui/tabs/outcome/InvalidOutcomeException.java | 11 + .../gui/tabs/outcome/InvalidSchemaException.java | 11 + .../gui/tabs/outcome/OutcomeException.java | 11 + .../c2kernel/gui/tabs/outcome/OutcomeHandler.java | 16 + .../outcome/OutcomeNotInitialisedException.java | 11 + .../gui/tabs/outcome/form/AttributeList.java | 160 +++++++ .../gui/tabs/outcome/form/CardinalException.java | 14 + .../c2kernel/gui/tabs/outcome/form/DataRecord.java | 252 ++++++++++ .../c2kernel/gui/tabs/outcome/form/Dimension.java | 395 ++++++++++++++++ .../gui/tabs/outcome/form/DimensionInstance.java | 33 ++ .../gui/tabs/outcome/form/DimensionTableModel.java | 332 +++++++++++++ .../com/c2kernel/gui/tabs/outcome/form/Field.java | 142 ++++++ .../c2kernel/gui/tabs/outcome/form/HelpPane.java | 55 +++ .../tabs/outcome/form/MultiLinePasteAdapter.java | 141 ++++++ .../gui/tabs/outcome/form/OutcomeEditor.java | 218 +++++++++ .../gui/tabs/outcome/form/OutcomePanel.java | 370 +++++++++++++++ .../gui/tabs/outcome/form/OutcomeStructure.java | 283 +++++++++++ .../gui/tabs/outcome/form/StructuralException.java | 12 + .../tabs/outcome/form/field/ArrayEditField.java | 173 +++++++ .../tabs/outcome/form/field/ArrayTableModel.java | 113 +++++ .../tabs/outcome/form/field/BooleanEditField.java | 75 +++ .../gui/tabs/outcome/form/field/ComboField.java | 144 ++++++ .../tabs/outcome/form/field/DecimalEditField.java | 122 +++++ .../tabs/outcome/form/field/ImageEditField.java | 112 +++++ .../tabs/outcome/form/field/IntegerEditField.java | 120 +++++ .../gui/tabs/outcome/form/field/ListOfValues.java | 31 ++ .../outcome/form/field/LongStringEditField.java | 40 ++ .../tabs/outcome/form/field/StringEditField.java | 257 ++++++++++ 50 files changed, 7061 insertions(+) create mode 100644 src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/CollectionPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/HistoryPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/JobListPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/Executor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java (limited to 'src/main/java/com/c2kernel/gui/tabs') 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> +{ + JTabbedPane collTabs; + + public CollectionPane() + { + super("Collection", "Item Collection"); + createLayout(); + } + + @Override + public void add(Collection contents) + { + Logger.msg(5, "Got "+contents.getName()+": "+contents.getClass().getName()); + Logger.msg(7, "Looking for existing "+contents.getName()); + CollectionView 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 findTabForCollName(String collName) { + CollectionView thisCollView = null; + for (int i = 0; i < collTabs.getTabCount(); i++) { + String tabName = collTabs.getTitleAt(i); + if (tabName.equals(collName)) { + thisCollView = (CollectionView)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>(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 domPaths; + DomainPathAdmin parent; + public DomainPathTableModel(DomainPathAdmin parent) { + this.parent = parent; + domPaths = new ArrayList(); + } + + 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..0a8a0cd --- /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.data.NodeEntity; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.gui.tabs.outcome.form.OutcomePanel; +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. - 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 { + + ArrayList 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 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(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(); + 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 { + + 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(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 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 { + + 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(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..2411296 --- /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.data.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, ActionListener { + + Box propertyBox; + boolean subbed = false; + HashMap loadedProps = new HashMap(); + 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(); + 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(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 { + + JComboBox schemas; + JComboBox views; + JComboBox events; + JLabel eventDetails; + JButton exportButton; + JButton viewButton; + + ArrayList schemaList; + ArrayList viewpointList; + ArrayList 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(this, ClusterStorage.VIEWPOINT, false)); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.OUTCOME, false)); + clearView(); + schemas.addItem("--"); + currentSchema = null; + schemaList = new ArrayList(); + 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(); + eventList = new ArrayList(); + + 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() { + @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 { + public int eventId; + public int schemaVersion; + public ArrayList viewNames = new ArrayList(); + 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 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..e4acd8d --- /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.graph.view.EditorPanel; +import com.c2kernel.graph.view.VertexPropertyPanel; +import com.c2kernel.gui.MainFrame; +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.WfGraphPanel; +import com.c2kernel.lifecycle.instance.gui.model.WfVertexFactory; +import com.c2kernel.lifecycle.instance.gui.model.WfVertexOutlineCreator; +import com.c2kernel.lifecycle.instance.gui.view.TransitionPanel; +import com.c2kernel.lifecycle.instance.gui.view.WfDirectedEdgeRenderer; +import com.c2kernel.lifecycle.instance.gui.view.WfVertexRenderer; +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 +{ + // 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(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..b6578bb --- /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.collection.gui.view.AggregationMemberRenderer; +import com.c2kernel.collection.gui.view.PropertyPanel; +import com.c2kernel.collection.gui.view.SelectedMemberPanel; +import com.c2kernel.graph.view.EditorPanel; +import com.c2kernel.graph.view.GraphPanel; +import com.c2kernel.gui.MainFrame; +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 +{ + 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 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 { + + ItemProxy item; + ArrayList collEvents; + ArrayList collEventData; + Aggregation coll; + public HistoryTableModel(ItemProxy item, Aggregation coll) { + this.item = item; + this.coll = coll; + collEvents = new ArrayList(); + collEventData = new ArrayList(); + item.subscribe(new MemberSubscription(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 extends JPanel { + + protected Collection thisColl; + protected ItemProxy item; + + public CollectionView() { + super(); + } + + public void setItem(ItemProxy entity) { + this.item = entity; + } + + public abstract void setCollection(Collection 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 +{ + // Objects to view/modify the properties of the selected activity + + public DependencyView() + { + super(); + setLayout(new GridLayout(1,1)); + createLayout(); + } + + @Override + public void setCollection(Collection 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 jobs = new ArrayList(); + + 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 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 requestButtons = new ArrayList(); + 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 attrSet = new ArrayList(); + 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 = "No help is available for this attribute"; + + + 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 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 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 instances = new ArrayList(); // stores DimensionInstances if tabs + ArrayList elements = new ArrayList(); // 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 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 -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 columnHeadings = new ArrayList(); + ArrayList> columnClasses = new ArrayList>(); + ArrayList columnDecls = new ArrayList(); + ArrayList colReadOnly = new ArrayList(); + ArrayList colHelp = new ArrayList(); + ArrayList rows = new ArrayList(); + ArrayList elements = new ArrayList(); + 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 = ""+Language.translate("No help is available for this cell")+""; + + 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 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"+Language.translate("Help")+""; + + 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+"

"+title+"


"+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) { + xhtml = xhtml.substring(0,startPos)+xhtml.substring(endPos+2); + } + // remove slash in + 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 subStructure = new HashMap(); + ArrayList order = new ArrayList(); + String help = ""+Language.translate("No help is available for this element")+""; + 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(); + 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 + *
    + *
  1. if maxOccurs>1 then Dimension + *
  2. SimpleTypes are Fields + *
  3. No element children is a Field + *
  4. Everything else is a DataRecord + *
+ */ + 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 contents = new ArrayList(); + 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 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 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 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 e = type.getAnnotations(); + while (e.hasMoreElements()) { + Annotation note = e.nextElement(); + for (Enumeration 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(); + } +} -- cgit v1.2.3