/* * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE OR * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. */ import java.io.*; import java.net.*; import java.util.*; import javax.swing.*; import javax.swing.tree.*; import javax.swing.text.*; import javax.swing.text.html.*; import javax.swing.text.html.parser.*; /** * Parses the Netscape bookmarks file (NETSCAPE-Bookmark-file-1) into * BookmarkEntries's and BookmarkDirectories. *
* For the time being, this is a hack, there needs to be a more generic * API to this to allow adding/removing bookmarks and pulling from * different sources other than just Netscape. But for this example, this is * plenty good. *
While a hack, this is interesting in that it shows how you can use
* the parser provided in the javax.swing.text.html.parser package outside
* of the HTML package. The netscape format is a pseudo HTML file, pseudo
* in that there is no head/body. All the bookmarks are presented as
* DT's in a DL and the name of the directory is a DT. An instance of the
* parser is created, a callback is registered, and as the parser parses
* the file, nodes of the correct type are created.
*
* @author Scott Violet
*/
public class Bookmarks {
/** The root node the bookmarks are added to. */
private BookmarkDirectory root;
/**
* Creates a new Bookmarks object, with the entries coming from
* path.
*/
public Bookmarks(String path) {
root = new BookmarkDirectory("Bookmarks");
if (path != null) {
parse(path);
}
}
/**
* Returns the root of the bookmarks.
*/
public BookmarkDirectory getRoot() {
return root;
}
/**
* Adds the bookmarks in the file at path to the
* current root. This creates a ParserDelegator and uses a
* CallbackHandler to do the parser.
*/
protected void parse(String path) {
try {
BufferedReader reader = new BufferedReader(new FileReader
(path));
new ParserDelegator().parse(reader, new CallbackHandler(), true);
}
catch (IOException ioe) {
System.out.println("IOE: " + ioe);
JOptionPane.showMessageDialog(null, "Load Bookmarks",
"Unable to load bookmarks",
JOptionPane.ERROR_MESSAGE);
}
}
private static final short NO_ENTRY = 0;
private static final short BOOKMARK_ENTRY = 2;
private static final short DIRECTORY_ENTRY = 3;
/**
* The heart of the parsing. The parser parses the data and notifies
* a delegate, via the HTMLEditorKit.ParserCallback interface, as the
* data is parsed. When CallbackHandler receives notification it
* creates new BookmarkEntries or BookmarkDirectories.
*/
private class CallbackHandler extends HTMLEditorKit.ParserCallback {
/** Parent node that new entries are added to. */
private BookmarkDirectory parent;
/** The most recently parsed tag. */
private HTML.Tag tag;
/** The last tag encountered. */
private HTML.Tag lastTag;
/**
* The state, will be one of NO_ENTRY, DIRECTORY_ENTRY,
* or BOOKMARK_ENTRY.
*/
private short state;
/**
* Date for the next BookmarkDirectory node.
*/
private Date parentDate;
/**
* The values from the attributes are placed in here. When the
* text is encountered this is added to the node hierarchy and a
* new instance is created.
*/
private BookmarkEntry lastBookmark;
/**
* Creates the CallbackHandler.
*/
public CallbackHandler() {
parent = root;
lastBookmark = new BookmarkEntry();
}
//
// HTMLEditorKit.ParserCallback methods
//
/**
* Invoked when text in the html document is encountered. Based on
* the current state, this will either: do nothing
* (state == NO_ENTRY),
* create a new BookmarkEntry (state == BOOKMARK_ENTRY) or
* create a new
* BookmarkDirectory (state == DIRECTORY_ENTRY). If state is
* != NO_ENTRY, it is reset to NO_ENTRY after this is
* invoked.
*/
public void handleText(char[] data, int pos) {
switch (state) {
case NO_ENTRY:
break;
case BOOKMARK_ENTRY:
// URL.
{
lastBookmark.setName(new String(data));
parent.add(lastBookmark);
lastBookmark = new BookmarkEntry();
}
break;
case DIRECTORY_ENTRY:
// directory.
{
BookmarkDirectory newParent = new
BookmarkDirectory(new String(data));
newParent.setCreated(parentDate);
parent.add(newParent);
parent = newParent;
}
break;
default:
break;
}
state = NO_ENTRY;
}
/**
* Invoked when a start tag is encountered. Based on the tag
* this may update the BookmarkEntry and state, or update the
* parentDate.
*/
public void handleStartTag(HTML.Tag t, MutableAttributeSet a,
int pos) {
lastTag = tag;
tag = t;
if (t == HTML.Tag.A && lastTag == HTML.Tag.DT) {
long lDate;
// URL
URL url;
try {
url = new URL((String)a.getAttribute(HTML.Attribute.HREF));
} catch (MalformedURLException murle) {
url = null;
}
lastBookmark.setLocation(url);
// created
Date date;
try {
lDate = Long.parseLong((String)a.getAttribute("add_date"));
if (lDate != 0l) {
date = new Date(1000l * lDate);
}
else {
date = null;
}
} catch (Exception ex) {
date = null;
}
lastBookmark.setCreated(date);
// last visited
try {
lDate = Long.parseLong((String)a.
getAttribute("last_visit"));
if (lDate != 0l) {
date = new Date(1000l * lDate);
}
else {
date = null;
}
} catch (Exception ex) {
date = null;
}
lastBookmark.setLastVisited(date);
state = BOOKMARK_ENTRY;
}
else if (t == HTML.Tag.H3 && lastTag == HTML.Tag.DT) {
// new node.
try {
parentDate = new Date(1000l * Long.parseLong((String)a.
getAttribute("add_date")));
} catch (Exception ex) {
parentDate = null;
}
state = DIRECTORY_ENTRY;
}
}
/**
* Invoked when the end of a tag is encountered. If the tag is
* a DL, this will set the node that parents are added to the current
* nodes parent.
*/
public void handleEndTag(HTML.Tag t, int pos) {
if (t == HTML.Tag.DL && parent != null) {
parent = (BookmarkDirectory)parent.getParent();
}
}
}
/**
* BookmarkDirectory represents a directory containing other
* BookmarkDirectory's as well as BookmarkEntry's. It adds a name
* and created property to DefaultMutableTreeNode.
*/
public static class BookmarkDirectory extends DefaultMutableTreeNode {
/** Dates created. */
private Date created;
public BookmarkDirectory(String name) {
super(name);
}
public void setName(String name) {
setUserObject(name);
}
public String getName() {
return (String)getUserObject();
}
public void setCreated(Date date) {
this.created = date;
}
public Date getCreated() {
return created;
}
}
/**
* BookmarkEntry represents a bookmark. It contains a URL,
* a user definable string, and two dates, one giving the date the
* URL was last visited and the other giving the date the bookmark
* was created.
*/
public static class BookmarkEntry extends DefaultMutableTreeNode {
/** User description of the string. */
private String name;
/** The URL the bookmark represents. */
private URL location;
/** Dates the URL was last visited. */
private Date lastVisited;
/** Date the URL was created. */
private Date created;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setLocation(URL location) {
this.location = location;
}
public URL getLocation() {
return location;
}
public void setLastVisited(Date date) {
lastVisited = date;
}
public Date getLastVisited() {
return lastVisited;
}
public void setCreated(Date date) {
this.created = date;
}
public Date getCreated() {
return created;
}
public String toString() {
return getName();
}
}
}