Building an XML Tree View Application
To exemplify the easy usage of XML, we will show you how to develop a basic
XML file viewer. This is done
1. by using the SpeedJG XML classes, and
2. by means of an XMLTreeModel implementation based on the W3C DOM.
|
The GUI of this application consists of a JSplitPane with a
JTree to navigate on the left and a JTextArea to show the contents on the
right. In addition, there is a JPopupMenu available on the text area to copy
the contents into the system clipboard.
To generate the source code, open the project
${YourPathToSpeedJG}/Examples.gpr.
Select the
JFrame xmlTreeView
and follow these steps to get a first outline of the Java source code:
|
|
-
Press the
Generate View Java Code
button on the tool bar and save the generated code into a file named
XmlTreeView.java.
-
Press the
Generate Controller Java Code
button on the tool bar. Accept the default listener recommendations
and save the generated code into a file named
XmlTreeViewController.java.
Customizing the generated Source Code
To customize the source code according to our needs in order to show the expected
results we only have to make changes within the
XmlTreeView.java
file and there only within the model class
XmlTreeView.
The generated view code (XmlTreeViewGUI)
and controller code (XmlTreeViewController)
remain unchanged. Thus, if you modify the layout of your GUI with
SpeedJG and re-generate the code, your individually added code lines
handling the GUI access remain untouched and valid because SpeedJG
by default only overwrites the previously generated view and
controller code.
First, add the following import statements at the beginning of the
XmlTreeView.java
file because we need these for some methods we will call later on.
import speed.util.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import javax.swing.event.*;
import java.io.*;
|
Next, replace the generated declaration and instantiation code lines of
the model class XmlTreeView
| from |
public class XmlTreeView
{
public XmlTreeView()
{ GUIObject gui = new XmlTreeViewGUI();
//XmlTreeViewController controller = new XmlTreeViewController(gui);
JFrame frame = (JFrame) gui.getComponent("xmlTreeView");
frame.show();
}
...
|
| to |
public class XmlTreeView extends XmlTreeViewController
{
public XmlTreeView()
{ super(new XmlTreeViewGUI());
xmlTreeView.show();
}
...
|
For performance and resource reasons SpeedJG implements its own lean XML DOM
and also a JTree model that handles a XML document in a JTree-specific manner.
Thus you are able not only to handle XML documents within a JTree but also to
substitute the default JTree model with an XML-based model!
In our example the instantiation of the SpeedJG
XMLDocumentTree
is done when opening an XML file.
private XMLDocumentTree openXMLDocument() throws Exception
{ File file = getXMLFile();
if (file == null) return null;
return new XMLDocumentTree(XMLDocument.fromFile(file.getPath()).getContent());
}
private class XMLFileFilter extends javax.swing.filechooser.FileFilter
{ public boolean accept(File file)
{ return file.getName().toLowerCase().endsWith(".gpr")
|| file.getName().toLowerCase().endsWith(".xml")
|| file.isDirectory();
}
public String getDescription()
{ return "SpeedJG Files, XML Files ( *.gpr, *.xml )";
}
}
private File getXMLFile()
{ JFileChooser jfc = new JFileChooser();
jfc.setCurrentDirectory(new File("."));
jfc.setFileFilter(new XMLFileFilter());
jfc.removeChoosableFileFilter(jfc.getAcceptAllFileFilter());
int result = jfc.showOpenDialog(null);
if (result != JFileChooser.APPROVE_OPTION)
{ return null;
}
else
{ return jfc.getSelectedFile();
}
}
|
At last, to make our example run, we have to overwrite some methods inherited from the controller class
XmlTreeViewController.
-
Remove the default model from our JTree when starting the application.
void initialize()
{ selectionTree.setModel(null);
}
-
Assign our own XMLTreeModel when opening a new XML file.
void handleOpenMenuItemActionPerformedEvent(ActionEvent e) throws Exception
{ selectionTree.setModel(openXMLDocument());
xmlTextArea.setText(null);
}
-
Show the contents of an XML node when selecting a node within the tree.
void handleSelectionTreeValueChangedEvent(TreeSelectionEvent e) throws Exception
{ Object[] path = e.getPath().getPath();
XMLElement nodeElement = (XMLElement)path[path.length - 1];
xmlTextArea.setText(nodeElement.asXMLString());
xmlTextArea.setCaretPosition(0);
}
-
Copy the outlined text of an XML node into the system Clipboard.
void handleCopyMenuItemActionPerformedEvent(ActionEvent e) throws Exception
{ Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipBoard.setContents(new StringSelection(xmlTextArea.getText()), null);
}
-
Exit the application.
void handleExitMenuItemActionPerformedEvent(ActionEvent e) throws Exception
{ System.exit(0);
}
If you want to test and experiment with this example you have to obtain the following files:
| XML Tree View Application Files |
| SpeedJG.jar |
Contains the classes GUIObject
and XMLDocumentTree.
Download and un-zip the SpeedJG.zip
file and place the SpeedJG.jar file on your
CLASSPATH.
|
|
XmlTreeView.java
|
Generated by SpeedJG and modified within this example.
|
|
XmlTreeViewController.java
|
Generated by SpeedJG.
|
XML Tree View Application based on the W3C DOM
If you prefer a tree model that works together with all current implementations
of the W3C DOM, or if you want to build an application without the need to
include classes from the SpeedJG.jar file to be licensed, you can also use the
XmlTreeModel
we have provided for these purposes, and that works similar to the SpeedJG
XMLDocumentTree.
I will not go into detail here because this would be a chapter of its own.
So you can study this class and look into the respective literature for particular
explanations. But already here I want to mention, that the
XmlTreeModel.class
references a
XmlTreeNodeFilter interface
that will not be explained until the next example -
XML Tree Edit - because
it is not used within this example.
To adapt our example above, we first have to modify the import statements at the
beginning of the XmlTreeView.java file,
and make the following changes:
| from |
to |
...
import speed.jg.*;
import speed.util.*;
...
|
...
import javax.xml.parsers.*;
import org.w3c.dom.*;
...
|
Also comment out the following import statement at the beginning of the
XmlTreeViewController.java file:
...
//import speed.jg.*;
...
|
Next we have to change the
openXMLDocument()
method that provides a new tree model for us:
private XmlTreeModel openXMLDocument() throws Exception
{ File file = getXMLFile();
if (file == null) return null;
DocumentBuilder documentBuilder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
XmlTreeModel xmlTreeModel =
new XmlTreeModel(documentBuilder.parse(file).getDocumentElement());
return xmlTreeModel;
}
|
At last we have to modify the method handling the tree selection events
because these events now deliver Nodes as defined within the W3C DOM interfaces:
void handleSelectionTreeValueChangedEvent(TreeSelectionEvent e) throws Exception
{ Object[] path = e.getPath().getPath();
Node nodeElement = (Node)path[path.length - 1];
xmlTextArea.setText(nodeElement.toString());
xmlTextArea.setCaretPosition(0);
}
|
If you want to test and experiment with this example you have to store the
following files into a directory of your choice and subsequently compile them:
If you execute this example you will see some differences to the example based
on the SpeedJG XML classes. This is because:
- SpeedJG only implements XML Elements and no Nodes.
- SpeedJG shows the element name with the toString() method.
-
It is not defined what your DOM imlementation will show with the toString() method.
The org.apache.crimson implementation (JDK 1.4.x) outlines the whole contents of a node.
If you use a DOM Level 3 implementation you can attach a DOMWriter.
If you want to customize the representation of an XML document within a
JTree, look at the next example -
XML Tree Edit - where the
XmlTreeNodeFilter comes into play.