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 java.util.Enumeration; 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 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); } } 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); } } 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); } } 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 (Enumeration globalElements = schemaSOM.getElementDecls(); globalElements.hasMoreElements();) { rootElementDecl = (ElementDecl) globalElements.nextElement(); // 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(); } public JPanel getPanel() throws OutcomeNotInitialisedException { return this; } 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; } public boolean isUnsaved() { return unsaved; } public void saved() { unsaved = false; } public void export(File targetFile) throws Exception { FileStringUtility.string2File(targetFile, getOutcome()); } }