001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.contrib.poibrowser;
019:
020: import java.io.IOException;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import javax.swing.tree.DefaultMutableTreeNode;
025: import javax.swing.tree.MutableTreeNode;
026:
027: import org.apache.poi.hpsf.HPSFException;
028: import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
029: import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
030: import org.apache.poi.poifs.filesystem.DocumentInputStream;
031: import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
032:
033: /**
034: * <p>Organizes document information in a tree model in order to be
035: * e.g. displayed in a Swing {@link javax.swing.JTree}. An instance of this
036: * class is created with a root tree node ({@link MutableTreeNode}) and
037: * registered as a {@link POIFSReaderListener} with a {@link
038: * org.apache.poi.poifs.eventfilesystem.POIFSReader}. While the latter processes
039: * a POI filesystem it calls this class' {@link #processPOIFSReaderEvent} for
040: * each document it has been registered for. This method appends the document it
041: * processes at the appropriate position into the tree rooted at the
042: * above mentioned root tree node.</p>
043: *
044: * <p>The root tree node should be the root tree node of a {@link
045: * javax.swing.tree.TreeModel}.</p>
046: *
047: * <p>A top-level element in the tree model, i.e. an immediate child
048: * node of the root node, describes a POI filesystem as such. It is
049: * suggested to use the file's name (as seen by the operating system)
050: * but it could be any other string.</p>
051: *
052: * <p>The value of a tree node is a {@link DocumentDescriptor}. Unlike
053: * a {@link org.apache.poi.poifs.filesystem.POIFSDocument} which may be as heavy
054: * as many megabytes, an instance of {@link DocumentDescriptor} is a
055: * light-weight object and contains only some meta-information about a
056: * document.</p>
057: *
058: * @author Rainer Klute <a
059: * href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
060: * @version $Id: TreeReaderListener.java 489730 2006-12-22 19:18:16Z bayard $
061: * @since 2002-01-24
062: */
063: public class TreeReaderListener implements POIFSReaderListener {
064:
065: /**
066: * <p>The tree's root node. POI filesystems get attached to this
067: * node as children.</p>
068: */
069: protected MutableTreeNode rootNode;
070:
071: /**
072: * <p>Maps filenames and POI document paths to their associated
073: * tree nodes.</p>
074: */
075: protected Map pathToNode;
076:
077: /**
078: * <p>The name of the file this {@link TreeReaderListener}
079: * processes. It is used to identify a top-level element in the
080: * tree. Alternatively any other string can be used. It is just a
081: * label which should identify a POI filesystem.</p>
082: */
083: protected String filename;
084:
085: /**
086: * <p>Creates a {@link TreeReaderListener} which should then be
087: * registered with a
088: * {@link org.apache.poi.poifs.eventfilesystem.POIFSReader}.</p>
089: *
090: * @param filename The name of the POI filesystem, i.e. the name
091: * of the file the POI filesystem resides in. Alternatively any
092: * other string can be used.
093: *
094: * @param rootNode All document information will be attached as
095: * descendands to this tree node.
096: */
097: public TreeReaderListener(final String filename,
098: final MutableTreeNode rootNode) {
099: this .filename = filename;
100: this .rootNode = rootNode;
101: pathToNode = new HashMap(15); // Should be a reasonable guess.
102: }
103:
104: /** <p>The number of bytes to dump.</p> */
105: private int nrOfBytes = 50;
106:
107: public void setNrOfBytes(final int nrOfBytes) {
108: this .nrOfBytes = nrOfBytes;
109: }
110:
111: public int getNrOfBytes() {
112: return nrOfBytes;
113: }
114:
115: /**
116: * <p>A document in the POI filesystem has been opened for
117: * reading. This method retrieves properties of the document and
118: * adds them to a tree model.</p>
119: */
120: public void processPOIFSReaderEvent(final POIFSReaderEvent event) {
121: DocumentDescriptor d;
122: final DocumentInputStream is = event.getStream();
123: if (!is.markSupported())
124: throw new UnsupportedOperationException(is.getClass()
125: .getName()
126: + " does not support mark().");
127:
128: /* Try do handle this document as a property set. We receive
129: * an exception if is no property set and handle it as a
130: * document of some other format. We are not concerned about
131: * that document's details. */
132: try {
133: d = new PropertySetDescriptor(event.getName(), event
134: .getPath(), is, nrOfBytes);
135: } catch (HPSFException ex) {
136: d = new DocumentDescriptor(event.getName(),
137: event.getPath(), is, nrOfBytes);
138: } catch (Throwable t) {
139: System.err.println("Unexpected exception while processing "
140: + event.getName() + " in "
141: + event.getPath().toString());
142: t.printStackTrace(System.err);
143: throw new RuntimeException(t.getMessage());
144: }
145:
146: try {
147: is.close();
148: } catch (IOException ex) {
149: System.err.println("Unexpected exception while closing "
150: + event.getName() + " in "
151: + event.getPath().toString());
152: ex.printStackTrace(System.err);
153: }
154:
155: final MutableTreeNode parentNode = getNode(d.path, filename,
156: rootNode);
157: final MutableTreeNode nameNode = new DefaultMutableTreeNode(
158: d.name);
159: parentNode.insert(nameNode, 0);
160: final MutableTreeNode dNode = new DefaultMutableTreeNode(d);
161: nameNode.insert(dNode, 0);
162: }
163:
164: /**
165: * <p>Locates the parent node for a document entry in the tree
166: * model. If the parent node does not yet exist it will be
167: * created, too. This is done recursively, if needed.</p>
168: *
169: * @param path The tree node for this path is located.
170: *
171: * @param fsName The name of the POI filesystem. This is just a
172: * string which is displayed in the tree at the top lovel.
173: *
174: * @param root The root node.
175: */
176: private MutableTreeNode getNode(final POIFSDocumentPath path,
177: final String fsName, final MutableTreeNode root) {
178: MutableTreeNode n = (MutableTreeNode) pathToNode.get(path);
179: if (n != null)
180: /* Node found in map, just return it. */
181: return n;
182: if (path.length() == 0) {
183: /* This is the root path of the POI filesystem. Its tree
184: * node is resp. must be located below the tree node of
185: * the POI filesystem itself. This is a tree node with the
186: * POI filesystem's name (this the operating system file's
187: * name) as its key it the path-to-node map. */
188: n = (MutableTreeNode) pathToNode.get(fsName);
189: if (n == null) {
190: /* A tree node for the POI filesystem does not yet
191: * exist. */
192: n = new DefaultMutableTreeNode(fsName);
193: pathToNode.put(fsName, n);
194: root.insert(n, 0);
195: }
196: return n;
197: } else {
198: /* The path is somewhere down in the POI filesystem's
199: * hierarchy. We need the tree node of this path's parent
200: * and attach our new node to it. */
201: final String name = path.getComponent(path.length() - 1);
202: final POIFSDocumentPath parentPath = path.getParent();
203: final MutableTreeNode parentNode = getNode(parentPath,
204: fsName, root);
205: n = new DefaultMutableTreeNode(name);
206: pathToNode.put(path, n);
207: parentNode.insert(n, 0);
208: return n;
209: }
210: }
211:
212: }
|