1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package dom.traversal;
18
19 import java.awt.BorderLayout;
20 import java.awt.Dimension;
21 import java.awt.event.ActionEvent;
22 import java.awt.event.ActionListener;
23 import java.util.Enumeration;
24 import java.util.Hashtable;
25
26 import javax.swing.BorderFactory;
27 import javax.swing.JButton;
28 import javax.swing.JCheckBox;
29 import javax.swing.JFrame;
30 import javax.swing.JList;
31 import javax.swing.JPanel;
32 import javax.swing.JScrollPane;
33 import javax.swing.JTextArea;
34 import javax.swing.JTextField;
35 import javax.swing.event.ListSelectionEvent;
36 import javax.swing.event.ListSelectionListener;
37 import javax.swing.event.TreeSelectionEvent;
38 import javax.swing.event.TreeSelectionListener;
39 import javax.swing.tree.DefaultTreeModel;
40 import javax.swing.tree.MutableTreeNode;
41 import javax.swing.tree.TreeNode;
42 import javax.swing.tree.TreePath;
43 import javax.swing.tree.TreeSelectionModel;
44
45 import org.apache.xerces.parsers.DOMParser;
46 import org.w3c.dom.DOMException;
47 import org.w3c.dom.Document;
48 import org.w3c.dom.Node;
49 import org.w3c.dom.traversal.DocumentTraversal;
50 import org.w3c.dom.traversal.NodeFilter;
51 import org.w3c.dom.traversal.NodeIterator;
52 import org.xml.sax.ErrorHandler;
53 import org.xml.sax.SAXException;
54 import org.xml.sax.SAXParseException;
55
56 import ui.DOMTreeFull;
57
58 /** This class shows a DOM Document in a JTree, and presents controls
59 * which allow the user to create and view the progress of a NodeIterator
60 * in the DOM tree.
61 */
62 public class IteratorView
63 extends JFrame
64 implements ActionListener {
65
66 private static final long serialVersionUID = 3256726186452662580L;
67
68 Document document;
69 TreeNode lastSelected;
70 DOMParser parser;
71 JTextArea messageText;
72 JScrollPane messageScroll;
73 DOMTreeFull jtree;
74 NodeIterator iterator;
75 NameNodeFilter nameNodeFilter;
76
77 JButton nextButton;
78 JButton prevButton;
79 JButton removeButton;
80 JButton addButton;
81 JTextField addText;
82 JButton newIterator;
83 JList whatToShow;
84 JCheckBox match;
85 JTextField nameFilter;
86 String whatArray[] = new String [] {
87 "ALL",
88 "ELEMENT",
89 "ATTRIBUTE",
90 "TEXT",
91 "CDATA_SECTION",
92 "ENTITY_REFERENCE",
93 "ENTITY",
94 "PROCESSING_INSTRUCTION",
95 "COMMENT",
96 "DOCUMENT",
97 "DOCUMENT_TYPE",
98 "DOCUMENT_FRAGMENT",
99 "NOTATION"
100 };
101 JCheckBox expandERs;
102
103 Hashtable treeNodeMap = new Hashtable();
104
105
106 /** main */
107 public static void main (String args[]) {
108
109 if (args.length > 0) {
110 String filename = args[0];
111 try {
112 IteratorView frame = new IteratorView(filename) ;
113 frame.addWindowListener(new java.awt.event.WindowAdapter() {
114 public void windowClosing(java.awt.event.WindowEvent e) {
115 System.exit(0);
116 }
117 });
118 frame.setSize(640, 480);
119 frame.setVisible(true);
120 } catch (Exception e) {
121 e.printStackTrace(System.err);
122 }
123 }
124 }
125
126 /** Constructor */
127 public IteratorView (String filename) {
128 super("IteratorView: "+filename);
129 try {
130 parser = new DOMParser();
131 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
132 parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
133 Errors errors = new Errors();
134 parser.setErrorHandler(errors);
135 parser.parse(filename);
136 document = parser.getDocument();
137
138 if (!document.isSupported("Traversal", "2.0")) {
139 // This cannot happen with ou DOMParser...
140 throw new RuntimeException("This DOM Document does not support Traversal");
141 }
142
143 // jtree UI setup
144 jtree = new DOMTreeFull((Node)document);
145 jtree.getSelectionModel().setSelectionMode
146 (TreeSelectionModel.SINGLE_TREE_SELECTION);
147 jtree.setRootVisible(false);
148
149 // Listen for when the selection changes, call nodeSelected(node)
150 jtree.addTreeSelectionListener(
151 new TreeSelectionListener() {
152 public void valueChanged(TreeSelectionEvent e) {
153 TreePath path = (TreePath)e.getPath();
154 TreeNode treeNode = (TreeNode)path.getLastPathComponent();
155 if(jtree.getSelectionModel().isPathSelected(path))
156 nodeSelected(treeNode);
157 }
158 }
159 );
160
161
162 //expandTree();
163
164
165 // controls
166
167 //iterate panel
168 JPanel iteratePanel = new JPanel();
169 iteratePanel.setBorder(BorderFactory.createCompoundBorder(
170 BorderFactory.createTitledBorder("Iterate"),
171 BorderFactory.createEmptyBorder(4, 4, 4, 4)
172 ));
173
174 prevButton = new JButton("Previous");
175 iteratePanel.add(prevButton);
176 prevButton.addActionListener(this);
177
178 nextButton = new JButton("Next");
179 iteratePanel.add(nextButton);
180 nextButton.addActionListener(this);
181
182 //DOM tree panel
183 JPanel domPanel = new JPanel();
184 domPanel.setLayout(new BorderLayout());
185 domPanel.setBorder(BorderFactory.createCompoundBorder(
186 BorderFactory.createTitledBorder("Selected Node"),
187 BorderFactory.createEmptyBorder(4, 4, 4, 4)
188 ));
189
190 removeButton = new JButton("Remove Selected Node");
191 domPanel.add(removeButton, BorderLayout.NORTH);
192 removeButton.addActionListener(this);
193
194 addButton = new JButton("Add Text Node");
195 addText = new JTextField(10);
196 domPanel.add(addButton, BorderLayout.CENTER);
197 domPanel.add(addText, BorderLayout.SOUTH);
198 addButton.addActionListener(this);
199
200 // iterator settings
201 JPanel settingsPanel = new JPanel();
202 settingsPanel.setLayout(new BorderLayout());
203 settingsPanel.setBorder(BorderFactory.createCompoundBorder(
204 BorderFactory.createTitledBorder("Iterator Settings"),
205 BorderFactory.createEmptyBorder(4, 4, 4, 4)
206 ));
207 JPanel iteratorPanel = new JPanel();
208 newIterator = new JButton("createNodeIterator");
209 expandERs = new JCheckBox("expandEntityReferences");
210 iteratorPanel.add(newIterator);
211 expandERs.setSelected(true);
212 iteratorPanel.add(expandERs);
213 settingsPanel.add(iteratorPanel, BorderLayout.NORTH);
214 newIterator.addActionListener(this);
215
216 JPanel whatPanel = new JPanel();
217 whatPanel.setBorder(BorderFactory.createCompoundBorder(
218 BorderFactory.createTitledBorder("whatToShow"),
219 BorderFactory.createEmptyBorder(4, 4, 4, 4)
220 ));
221 whatToShow = new JList(DOMTreeFull.whatArray);
222 JScrollPane whatScroll =
223 new JScrollPane(whatToShow) {
224 private static final long serialVersionUID = 3546357344813724213L;
225 public Dimension getPreferredSize(){
226 return new Dimension(200, 75 );
227 }
228 };
229
230 whatPanel.add(whatScroll);
231
232
233 JPanel filterPanel = new JPanel();
234 filterPanel.setBorder(BorderFactory.createCompoundBorder(
235 BorderFactory.createTitledBorder("NodeNameFilter"),
236 BorderFactory.createEmptyBorder(4, 4, 4, 4)
237 ));
238 filterPanel.setLayout(new BorderLayout());
239 match = new JCheckBox("match/ignore node name", true);
240 nameFilter = new JTextField(10);
241 filterPanel.add(match, BorderLayout.NORTH);
242 filterPanel.add(nameFilter, BorderLayout.SOUTH);
243
244 settingsPanel.add(whatPanel, BorderLayout.WEST);
245 settingsPanel.add(filterPanel, BorderLayout.EAST);
246
247
248 // Listen for when the selection changes, call nodeSelected(node)
249 whatToShow.addListSelectionListener(
250 new ListSelectionListener() {
251 public void valueChanged(ListSelectionEvent e) {
252 // do nothing on selection...
253 }
254 }
255 );
256
257
258 JPanel controlsPanel = new JPanel(new BorderLayout());
259 JPanel buttonsPanel = new JPanel(new BorderLayout());
260 buttonsPanel.add(iteratePanel, BorderLayout.NORTH);
261 buttonsPanel.add(domPanel, BorderLayout.SOUTH);
262 controlsPanel.add(buttonsPanel, BorderLayout.WEST);
263 controlsPanel.add(settingsPanel, BorderLayout.CENTER);
264
265 controlsPanel.setBorder(BorderFactory.createCompoundBorder(
266 BorderFactory.createTitledBorder("Controls"),
267 BorderFactory.createEmptyBorder(4, 4, 4, 4)
268 ));
269
270
271 // tree panel
272 JPanel treePanel = new JPanel(new BorderLayout());
273
274 JScrollPane treeScroll = new JScrollPane(jtree) ;
275 treeScroll.setBorder(BorderFactory.createCompoundBorder(
276 BorderFactory.createTitledBorder("Tree View"),
277 BorderFactory.createEmptyBorder(4, 4, 4, 4)
278 ));
279
280 // message text UI setup
281 messageText = new JTextArea(3,5);
282
283 JPanel messagePanel = new JPanel(new BorderLayout());
284 messageScroll = new JScrollPane(messageText);
285 messagePanel.add(messageScroll);
286 messagePanel.setBorder(BorderFactory.createCompoundBorder(
287 BorderFactory.createTitledBorder("Messages"),
288 BorderFactory.createEmptyBorder(4, 4, 4, 4)
289 ));
290
291 JPanel mainPanel = new JPanel();
292 mainPanel.setLayout(new BorderLayout());
293 mainPanel.add(controlsPanel, BorderLayout.NORTH);
294 mainPanel.add(treeScroll, BorderLayout.CENTER);
295 mainPanel.add(messagePanel, BorderLayout.SOUTH);
296 getContentPane().add(mainPanel);
297
298 Hashtable errorNodes = errors.getErrorNodes();
299 Enumeration elements = errorNodes.elements();
300 while (elements.hasMoreElements()) {
301 //*** append errors to messageText
302 messageText.append( (String)elements.nextElement());
303 }
304
305 // This cast must work, because we have tested above
306 // with document.isSupported("Traversal")
307 iterator = ((DocumentTraversal)document).
308 createNodeIterator(
309 document,
310 NodeFilter.SHOW_ALL,
311 new NameNodeFilter(),
312 true);
313
314 } catch (Exception e) {
315 e.printStackTrace(System.err);
316 }
317 }
318
319 public void actionPerformed(ActionEvent e) {
320
321 if (e.getSource() == newIterator) {
322 Node node = document;
323
324 // whatToShow section
325 int [] indices = whatToShow.getSelectedIndices();
326 int mask = 0x0;
327 for (int i = 0; i < indices.length; i++) {
328 if (indices[i] == 0) {
329 mask = 0xFFFF;
330 break;
331 } else {
332 mask = mask | 1<<indices[i]-1;
333 }
334 }
335 // filter section
336 String nameText = nameFilter.getText();
337 boolean matched = match.isSelected();
338 if (nameNodeFilter==null) {
339 nameNodeFilter = new NameNodeFilter();
340 }
341 if (nameText.equals("")) {
342 setMessage("NodeNameFilter name is \"\". Assuming null.");
343 nameText = null;
344 }
345 nameNodeFilter.setName(nameText);
346 nameNodeFilter.setMatch(matched);
347
348 if (iterator !=null) iterator.detach();
349 boolean expand = expandERs.isSelected();
350 iterator = ((DocumentTraversal)document).
351 createNodeIterator(
352 node,
353 (short)mask,
354 nameNodeFilter,
355 expand);
356 setMessage("doc.createNodeIterator("+
357 " root="+node+
358 ", whatToShow="+mask+
359 ", match="+matched+
360 ", name="+nameText+")"
361 );
362 return;
363
364 }
365
366 if (e.getSource() == addButton) {
367
368 String text = addText.getText();
369
370 if (text==null) return;
371
372 TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
373 if (treeNode == null) {
374 messageText.append("Must select a tree component to add a child to it.");
375 return;
376 }
377 TreePath path = new TreePath(
378 ((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
379 if (path == null) {
380 setMessage("Could not create a path.");
381 return;
382 }
383 if(!jtree.getSelectionModel().isPathSelected(path))
384 return;
385 Node node = jtree.getNode(treeNode);
386 Node textNode = document.createTextNode(text);
387 try {
388 node.appendChild(textNode);
389 } catch (DOMException dome) {
390 setMessage("DOMException:"+dome.code+", "+dome);
391 return;
392 }
393 ((DOMTreeFull.Model)jtree.getModel()).insertNode(textNode, (MutableTreeNode)treeNode);
394
395 return;
396 }
397 if (e.getSource() == nextButton) {
398 Node node = iterator.nextNode();
399 if (node==null) {
400 setMessage("iterator.nextNode() == null");
401 return;
402 }
403
404 setMessage("iterator.nextNode() == "+node);
405
406 TreeNode treeNode = jtree.getTreeNode(node);
407 if (treeNode == null) {
408 setMessage("No JTree TreeNode for Node name:" + node.getNodeName());
409 return;
410 }
411
412 TreePath path = new TreePath(
413 ((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
414 jtree.requestFocus();
415 jtree.setSelectionPath(path);
416 jtree.scrollPathToVisible(path);
417 return;
418 }
419
420 if (e.getSource() == prevButton) {
421 Node node = iterator.previousNode();
422 if (node==null) {
423 setMessage("iterator.previousNode() == null");
424 return;
425 }
426
427 setMessage("iterator.previousNode() == "+node);
428
429 TreeNode treeNode = jtree.getTreeNode(node);
430 if (treeNode == null) {
431 setMessage("No JTree TreeNode for Node name:" + node.getNodeName());
432 return;
433 }
434
435 TreePath path = new TreePath(
436 ((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
437 jtree.requestFocus();
438 jtree.setSelectionPath(path);
439 jtree.scrollPathToVisible(path);
440 return;
441 }
442 if (e.getSource() == removeButton) {
443
444 /** If the node is not selected don't remove. */
445 TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
446 if (treeNode == null) {
447 messageText.append("Must select a tree component to remove it.");
448 return;
449 }
450 TreePath path = new TreePath(
451 ((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
452 if (path == null) {
453 setMessage("Could not create a path.");
454 return;
455 }
456 if(!jtree.getSelectionModel().isPathSelected(path))
457 return;
458 Node node = jtree.getNode(treeNode);
459 if (node == null) return;
460 Node parent = node.getParentNode();
461 if (parent == null) return;
462
463 parent.removeChild(node);
464
465 ((DefaultTreeModel)jtree.getModel()).removeNodeFromParent((MutableTreeNode)treeNode);
466 return;
467 }
468
469 }
470
471 /** Helper function to set messages */
472 void setMessage(String string) {
473 messageText.selectAll();
474 messageText.cut();
475 messageText.append(string);
476 messageText.setCaretPosition(0);
477 }
478
479 /** called when our JTree's nodes are selected.
480 */
481 void nodeSelected(TreeNode treeNode) {
482
483 lastSelected = treeNode;
484 Node node = jtree.getNode(treeNode);
485
486 System.out.println("nodeSelected.node="+node);
487 if (node == null) return;
488
489 setMessage(DOMTreeFull.toString(node));
490 }
491
492 /** Utility function to expand the jtree */
493 void expandTree() {
494 for (int i = 0; i < jtree.getRowCount(); i++) {
495 jtree.expandRow(i);
496 }
497 }
498
499 class Errors implements ErrorHandler {
500
501 Hashtable errorNodes = new Hashtable();
502
503 public void warning(SAXParseException ex) {
504 store(ex, "[Warning]");
505 }
506
507 public void error(SAXParseException ex) {
508 store(ex, "[Error]");
509 }
510
511 public void fatalError(SAXParseException ex) throws SAXException {
512 store(ex, "[Fatal Error]");
513 }
514
515 public Hashtable getErrorNodes() {
516 return errorNodes;
517 }
518
519 public Object getError(Node node) {
520 return errorNodes.get(node);
521 }
522
523 public void clearErrors() {
524 errorNodes.clear();
525 }
526
527 void store(SAXParseException ex, String type) {
528
529 // build error text
530 String errorString= type+" at line number, "+ex.getLineNumber()
531 +": "+ex.getMessage()+"\n";
532 Node currentNode = null;
533 try {
534 currentNode = (Node)parser.getProperty("http://apache.org/xml/properties/dom-node");
535 } catch (SAXException se) {
536 System.err.println(se.getMessage());
537 return;
538 }
539 if (currentNode == null) return;
540
541 // accumulate any multiple errors per node in the Hashtable.
542 String previous = (String) errorNodes.get(currentNode);
543 if (previous != null)
544 errorNodes.put(currentNode, previous +errorString);
545 else
546 errorNodes.put(currentNode, errorString);
547 }
548 }
549
550 }