/** * This quick hack constructs the "home page" file I use in my web browser. * The application is totally lacking in redeeming human interface. Just * let it run until it quits. It was written in one evening and rewritten * in a second (about three years later). * * My web browser home page is merely a list of the pages I visit often enough * to want to remember their locations. The advantage of this is that it * loads fast and gets me to where I want to be quickly. It is organized * as a multi-column table. As you might expect, constructing this by hand * turned out to be an unpleasant task. * * The application reads a list of sites from a source file, "HomePage.src" * and writes the formatted table to "HomePage.html". The source file has * the following format:<pre> *	** Comment - rest of this line is ignored. *	*fontname	<whitespace>	Fontname list. *	*fontsize	<whitespace>	<number> *	*title		<whitespace>	Text *      *copy   Copy the rest of the line (starting after whitespace) *      *copy   to the output stream. This lets you write HTML into *      *copy   the result. *	<name><newline>			Section heading *	+<name><Newline>		This section heading starts a new column *	<name><tabs>URL<newline>	Normal URL entry. *	<Newline>			Blank cell * </pre> * If fontname, fontsize or title commands are given more than once, the last * one will be used for all text. I.e., you can't change fonts in mid-stream. * fontname, fontsize and title must be specified in lowercase. * For example,<pre> *	** Define my home page *	*fontnanme			Arial, Helvetica *	*fontsize			3 *	*title				My Home Page *	Macintosh Stuff *	Apple Computer Inc.		http://www.apple.com/ *	MacInTouch			http://www.macintouch.com/ * *	Java Stuff *	Apple Java			http://applejava.apple.com/ *	Roaster				http://www.roaster.com/ *	Javasoft			http://www.javasoft.com/ *	Gamelan				http://www.gamelan.com/ *	+Useful information *	Internic URL Lookup		http://rs.internic.net/cgi-bin/whois *	USNO Time Service		http://tycho.usno.navy.mil/ *	U.S.G.S Earthquake Info		http://quake.wr.usgs.gov/ *	HTML ISO Latin-1 Character Set	http://info.cern.ch/hypertext/WWW/MarkUp/ISOlat1.html *	HTML Markup entities entities	http://info.cern.ch/hypertext/WWW/MarkUp/Entities.html * </pre> * <p> * Copyright &copy; 1996-1999 Martin Minow. All Rights Reserved.<p> * * Permission to use, copy, modify, and redistribute this software and its * documentation for personal, non-commercial use is hereby granted provided that * this copyright notice and appropriate documentation appears in all copies. This * software may not be distributed for fee or as part of commercial, "shareware," * and/or not-for-profit endevors including, but not limited to, CD-ROM collections, * online databases, and subscription services without specific license.<p> * * @author <a href="mailto:minow@apple.com">Martin Minow</a> * @version 1.0.4 * 1996.09.21	Use ProgressBar.java to log progress. Renamed MakeHomePage * 1998.12.31	Renamed MakeHomePage, recompiled for MRJ 2.0. * 1999.08.18	Rewritten for Java 1.1 (using Reader/Writer). * Set tabs every 8 characters. */import java.awt.*;import java.util.*;import java.lang.*;import java.io.*;import com.apple.mrj.MRJFileUtils;import com.apple.mrj.MRJOSType;public class HomePageBuilder extends Frame{    public static final String	copyright =    		"1.0.3 Copyright 1996-1999 Martin Minow. All Rights Reserved";    /**     * The input file name.     */    public static final String	defaultSourceFile	= "HomePage.src";    /**     * The output file name.     */    public static final String	defaultOutputFile	= "HomePage.html";    /**     * The following can be changed by * commands.     * The title of the home page.     */    String fontName			= "Arial, Helvetica";    String fontSize			= "3";    String titleString			= "My Home Page";    String backgroundColor		= "FFFFFF";    String linkColor			= "3333FF";    String visitedColor			= "333355";    String sectionColor			= "#CC0033";    /**     * All links are read into row vectors stored in this     * column vector..     */    Vector columnVector			= new Vector();    Label progressLabel			= new Label("", Label.CENTER);    Label copyrightLabel		= new Label(copyright, Label.CENTER);    Font labelFont			= new Font("Serif", Font.PLAIN, 12);    static void main(    		String			args[]    	)    {	String sourceFile		= defaultSourceFile;	String outputFile		= defaultOutputFile;	if (args.length == 2) {	    sourceFile			= args[0];	    outputFile			= args[1];	}	else if (args.length > 0) {	    System.err.println("Arguments ignored.");	    System.err.println("Usage: HomePageBuilder sourceFile outputFile");	}    	new HomePageBuilder(sourceFile, outputFile);    }    /**     * HomePageBuilder processes the input file.     * @param fileName		The file to process.     */    public HomePageBuilder(    		String				sourceFile,    		String				outputFile    	)    {    	super("Make Home Page");    	addNotify();	/* Create peers */    	setLayout(new BorderLayout(8, 8));    	progressLabel.setFont(labelFont);    	copyrightLabel.setFont(labelFont);    	add("North", progressLabel);    	add("South", copyrightLabel);    	this.pack();    	/*    	 * Center the progress bar on the main screen.    	 * This might look bad on a multi-screen display.    	 */    	Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();    	this.move(    	    Math.max(4, (screen.width - size().width) / 2),    	    Math.max(0, (screen.height - size().height - 24) / 3) + 24    	);    	this.setVisible(true);    	boolean success		= true;    	int lineCount		= 0;    	try { 	    FileReader inFile	= new FileReader(sourceFile); 	    progressLabel.setText("Reading " + sourceFile);	    LineNumberReader in	= new LineNumberReader(inFile);    	    lineCount		= readInputFile(in);    	    in.close();    	    inFile.close();    	}    	catch (IOException e) {	    System.err.println("Can't read \"" + sourceFile + "\": " + e.toString());	    success		= false;	}	if (success) { 	    progressLabel.setText("Writing " + lineCount + " links to " + outputFile);	    try {	        File theOutputFile	= new File(outputFile);    	        FileWriter outFile	= new FileWriter(theOutputFile);    	        PrintWriter out		= new PrintWriter(outFile, false);		try { /* Macintosh specific */		    MRJFileUtils.setFileTypeAndCreator(			theOutputFile,			new MRJOSType("TEXT"),			new MRJOSType("MSIE")		    );		}		catch (IOException e) {		    System.err.println("Warning: can't set file type: " + e);		}		catch (NoClassDefFoundError e) {		    /* Ignored: not running on a Mac */		}		writeOutputFile(out);		out.flush();		outFile.flush();		outFile.close();	    }	    catch (IOException e) {		System.err.println("Can't write \"" + outputFile + "\": " + e.toString());		success			= false;	    }    	}	System.exit((success) ? 0 : 1);    }        /**     * Read the source file, store the data in the column vectors.     */     private int readInputFile(	    LineNumberReader		in	)	throws IOException    {	String currentLine		= null;	boolean needNewColumn		= true;	Vector rowVector		= null;	int lineCount			= 0;    	while ((currentLine = in.readLine()) != null) {    	    // System.out.println("In: \"" + currentLine + "\"");    	    currentLine = currentLine.trim();	    if (currentLine.length() >= 2	     && currentLine.charAt(0) == '*'	     && currentLine.charAt(1) == '*') {    		/* Comment, ignored */	    }	    else if (currentLine.length() == 0) {	        /* Comment, ignored */	    }	    else if (currentLine.startsWith("*copy")) {	        int start       = 5;	        while (start < currentLine.length()	            && Character.isWhitespace(currentLine.charAt(start))) {	            ++start;	        }	        rowVector.addElement("*" + currentLine.substring(start));	    }               	    else if (currentLine.charAt(0) == '*') {    		fontName	= parseString(currentLine, "fontname",	fontName);    		fontSize	= parseString(currentLine, "fontsize",	fontSize);    		titleString	= parseString(currentLine, "title",	titleString);    		backgroundColor	= parseString(currentLine, "background", backgroundColor);    		sectionColor	= parseString(currentLine, "sectioncolor", sectionColor);    		linkColor	= parseString(currentLine, "link",	linkColor);    		visitedColor	= parseString(currentLine, "visited",	visitedColor);    	    }    	    else { /* It's a link */		if (currentLine.charAt(0) == '+') {		    currentLine		= currentLine.substring(1);		    needNewColumn	= true;		}		if (needNewColumn) {		    rowVector		= new Vector();		    columnVector.addElement(rowVector);		    needNewColumn	= false;		}    		rowVector.addElement(currentLine);    		++lineCount;    	    }    	}	return (lineCount);    }    /**     * Parse a command string. Returns the parsed value if successful, or the     * default string if not.     * @param	string			The string as read from the input file.     * @param	command			The parameter to test     * @param	defaultValue	A value to return if this parameter doesn't match.     */    public String parseString(    		String		string,    		String		command,    		String		defaultValue    	)    {    	String result		= defaultValue;    	int i = skipBlanks(string, 1);    	if (string.toLowerCase().startsWith(command, i)) {    		i		= skipBlanks(string, i + command.length());    		result		= string.substring(i);    		// System.out.println(command + " = " + result);    	}    	return (result);    }        /**     * Write the finished web page, one column at a time.     * @param out	The output file     */    private void writeOutputFile(	    PrintWriter		out	)	throws IOException    {	writeHeader(out);	Enumeration e		= columnVector.elements();	while (e.hasMoreElements()) {	    writeOneColumn(out, (Vector) e.nextElement());	}	writeTrailer(out);    }    /**     * Write all links in this column.     * @param out	The output file     * @param rows	The links to write in this column.     */    private void writeOneColumn(	    PrintWriter		out,	    Vector		rows	)    {	out.println("<td valign=\"top\">");	Enumeration e		= rows.elements();	int sectionIndex	= 0;	while (e.hasMoreElements()) {	    String element	= (String) e.nextElement();	    if (element == "") {		writeURL(out, "", "");	    }	    else if (element.charAt(0) == '*') {	        out.println(element.substring(1));	    }	    else { 		int nameEnd	= element.indexOf('\t');    		if (nameEnd == -1) {    		    writeSection(out, element, sectionIndex);    		    ++sectionIndex;		}    		else {    		    int urlStart = element.lastIndexOf('\t') + 1;    		    writeURL(    		    	    out,    			    element.substring(0, nameEnd).trim(),    			    element.substring(urlStart).trim()    			);    		}	    }    	}    	if (sectionIndex > 0) {	    out.println("</p>");	}	out.println("</td>");    }    /**     * Write the home page header, called once at start.     * @param out	The output file     */    void writeHeader(	    PrintWriter		out	)    {	out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">");	out.println("<html><head><title>" + titleString + "</title></head>");	out.println("<body>"	    );	out.println(		"<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"	   );	out.println("<tr>");    }    /**     * Output the home page trailer, called once at completion.     */    void writeTrailer(	    PrintWriter		out	)    {	out.println("</tr></table></body></html>");    }    /**     * Output a section identifier.     * @param out	The output file     * @param name	The section identifier (may be blank)     * @param sectionIndex section counter (for paragraph termination).     */    void writeSection(	    PrintWriter		out,    	    String		name,    	    int			sectionIndex    	)    {	if (sectionIndex > 1) {	    out.println("</p>");	}	if (sectionIndex > 0) {	    out.println("<p>");	}	int offset = (name.charAt(0) == '+') ? 1 : 0;    	out.println("<font face=\"" + fontName		+ "\" color=\"" + sectionColor		+ "\" size=\"" + fontSize		+ "\"><em> "    		+ name.substring(offset)    		+ " </em></font><br>"  	    );    }        /**     * Output a URL.     * @param out	The output file     * @param name	The name of this site (human readable)     * @param url	The site's URL     */    void writeURL(	    PrintWriter		out,    	    String		name,    	    String		url    	)    {	/*	 * Leading &nbsp; sequences are not included in the anchor.	 * Append two nbsp's to separate columns.	 */	while (name.startsWith("&nbsp;") || name.startsWith("&NBSP;")) {	    out.print("&nbsp;");	    name		= name.substring(6);	}    	out.println("<font face=\"" + fontName    		+ "\" size=\"" + fontSize    		+ "\"><a href=\"" + url + "\">"    		+ name    		+ "</a>&nbsp;&nbsp;</font><br>"    	    );    }    /**     * Simple function to skip over whitespace.     * @param string	The string to examine.     * @param offset	Where to start looking for whitespace     * @result Return the offset of the first non-whitespace character.     */    int skipBlanks(	    String		string,    	    int			offset    	)    {    	while (offset < string.length()    	    && Character.isSpace(string.charAt(offset))) {    	    ++offset;    	}    	return (offset);    }    public Dimension minimumSize()    {	FontMetrics fm		= getFontMetrics(labelFont);	int height		= fm.getHeight() * 4;	int width		= fm.charWidth('M') * 48;    	return (new Dimension(width, height));    }    public Dimension preferredSize()    {	return (minimumSize());    }}