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 --- .../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 ++++++++++++++ 29 files changed, 3766 insertions(+) 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/outcome') 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