/**
* DOMTree.java
*
* 1.00 2001/7/26
*
*/
package dods.clients.importwizard.DatasetList;
import dods.clients.importwizard.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import gnu.regexp.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.File;
import java.io.IOException;
import org.w3c.dom.*;
import javax.swing.tree.*;
/**
* This class echos an xmlfile
*
* @version 1.00 26 Jul 2001
* @author Kashan A. Shaikh
*/
public class DOMTree extends JTree {
final static public int SEARCH_NULL = 0;
final static public int SEARCH_NO_MATCH = 1;
final static public int SEARCH_ERROR = 2;
final static public int SEARCH_MATCH_FOUND = 3;
static private String listTitle = "DODS Dataset List";
// XML filename
private String xmlFile;
// DOM object
private Document document;
private Document currentDoc;
// List of elements
static private String[] treeElementNames = {
"datasets",
"provider",
"dataset",
"subdataset",
};
static private String rootTitle = "Data Providers";
static public String ELEMENT_ROOT = "datasets";
static public String ELEMENT_DATASET = "dataset";
// List of attributes
static private String[] desiredTreeAttributes = {
"baseURL",
"name",
"url",
"catalog",
"dir",
"gcmd",
};
static public String ATTR_NAME = "name";
static public String ATTR_CATALOG = "catalog";
static public String ATTR_DIR = "dir";
// List of desired URL attributes
static public String[] desiredURLAttributes = {
"baseURL",
};
static public String ATTR_BASE_URL = "baseURL";
//
// Constructor
//
public DOMTree(String fname) {
xmlFile = fname;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
//document = builder.parse( new File(xmlFile) );
document = builder.parse(xmlFile);
currentDoc = document;
} catch (SAXException sxe) {
// Error generated during parsing
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
} catch (ParserConfigurationException pce) {
// Parser with specified options can't be built
pce.printStackTrace();
} catch (IOException ioe) {
// I/O error
ioe.printStackTrace();
}
// Set up the tree
setModel(new DomToTreeModelAdapter(document));
expandRow(1);
}
//
// Returns an array of the selected nodes
//
public Object[] getSelection() {
Hashtable hashNodes = new Hashtable();
Vector vnodes = new Vector();
TreePath[] selectionPath = getSelectionPaths();
DomToTreeModelAdapter model = new DomToTreeModelAdapter(currentDoc);
for (int s=0; s < getSelectionCount(); s++) {
AdapterNode temp = null;
boolean leafFound = false;
for (int i=0; i < selectionPath[s].getPathCount(); i++) {
AdapterNode node = (AdapterNode) selectionPath[s].getPathComponent(i);
if (node != null) {
if (node.getAttributes() != null) {
if (model.isLeaf(node)) {
if (! hashNodes.containsKey(node.toString())) {
hashNodes.put(node.toString(),node.toString());
vnodes.addElement(node);
leafFound = true;
}
} else if (node.getNodeName().equals(ELEMENT_DATASET)) {
if (! hashNodes.containsKey(node.toString())) {
temp = node;
}
}
}
}
}
if ((! leafFound) && (temp != null)) {
hashNodes.put(temp.toString(),temp.toString());
vnodes.addElement(temp);
}
temp = null;
}
// toArray doesn't exist in JDK1.1
// return vnodes.toArray();
Object[] vnodeArray = new Object[vnodes.size()];
vnodes.copyInto(vnodeArray);
return vnodeArray;
}
//
// Returns the number of desired URL attributes found in the node
//
public int numDesiredURLAttributes(AdapterNode node) {
if ((node == null) || (node.getAttributes() == null)) return 0;
int count = 0;
for (int i=0; i < desiredURLAttributes.length; i++) {
if (node.getAttributes().getNamedItem(desiredURLAttributes[i]) != null) {
count++;
}
}
return count;
}
//
// Removes all Constraints
//
public void removeConstraints() {
setModel(new DomToTreeModelAdapter(document));
expandRow(1);
}
//
// Constrains the tree
//
public int constrainTree(Object[] keywords_G1, String logic_G1,
String logic_between,
Object[] keywords_G2, String logic_G2) {
// setup regular expressions
REMatch match;
RE[] search_G1 = new RE[keywords_G1.length];
RE[] search_G2 = new RE[keywords_G2.length];
try {
for (int i=0; i < keywords_G1.length; i++) {
search_G1[i] = new RE(keywords_G1[i].toString(),RE.REG_ICASE);
}
for (int i=0; i < keywords_G2.length; i++) {
search_G2[i] = new RE(keywords_G2[i].toString(),RE.REG_ICASE);
}
} catch(Exception e) {}
// setup logic
boolean init_remove_G1 = true;
if (logic_G1.equalsIgnoreCase("AND")) {
init_remove_G1 = false;
} else if (logic_G1.equalsIgnoreCase("OR")) {
init_remove_G1 = true;
}
boolean init_remove_G2 = true;
if (logic_G2.equalsIgnoreCase("AND")) {
init_remove_G2 = false;
} else if (logic_G2.equalsIgnoreCase("OR")) {
init_remove_G2 = true;
}
// Check for a null search
boolean nosearch = false;
boolean g1null = false;
boolean g2null = false;
if ( ((keywords_G1.length == 0) || ((keywords_G1.length == 1) && (keywords_G1[0].toString().equals("")) )) ) {
logic_between = "AND"; // AND it
g1null = true;
}
if ( ((keywords_G2.length == 0) || ((keywords_G2.length == 1) && (keywords_G2[0].toString().equals("")) )) ) {
logic_between = "AND"; // AND it
g2null = true;
}
if (g1null && g2null) {
nosearch = true;
}
if (! nosearch) {
// search tree
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document nDoc;
try {
DocumentBuilder builder = factory.newDocumentBuilder();
nDoc = builder.parse( new File(xmlFile) );
} catch(Exception e) {return SEARCH_ERROR;}
AdapterNode newDoc = new AdapterNode(nDoc);
AdapterNode root = newDoc.getChild(0);
int provcount = root.childCount();
int provpos = 0;
for (int p=0; p < provcount; p++) { // provider level
AdapterNode prov = root.getChild(provpos);
int dsetcount = prov.childCount();
int dsetpos = 0;
for (int d=0; d < dsetcount; d++) { // dataset level
AdapterNode dset = prov.getChild(dsetpos);
if ( dset.isLeaf() ) {
boolean remove_G1 = init_remove_G1;
for (int k=0; k < keywords_G1.length; k++) {
match = search_G1[k].getMatch( dset.getAttributes().getNamedItem(ATTR_NAME).getNodeValue() );
if (match != null) {
if (logic_G1.equalsIgnoreCase("OR")) {
remove_G1=false;
}
} else {
if (logic_G1.equalsIgnoreCase("AND")) {
remove_G1=true;
}
}
}
boolean remove_G2 = init_remove_G2;
for (int k=0; k < keywords_G2.length; k++) {
match = search_G2[k].getMatch( dset.getAttributes().getNamedItem(ATTR_NAME).getNodeValue() );
if (match != null) {
if (logic_G2.equalsIgnoreCase("OR")) {
remove_G2=false;
}
} else {
if (logic_G2.equalsIgnoreCase("AND")) {
remove_G2=true;
}
}
}
boolean remove = false;
if (logic_between.equalsIgnoreCase("AND")) {
remove = remove_G1 || remove_G2;
} else if (logic_between.equalsIgnoreCase("OR")) {
remove = remove_G1 && remove_G2;
}
if (remove == true) {
prov.removeChild(dsetpos);
} else {
dsetpos++;
}
} else {
int subdsetcount = dset.childCount();
int subdsetpos = 0;
for (int s=0; s < subdsetcount; s++) { // subdataset level
AdapterNode subdset = dset.getChild(subdsetpos);
boolean remove_G1 = init_remove_G1;
for (int k=0; k < keywords_G1.length; k++) {
match = search_G1[k].getMatch( subdset.getAttributes().getNamedItem(ATTR_NAME).getNodeValue() );
if (match != null) {
if (logic_G1.equalsIgnoreCase("OR")) {
remove_G1=false;
}
} else {
if (logic_G1.equalsIgnoreCase("AND")) {
remove_G1=true;
}
}
}
boolean remove_G2 = init_remove_G2;
for (int k=0; k < keywords_G2.length; k++) {
match = search_G2[k].getMatch( subdset.getAttributes().getNamedItem(ATTR_NAME).getNodeValue() );
if (match != null) {
if (logic_G2.equalsIgnoreCase("OR")) {
remove_G2=false;
}
} else {
if (logic_G2.equalsIgnoreCase("AND")) {
remove_G2=true;
}
}
}
boolean remove = false;
if (logic_between.equalsIgnoreCase("AND")) {
remove = remove_G1 || remove_G2;
} else if (logic_between.equalsIgnoreCase("OR")) {
remove = remove_G1 && remove_G2;
}
if (remove == true) {
dset.removeChild(subdsetpos);
} else {
subdsetpos++;
}
}
if (dset.childCount() == 0) { // no subdatasets left under this dataset?
prov.removeChild(dsetpos);
} else {
dsetpos++;
}
}
}
if (prov.childCount() == 0) { // no datasets left under this provider?
root.removeChild(provpos);
} else {
provpos++;
}
}
if (root.childCount() == 0) {
return SEARCH_NO_MATCH;
} else {
currentDoc = (Document) newDoc.getFirstChild().getParentNode();
DomToTreeModelAdapter newTree = new DomToTreeModelAdapter(currentDoc);
setModel(newTree);
expandRow(1);
return SEARCH_MATCH_FOUND;
}
} else {
return SEARCH_NULL;
}
}
// An array of names for DOM node-types
// (Array indexes = nodeType() values.)
static final String[] typeName = {
"none",
"Element",
"Attr",
"Text",
"CDATA",
"EntityRef",
"Entity",
"ProcInstr",
"Comment",
"Document",
"DocType",
"DocFragment",
"Notation",
};
static final int ELEMENT_TYPE = 1; // Element
static final int ATTR_TYPE = 2;
static final int TEXT_TYPE = 3;
static final int CDATA_TYPE = 4;
static final int ENTITYREF_TYPE = 5;
static final int ENTITY_TYPE = 6;
static final int PROCINSTR_TYPE = 7;
static final int COMMENT_TYPE = 8;
static final int DOCUMENT_TYPE = 9;
static final int DOCTYPE_TYPE = 10;
static final int DOCFRAG_TYPE = 11;
static final int NOTATION_TYPE = 12;
//
// Checks to see if we want to display this element
//
public boolean treeElement(String elementName) {
for (int i=0; i<treeElementNames.length; i++) {
if ( elementName.equals(treeElementNames[i]) ) {
return true;
}
}
return false;
}
//
// DOM node Adapter
//
public class AdapterNode
{
private org.w3c.dom.Node domNode;
// Construct an Adapter node from a DOM node
public AdapterNode(org.w3c.dom.Node node) {
domNode = node;
}
// Return a string that identifies this node in the tree
public String toString() {
String s = "";
String nodeName = domNode.getNodeName();
if (! nodeName.startsWith("#")) {
if (nodeName.equals(ELEMENT_ROOT)) {
s += rootTitle;
} else {
// Trim the value to get rid of NL's at the front
String t = content().trim();
int x = t.indexOf("\n");
if (x >= 0) t = t.substring(0, x);
s += " " + t;
}
} else {
if (nodeName.startsWith("#document")) {
s += listTitle;
}
}
return s;
}
public String content() {
String s = "";
if (domNode.getAttributes() != null) {
if (domNode.getAttributes().getLength() > 0) {
for (int i=0; i < desiredTreeAttributes.length; i++) {
if (domNode.getAttributes().getNamedItem(desiredTreeAttributes[i]) != null) {
if (desiredTreeAttributes[i] == ATTR_NAME) {
s += domNode.getAttributes().getNamedItem(desiredTreeAttributes[i]).getNodeValue();
}
}
}
}
}
return s;
}
public NamedNodeMap getAttributes() {
return domNode.getAttributes();
}
public String getNodeName() {
return domNode.getNodeName();
}
public String getNodeValue() {
return domNode.getNodeValue();
}
public Node getParentNode() {
return domNode.getParentNode();
}
public NodeList getChildNodes() {
return domNode.getChildNodes();
}
public Node getFirstChild() {
return domNode.getFirstChild();
}
public Node removeChild(int searchIndex) {
//Note: JTree index is zero-based.
org.w3c.dom.Node node = domNode.getChildNodes().item(searchIndex);
// Return Nth displayable node
int elementNodeIndex = 0;
for (int i=0; i<domNode.getChildNodes().getLength(); i++) {
node = domNode.getChildNodes().item(i);
if (node.getNodeType() == ELEMENT_TYPE
&& treeElement( node.getNodeName() )
&& elementNodeIndex++ == searchIndex)
{
break;
}
}
return domNode.removeChild(node);
}
public boolean isLeaf() {
if (childCount() > 0) return false;
return true;
}
public int index(AdapterNode child) {
//System.err.println("Looking for index of " + child);
int count = childCount();
for (int i=0; i<count; i++) {
AdapterNode n = (AdapterNode) this.getChild(i);
if (child == n) return i;
}
return -1; // Should never get here.
}
public AdapterNode getChild(int searchIndex) {
//Note: JTree index is zero-based.
org.w3c.dom.Node node = domNode.getChildNodes().item(searchIndex);
// Return Nth displayable node
int elementNodeIndex = 0;
for (int i=0; i<domNode.getChildNodes().getLength(); i++) {
node = domNode.getChildNodes().item(i);
if (node.getNodeType() == ELEMENT_TYPE
&& treeElement( node.getNodeName() )
&& elementNodeIndex++ == searchIndex)
{
break;
}
}
return new AdapterNode(node);
}
public int childCount() {
int count = 0;
for (int i=0; i<domNode.getChildNodes().getLength(); i++) {
org.w3c.dom.Node node = domNode.getChildNodes().item(i);
if (node.getNodeType() == ELEMENT_TYPE
&& treeElement( node.getNodeName() ))
{
++count; // count only the nodes we want
}
}
return count;
}
} // AdapterNode
//
// This adapter converts the current Document (a DOM) into
// a JTree model.
//
public class DomToTreeModelAdapter implements javax.swing.tree.TreeModel
{
private Document domDoc;
// Constructor
public DomToTreeModelAdapter(Document doc) {
domDoc = doc;
}
// Basic TreeModel operations
public Object getRoot() {
return new AdapterNode(domDoc);
}
public boolean isLeaf(Object aNode) {
// Return true for any node with no children
AdapterNode node = (AdapterNode) aNode;
return node.isLeaf();
}
public int getChildCount(Object parent) {
AdapterNode node = (AdapterNode) parent;
return node.childCount();
}
public Object getChild(Object parent, int index) {
AdapterNode node = (AdapterNode) parent;
return node.getChild(index);
}
public int getIndexOfChild(Object parent, Object child) {
AdapterNode node = (AdapterNode) parent;
return node.index((AdapterNode) child);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// Null. We won't be making changes in the GUI
// If we did, we would ensure the new value was really new
// and then fire a TreeNodesChanged event.
}
private Vector listenerList = new Vector();
public void addTreeModelListener( TreeModelListener listener ) {
if ( listener != null && ! listenerList.contains( listener ) ) {
listenerList.addElement( listener );
}
}
public void removeTreeModelListener( TreeModelListener listener ) {
if ( listener != null ) {
listenerList.removeElement( listener );
}
}
} // DomToTreeModelAdapter
} // DOMTree