001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: DocumentDataSource.java,v $
023   Revision 1.7  2004/05/31 07:30:26  markl
024   Final cleanup and bugfixes of kiwi.ui.model.
025
026   Revision 1.6  2004/03/23 06:49:44  markl
027   Use Boolean.valueOf(), not new Boolean()
028
029   Revision 1.5  2003/01/19 09:33:06  markl
030   Javadoc & comment header updates.
031
032   Revision 1.4  2001/03/12 04:11:41  markl
033   Source code cleanup.
034
035   Revision 1.3  2000/07/31 02:02:13  markl
036   Modified to use a document icon for non-expandable nodes.
037
038   Revision 1.2  1999/01/10 03:12:19  markl
039   added GPL header & RCS tag
040   ----------------------------------------------------------------------------
041*/
042
043package kiwi.ui.model;
044
045import java.io.*;
046import java.net.*;
047import java.util.*;
048import javax.swing.*;
049
050import kiwi.util.*;
051
052/** This class is an implementation of <code>TreeDataSource</code>
053  * in which tree nodes represent HTML documents that are loaded as system
054  * resources.
055  * <p>
056  * Documents are loaded using the provided <code>ResourceManager</code>. The
057  * default base path for the documents is "docs/", and since they are loaded
058  * as URL resources, they should be located relative to "html/docs/" which in
059  * turn will be relative to the <code>ResourceManager</code>'s resource anchor
060  * class. One form of the constructor allows an alternate base path to be
061  * specified.
062  * <p>
063  * Documents may be organized in a hierarchy; each expandable node in the
064  * hierarchy corresponds to a directory in the resource file tree. Each
065  * directory (including the root directory, "docs/") is expected to contain
066  * an index file named "_index.txt" describing the child nodes of that
067  * directory. Nodes are listed in this file, one per line. Each line should
068  * include the following fields, delimited by vertical bar characters (|):
069  * <p>
070  * <dl>
071  * <dt>Icon name
072  * <dd>The name of the icon for this node. If an asterisk (*) is specified
073  * for the name, a default icon will be used.
074  * <dt>Alternate Icon name
075  * <dd>The name of an alternate icon for this node. This is the icon that
076  * is used to display expanded nodes. If an asterisk (*) is specified for the
077  * name, a default icon will be used. If a dash (-) is specified for the name,
078  * the alternate icon will be the same as the normal icon (above).
079  * <dt>Expandability flag
080  * <dd>One of the characters '+' or '-', denoting expandable and
081  * non-expandable, respectively.
082  * <dt>Node label
083  * <dd>A human-readable, brief textual description of the node.
084  * <dt>File
085  * <dd>The file corresponding to this resource--either a directory name if
086  * this is an expandable node, or a filename if this is a leaf (document)
087  * node.
088  * </dl>
089  * <p>
090  * Here is an example entry:
091  * <p>
092  * <tt>book-closed.gif|book-open.gif|+|API Specification|api</tt>
093  *
094  * @see kiwi.util.ResourceManager
095  * @see kiwi.ui.DocumentBrowserView
096  * @see kiwi.ui.DocumentBrowserFrame
097  *
098  * @author Mark Lindner
099  */
100
101public class DocumentDataSource implements TreeDataSource
102  {
103  private ResourceManager resmgr;
104  private String basePath;
105  private DocumentNode root;
106  private static Icon DOCUMENT_ICON = KiwiUtils.getResourceManager()
107     .getIcon("document.gif");
108  private static Icon BOOKS_ICON = KiwiUtils.getResourceManager()
109     .getIcon("books.gif");
110  private static Icon UNKNOWN_ICON = KiwiUtils.getResourceManager()
111    .getIcon("document-unknown.gif");
112  private static Icon BOOK_OPEN_ICON = KiwiUtils.getResourceManager()
113    .getIcon("book-open.gif");
114  private static Icon BOOK_CLOSED_ICON = KiwiUtils.getResourceManager()
115    .getIcon("book-closed.gif");
116  private static final String INDEX_FILE = "_index.txt";
117  /** The default description of this set of documents. */
118  public static final String DEFAULT_DESCRIPTION = "Help Topics";
119  /** The default relative document base path. */
120  public static final String DEFAULT_BASEPATH = "docs/";
121  
122  /** Construct a new <code>DocumentDataSource</code> with a default
123    * description and base path.
124    *
125    * @param manager the <code>ResourceManager</code> that will be used to load
126    * index files for the tree.
127    */
128
129  public DocumentDataSource(ResourceManager manager)
130    {
131    this(manager, DEFAULT_DESCRIPTION, DEFAULT_BASEPATH);
132    }
133
134  /** Construct a new <code>DocumentDataSource</code> with the specified
135    * description and base path.
136    *
137    * @param manager The <code>ResourceManager</code> that will be used to load
138    * index files for the tree.
139    * @param description A brief description of this set of documents; this
140    * becomes the label for the root node in the tree.
141    */
142  
143  public DocumentDataSource(ResourceManager manager, String description,
144                            String basePath)
145    {
146    this.resmgr = manager;
147    if(! basePath.endsWith("/"))
148      basePath += "/";
149    this.basePath = basePath;
150
151    URL rootURL = resmgr.getURL(basePath + INDEX_FILE);
152    root = new DocumentNode(null, description, BOOKS_ICON, null, rootURL,
153                            true, "");
154    }
155
156  /** Get the root object. */
157
158  public Object getRoot()
159    {
160    return(root);
161    }
162
163  /** Get the children of a given node. */
164
165  public Object[] getChildren(Object node)
166    {
167    DocumentNode n = (DocumentNode)node;
168    Vector children = new Vector();
169
170    try
171      {
172      String s;
173      DocumentNode sect;
174
175      InputStream is = n.getURL().openStream();
176      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
177
178      while((s = reader.readLine()) != null)
179        {
180        if((sect = parseLine(n, s)) != null)
181          children.addElement(sect);
182        }
183      reader.close();
184      is.close();
185      }
186    catch(IOException ex)
187      {
188      }
189
190    Object childlist[] = new Object[children.size()];
191    children.copyInto(childlist);
192
193    return(childlist);
194    }
195
196  public boolean isExpandable(Object node)
197    { 
198    DocumentNode doc = (DocumentNode)node;
199
200    return(doc.isExpandable());
201    }
202
203  public Icon getIcon(Object node, boolean isExpanded)
204    {
205    DocumentNode doc = (DocumentNode)node;
206
207    return(isExpanded ? doc.getAltIcon() : doc.getIcon());
208    }
209
210  public String getLabel(Object node)
211    {
212    DocumentNode doc = (DocumentNode)node;
213
214    return(doc.getLabel());
215    }
216  
217  /** Get the value for a given property. */
218
219  public Object getValueForProperty(Object node, String property)
220    {
221    return(null);
222    }
223
224  /* parse a line of an index file */
225
226  private DocumentNode parseLine(DocumentNode parent, String line)
227    {
228    StringTokenizer st = new StringTokenizer(line, "|");
229    if(st.countTokens() != 5) return(null);
230
231    String file;
232    String iconName = st.nextToken();
233    String altIconName = st.nextToken();
234    boolean expandable = st.nextToken().equals("+");
235    URL url;
236
237    Icon icon = null, alticon = null;
238
239    if(iconName.equals("*"))
240      icon = (expandable ? BOOK_CLOSED_ICON : DOCUMENT_ICON);
241    else
242      icon = resmgr.getIcon(iconName);
243
244    if(altIconName.equals("*"))
245      alticon = (expandable ? BOOK_OPEN_ICON : DOCUMENT_ICON);
246    else if(!altIconName.equals("-"))
247      alticon = resmgr.getIcon(altIconName);
248
249    String label = st.nextToken();
250
251    try
252      {
253      String parentURL = parent.getURL().toString();
254      int idx = parentURL.lastIndexOf("/");
255      file = st.nextToken();
256      String temp = parentURL.substring(0, idx) + "/" + file;
257      if(expandable)
258        temp += "/" + INDEX_FILE;
259      url = new URL(temp);
260      }
261    catch(MalformedURLException ex)
262      {
263      return(null);
264      }
265
266    return(new DocumentNode(parent, label, icon, alticon, url, expandable,
267                            file));
268    }
269  
270  /* Internal class for managing help nodes. */
271
272  public class DocumentNode
273    {
274    private String label, file;
275    private Icon icon, alticon;
276    private URL url;
277    private boolean expandable;
278    private DocumentNode parent = null;
279
280    DocumentNode(DocumentNode parent, String label, Icon icon, Icon alticon,
281                 URL url, boolean expandable, String file)
282      {
283      this.label = label;
284      this.icon = ((icon != null) ? icon : UNKNOWN_ICON);
285      this.alticon = ((alticon != null) ? alticon : this.icon);
286      this.url = url;
287      this.expandable = expandable;
288      this.file = file;
289      }
290
291    public DocumentNode getParent()
292      {
293      return(parent);
294      }
295
296    public String getFile()
297      {
298      return(file);
299      }
300    
301    public boolean isExpandable()
302      {
303      return(expandable);
304      }
305
306    public String getLabel()
307      {
308      return(label);
309      }
310
311    public Icon getIcon()
312      {
313      return(icon);
314      }
315
316    public Icon getAltIcon()
317      {
318      return(alticon);
319      }
320
321    public URL getURL()
322      {
323      return(url);
324      }
325    }
326  
327  }
328
329/* end of source file */