package com.fg.fxapplet;
import com.fg.util.FLoader;
import com.fg.util.FadingFilter;
import com.fg.xmleditor.FXDocumentModel;
import com.fg.xmleditor.FXDocumentModelImpl;
import com.fg.xmleditor.FXDoubleView;
import com.fg.xmleditor.FXModel;
import com.fg.xmleditor.FXModelStatusListener;
import com.fg.xmleditor.FXStatusEvent;
import java.applet.Applet;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.EventObject;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import netscape.javascript.JSObject;
import org.apache.xml.serialize.BaseMarkupSerializer;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class FXApplet extends JApplet
{
class Btn extends JButton
{
public Btn(ImageIcon icon, String toolTipText)
{
super(icon);
setFocusPainted(false);
setDisabledIcon(FadingFilter.fade(icon));
setToolTipText(toolTipText);
setPreferredSize(new Dimension(35, 27));
setMinimumSize(new Dimension(35, 27));
setMaximumSize(new Dimension(35, 27));
addActionListener(innerListener);
toolbar.add(this, null);
}
}
class ToggleBtn extends JToggleButton
{
public ToggleBtn(ImageIcon icon, String toolTipText)
{
super(icon);
setFocusPainted(false);
setDisabledIcon(FadingFilter.fade(icon));
setToolTipText(toolTipText);
setPreferredSize(new Dimension(35, 27));
setMinimumSize(new Dimension(35, 27));
setMaximumSize(new Dimension(35, 27));
addActionListener(innerListener);
toolbar.add(this, null);
}
}
class MItem extends JMenuItem
{
public MItem(String text, ImageIcon icon)
{
super(text);
if(icon != null)
{
setIcon(icon);
setDisabledIcon(FadingFilter.fade(icon));
}
addActionListener(innerListener);
}
}
class XMLDocumentLoader
implements Runnable
{
public void run()
{
doLoadXMLDocument(xmlContent);
}
String xmlContent;
public XMLDocumentLoader(String xmlContent)
{
this.xmlContent = xmlContent;
}
}
class InnerListener
implements ActionListener, FXModelStatusListener
{
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
if(source == btnReload || source == mReload)
{
if(prmOnLoad != null)
callJavascriptHandler(prmOnLoad);
else
doLoadXMLDocument(null);
} else
if(source == btnSave || source == mSave)
{
if(prmOnSave != null)
callJavascriptHandler(prmOnSave);
else
saveXMLDocument();
} else if (source == btnXmlLoad || source == mXmlLoad) {
String cur = textFieldXml.getText();
JFileChooser fc = null;
if (cur != null && ! cur.isEmpty()) {
File parent = new File(cur).getParentFile();
fc = new JFileChooser(parent);
} else {
fc = new JFileChooser();
}
int val = fc.showOpenDialog(rootPane);
if (val == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
textFieldXml.setText(file.getAbsolutePath());
}
setXMLSource(textFieldXml.getText());
doLoadXMLDocument(null);
} else if (source == btnXsdLoad || source == mXsdLoad) {
String cur = textField.getText();
JFileChooser fc = null;
if (cur != null && ! cur.isEmpty()) {
File parent = new File(cur).getParentFile();
fc = new JFileChooser(parent);
} else {
fc = new JFileChooser();
}
int val = fc.showOpenDialog(rootPane);
if (val == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
textField.setText(file.getAbsolutePath());
}
setXMLSchema(textField.getText());
doLoadXMLDocument(null);
} else
if(source == btnHorizSplit)
dblView.setOrientation(1);
else
if(source == btnVertSplit)
dblView.setOrientation(0);
else
if(source == btnSync)
dblView.setSyncSelectNodes(btnSync.getModel().isSelected());
else
if(source instanceof JRadioButtonMenuItem)
updateLookAndFeel(((JRadioButtonMenuItem)source).getText());
}
public void newDocumentLoaded(FXStatusEvent e)
{
btnSave.setEnabled(dblView.hasDocument() && dblView.isDocValid());
mSave.setEnabled(dblView.hasDocument() && dblView.isDocValid());
}
public void docValidityStatusChanged(FXStatusEvent e)
{
btnSave.setEnabled(dblView.hasDocument() && dblView.isDocValid());
mSave.setEnabled(dblView.hasDocument() && dblView.isDocValid());
}
InnerListener()
{
}
}
public FXApplet()
{
innerListener = new InnerListener();
model = new FXDocumentModelImpl();
dblView = new FXDoubleView(model);
toolbar = new JToolBar();
splitGroup = new ButtonGroup();
menuBar = new JMenuBar();
menuDocument = new JMenu("Document");
menuLF = new JMenu("Look & Feel");
}
String normalize(String s)
{
if(s == null)
{
return null;
} else
{
s = s.trim();
return s.length() == 0 ? null : s;
}
}
public void setDocName(String docName)
{
prmDocName = normalize(docName);
}
public String getDocName()
{
return prmDocName;
}
public void setXMLSchema(String xmlSchema)
{
prmXMLSchema = normalize(xmlSchema);
}
public String getXMLSchema()
{
return prmXMLSchema;
}
public void setXMLSource(String xmlSource)
{
prmXMLSource = normalize(xmlSource);
}
public String getXMLSource()
{
return prmXMLSource;
}
public void setBaseURL(String baseURL)
{
prmBaseURL = baseURL == null ? null : baseURL.trim();
}
public String getBaseURL()
{
return prmBaseURL;
}
public void setNamespace(String namespace)
{
prmNamespace = namespace == null ? null : namespace.trim();
}
public String getNamespace()
{
return prmNamespace;
}
public void setElement(String rootElementName)
{
prmElement = normalize(rootElementName);
}
public String getElement()
{
return prmElement;
}
public void setXMLDest(String xmlDest)
{
prmXMLDest = normalize(xmlDest);
}
public String getXMLDest()
{
return prmXMLDest;
}
public void init()
{
setDocName(getParameter("DOC_NAME"));
setXMLSchema(getParameter("XML_SCHEMA"));
setXMLSource(getParameter("XML_SOURCE"));
setBaseURL(getParameter("BASE_URL"));
setNamespace(getParameter("NAMESPACE"));
setElement(getParameter("ELEMENT"));
setXMLDest(getParameter("XML_DEST"));
prmOnStart = normalize(getParameter("ON_START"));
prmOnLoad = normalize(getParameter("ON_LOAD"));
prmOnSave = normalize(getParameter("ON_SAVE"));
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
doLoadXMLDocument(null);
}
private void jbInit()
throws Exception
{
setSize(new Dimension(812, 526));
model.addModelStatusListener(innerListener);
getContentPane().add(dblView, "Center");
getContentPane().add(toolbar, "North");
ImageIcon imgXsd = FLoader.getIcon(this, "OpenXSD.gif");
ImageIcon imgXml = FLoader.getIcon(this, "OpenXML.gif");
ImageIcon imgReload = FLoader.getIcon(this, "Reload.gif");
ImageIcon imgSave = FLoader.getIcon(this, "Save.gif");
ImageIcon imgHorizSplit = FLoader.getIcon(this, "HorizSplit.gif");
ImageIcon imgVertSplit = FLoader.getIcon(this, "VertSplit.gif");
ImageIcon imgSync = FLoader.getIcon(this, "Sync.gif");
btnXsdLoad = new Btn(imgXsd, "Load XSD schema");
btnXmlLoad = new Btn(imgXml, "Load XML Document");
btnReload = new Btn(imgReload, "Reload XML Document");
btnSave = new Btn(imgSave, "Save XML Document");
toolbar.addSeparator();
btnHorizSplit = new ToggleBtn(imgHorizSplit, "Horizontal Split");
splitGroup.add(btnHorizSplit);
btnVertSplit = new ToggleBtn(imgVertSplit, "Vertical Split");
splitGroup.add(btnVertSplit);
btnSync = new ToggleBtn(imgSync, "Synchronized Node Selection");
mReload = new MItem("Reload XML Document", imgReload);
menuDocument.add(mReload);
mXsdLoad = new MItem("Load XSD Document", imgXsd);
menuDocument.add(mXsdLoad);
mXmlLoad = new MItem("Load XML Document", imgXml);
menuDocument.add(mXmlLoad);
mSave = new MItem("Save XML Document", imgSave);
menuDocument.add(mSave);
menuBar.add(menuDocument);
javax.swing.UIManager.LookAndFeelInfo lfi[] = UIManager.getInstalledLookAndFeels();
LookAndFeel lf = UIManager.getLookAndFeel();
ButtonGroup group = new ButtonGroup();
for(int i = 0; i < lfi.length; i++)
{
JRadioButtonMenuItem mi = new JRadioButtonMenuItem(lfi[i].getName());
group.add(mi);
if(lfi[i].getClassName().equals(lf.getClass().getName()))
mi.setSelected(true);
mi.addActionListener(innerListener);
menuLF.add(mi);
}
menuBar.add(menuLF);
menuBar.setBorder(BorderFactory.createEtchedBorder());
setJMenuBar(menuBar);
JLabel lblXsdFile = new JLabel("XSD File");
lblXsdFile.setHorizontalAlignment(SwingConstants.RIGHT);
lblXsdFile.setPreferredSize(new Dimension(60, 14));
lblXsdFile.setMinimumSize(new Dimension(60, 14));
menuBar.add(lblXsdFile);
textField = new JTextField();
menuBar.add(textField);
textField.setColumns(10);
JLabel lblXmlFile = new JLabel("XML File");
lblXmlFile.setHorizontalAlignment(SwingConstants.RIGHT);
lblXmlFile.setPreferredSize(new Dimension(60, 14));
lblXmlFile.setMinimumSize(new Dimension(60, 14));
menuBar.add(lblXmlFile);
textFieldXml = new JTextField();
menuBar.add(textFieldXml);
textFieldXml.setColumns(10);
}
void callJavascriptHandler(String methodName)
{
try
{
JSObject win = JSObject.getWindow(this);
win.call(methodName, new Object[] {
this
});
}
catch(Exception ex)
{
dblView.showErrorMessage(ex.toString());
}
}
public void start()
{
if(prmOnStart != null)
callJavascriptHandler(prmOnStart);
}
URL getXMLBaseURL()
throws Exception
{
if(prmBaseURL != null)
return new URL(getCodeBase() + prmBaseURL);
if(prmXMLSource != null)
return new URL(getCodeBase() + prmXMLSource);
else
return null;
}
void doLoadXMLDocument(String xmlContent)
{
xmlContent = normalize(xmlContent);
if(prmXMLSchema != null)
{
showStatus("Loading XML document. Please wait ...");
try
{
java.util.List lostElements = null;
File tmp = new File(prmXMLSchema);
URL xsdURL = null;
if (tmp.exists()) {
xsdURL = tmp.toURI().toURL();
} else {
xsdURL = new URL(getCodeBase() + prmXMLSchema);
}
if(xmlContent != null)
{
StringReader reader = new StringReader(xmlContent);
InputSource src = new InputSource(reader);
src.setSystemId(getXMLBaseURL().toString());
xmlContent = null;
lostElements = model.openDocument(xsdURL, src);
} else
if(prmXMLSource != null)
{
tmp = new File(prmXMLSource);
URL xmlURL = null;
if (tmp.exists()) {
xmlURL = tmp.toURI().toURL();
} else {
xmlURL = new URL(getCodeBase() + prmXMLSource);
}
URLConnection con = xmlURL.openConnection();
con.connect();
InputStream in = con.getInputStream();
try
{
InputStreamReader reader = new InputStreamReader(in, "UTF-8");
InputSource src = new InputSource(reader);
src.setSystemId(getXMLBaseURL().toString());
lostElements = model.openDocument(xsdURL, src);
}
finally
{
try
{
in.close();
}
catch(Exception exception1) { }
if(con instanceof HttpURLConnection)
{
HttpURLConnection httpConn = (HttpURLConnection)con;
try
{
httpConn.disconnect();
}
catch(Exception ignore) { }
}
}
} else
if(prmNamespace != null && prmElement != null)
model.newDocument(xsdURL, prmNamespace, prmElement);
else
if(prmElement != null)
model.newDocument(xsdURL, prmElement);
else
model.newDocument(xsdURL);
if(lostElements != null)
{
StringBuffer sb = new StringBuffer("Error: The source XML document is invalid.\nThe following elements have not been loaded:");
for(int i = 0; i < lostElements.size(); i++)
{
sb.append("\n");
int k = sb.length();
Node element = (Node)lostElements.get(i);
sb.append(element.getNodeName());
for(Node node = element.getParentNode(); node != null && !(node instanceof Document); node = node.getParentNode())
sb.insert(k, node.getNodeName() + "/");
}
dblView.showErrorMessage(sb.toString());
}
if(prmDocName != null)
dblView.showInfoMessage(prmDocName);
showStatus("XML document has been loaded");
}
catch(Exception ex)
{
showStatus("");
dblView.showErrorMessage(ex.getMessage());
ex.printStackTrace();
}
}
}
public void loadXMLDocument(String xmlContent)
{
SwingUtilities.invokeLater(new XMLDocumentLoader(xmlContent));
}
public String getXMLDocumentAsText()
{
Document doc = model.getDocument();
if(doc == null)
return "";
StringWriter writer = new StringWriter();
try
{
try
{
OutputFormat format = new OutputFormat(doc, "UTF-8", true);
XMLSerializer serial = new XMLSerializer(writer, format);
serial.asDOMSerializer();
serial.serialize(doc);
String s = writer.toString();
return s;
}
catch(IOException ex)
{
dblView.showErrorMessage(ex.toString());
ex.printStackTrace();
}
return "";
}
finally
{
try
{
writer.close();
}
catch(Exception ignore) { }
}
}
void saveXMLDocument()
{
if(!dblView.hasDocument())
return;
dblView.stopEditing();
if(!dblView.isDocValid())
{
dblView.showErrorMessage("Error: Invalid document can not be saved");
return;
}
prmXMLDest = null;
if(prmXMLDest == null)
{
String cur = textFieldXml.getText();
JFileChooser fc = null;
if (cur != null && ! cur.isEmpty()) {
File parent = new File(cur).getParentFile();
fc = new JFileChooser(parent);
} else {
fc = new JFileChooser();
}
int val = fc.showSaveDialog(rootPane);
if (val == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
textFieldXml.setText(file.getAbsolutePath());
prmXMLDest = textFieldXml.getText();
OutputStream out = null;
try
{
Document doc = model.getDocument();
if(doc == null)
return;
out = new FileOutputStream(file);
OutputFormat format = new OutputFormat(doc, "UTF-8", true);
java.io.Writer writer = new OutputStreamWriter(out);
XMLSerializer serial = new XMLSerializer(writer, format);
serial.asDOMSerializer();
serial.serialize(doc);
dblView.showErrorMessage("File written");
}
catch(Exception ex)
{
dblView.showErrorMessage(ex.toString());
ex.printStackTrace();
}
finally
{
try
{
if (out != null) {
out.close();
}
}
catch(Exception exception2) { }
}
return;
} else {
dblView.showErrorMessage("Error: XML_DEST parameter is not specified");
return;
}
}
HttpURLConnection httpConn = null;
OutputStream out = null;
BufferedReader reader = null;
try
{
Document doc = model.getDocument();
if(doc == null)
return;
URL url = new URL(getCodeBase() + prmXMLDest);
httpConn = (HttpURLConnection)url.openConnection();
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
httpConn.setUseCaches(false);
httpConn.setRequestProperty("Content-Type", "text/plain");
out = httpConn.getOutputStream();
OutputFormat format = new OutputFormat(doc, "UTF-8", true);
java.io.Writer writer = new OutputStreamWriter(out);
XMLSerializer serial = new XMLSerializer(writer, format);
serial.asDOMSerializer();
serial.serialize(doc);
reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
String message;
String line;
for(message = ""; (line = reader.readLine()) != null; message = message + line + "\n");
dblView.showErrorMessage("Server response: " + message.trim());
}
catch(Exception ex)
{
dblView.showErrorMessage(ex.toString());
ex.printStackTrace();
}
finally
{
try
{
reader.close();
}
catch(Exception exception1) { }
try
{
out.close();
}
catch(Exception exception2) { }
try
{
httpConn.disconnect();
}
catch(Exception ignore) { }
}
}
void updateLookAndFeel(String lfName)
{
LookAndFeel lf = UIManager.getLookAndFeel();
if(lf != null && lf.getName().equals(lfName))
return;
javax.swing.UIManager.LookAndFeelInfo lfi[] = UIManager.getInstalledLookAndFeels();
for(int i = 0; i < lfi.length; i++)
if(lfi[i].getName().equals(lfName))
try
{
dblView.stopEditing();
UIManager.setLookAndFeel(lfi[i].getClassName());
SwingUtilities.updateComponentTreeUI(this);
return;
}
catch(Exception exception) { }
}
public String getAppletInfo()
{
return "XML Editor Applet. Author: Felix Golubov, WMG 2003.";
}
public String[][] getParameterInfo()
{
return (new String[][] {
new String[] {
"XML_SCHEMA", "String", "Relative URL of XML Schema document. Mandatory parameter."
}, new String[] {
"XML_SOURCE", "String", "Relative URL of XML document (may be servlet url with query string). Optional parameter. Required for loading existing XML documents."
}, new String[] {
"BASE_URL", "String", "Relative base URL of XML document. Optional parameter. When not provided, the XML_SOURCE URL is used."
}, new String[] {
"NAMESPACE", "String", "Namespace of the root XML element. Optional parameter. Required for creating new XML documents."
}, new String[] {
"ELEMENT", "String", "Name of the root XML element. Optional parameter. Required for creating new XML documents."
}, new String[] {
"XML_DEST", "String", "Relative URL of a servlet which saves XML documents (may have query string). Mandatory parameter."
}, new String[] {
"ON_START", "String", "Name of a javascript event handler method, which is called from applet start() method. Optional parameter."
}, new String[] {
"ON_LOAD", "String", "Name of a javascript event handler method, which is called when \"Load\" button clicked. Optional parameter."
}, new String[] {
"ON_SAVE", "String", "Name of a javascript event handler method, which is called when \"Save\" button clicked. Optional parameter."
}
});
}
public void destroy()
{
Thread.yield();
}
public static final String DOC_NAME = "DOC_NAME";
public static final String XML_SCHEMA = "XML_SCHEMA";
public static final String XML_SOURCE = "XML_SOURCE";
public static final String BASE_URL = "BASE_URL";
public static final String NAMESPACE = "NAMESPACE";
public static final String ELEMENT = "ELEMENT";
public static final String XML_DEST = "XML_DEST";
public static final String CONTENT = "CONTENT";
public static final String ON_START = "ON_START";
public static final String ON_LOAD = "ON_LOAD";
public static final String ON_SAVE = "ON_SAVE";
InnerListener innerListener;
String prmDocName;
String prmXMLSchema;
String prmXMLSource;
String prmBaseURL;
String prmNamespace;
String prmElement;
String prmXMLDest;
String prmOnStart;
String prmOnLoad;
String prmOnSave;
String prmCookieName;
String prmCookieValue;
FXDocumentModel model;
FXDoubleView dblView;
JToolBar toolbar;
JButton btnXsdLoad;
JButton btnXmlLoad;
JButton btnReload;
JButton btnSave;
JToggleButton btnHorizSplit;
JToggleButton btnVertSplit;
ButtonGroup splitGroup;
JToggleButton btnSync;
JMenuBar menuBar;
JMenu menuDocument;
JMenuItem mXsdLoad;
JMenuItem mXmlLoad;
JMenuItem mReload;
JMenuItem mSave;
JMenu menuLF;
private JTextField textField;
private JTextField textFieldXml;
static
{
try
{
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
}
catch(Exception ignore) { }
}
}