All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.help.HelpSet Maven / Gradle / Ivy

The newest version!
/*
 * @(#)HelpSet.java	1.108 06/10/30
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 * 
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package javax.help;

import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.util.*;
import java.io.*;
import java.awt.Dimension;
import java.awt.Point;
import javax.help.event.EventListenerList;
import javax.help.DefaultHelpBroker;
import javax.help.event.HelpSetListener;
import javax.help.event.HelpSetEvent;
import javax.help.Map.ID;

// implementation-specific
import com.sun.java.help.impl.Parser;
import com.sun.java.help.impl.ParserListener;
import com.sun.java.help.impl.ParserEvent;
import com.sun.java.help.impl.Tag;
import com.sun.java.help.impl.TagProperties;
import com.sun.java.help.impl.XmlReader;
import com.sun.java.help.impl.LangElement;
import javax.help.Map.ID;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.Constructor;
/**
 * A HelpSet  is a collection of help information consisting of a HelpSet
 * file, table of contents (TOC), index, topic files, and Map file.
 * The HelpSet file is the portal to the HelpSet.
 *
 * @author Roger D. Brinkley
 * @author Eduardo Pelegri-Llopart
 * @author Stepan Marek
 * @version	1.108	10/30/06
 */

public class HelpSet implements Serializable{
    private static String errorMsg = null;
    /*
     * Event listeners for adding to the HelpSet
     */

    protected EventListenerList listenerList = new EventListenerList();

    /**
     * PublicID (known to this XML processor) to the DTD for version 1.0 of the HelpSet
     */
    public static final String publicIDString =
        "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN";

    /**
     * PublicID (known to this XML processor) to the DTD for version 2.0 of the HelpSet
     */
    public static final String publicIDString_V2 =
        "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN";

    /**
     * Information for implementation customization.
     * 
     * helpBroker/class is used to locate the class for a HelpBroker.
     * helpBroker/loader is used to determine the ClassLoader to use.
     */

    public static final Object implRegistry =
        new StringBuffer("HelpSet.implRegistry");
    public static final String helpBrokerClass = "helpBroker/class";
    public static final String helpBrokerLoader = "helpBroker/loader";

    /**
     * HelpSet context information.
     *
     * A HelpSet can map between keys (String) and values (Strings).
     * There is a per-HelpSet value and a default value.
     * The per-HelpSet value is specified in the appropriate section of the
     * HelpSet file.
     * The default value is global and only specified at class initialization time.
     */

    public static final Object kitTypeRegistry = 
        new StringBuffer("JHelpViewer.kitTypeRegistry");
    public static final Object kitLoaderRegistry = 
        new StringBuffer("JHelpViewer.kitLoaderRegistry");

    /**
     * Creates an empty HelpSet that one can parse into.
     * @param loader The ClassLoader to use. If loader is null, the default
     * ClassLoader is used.
     */
    public HelpSet(ClassLoader loader) {
	this.helpsets = new Vector();
	this.loader = loader;
    }

    /**
     * Creates an empty HelpSet. Uses the default ClassLoader
     */
    public HelpSet() {
	this.helpsets = new Vector();
	this.loader = null;
    }

    /**
     * Creates a HelpSet.  The locale for the data is either that indicated in
     * the lang attribute of the helpset tag, or
     * Locale.getDefault() if the lang attribute is not present.
     *
     * @param loader The class loader to use to locate any classes
     * required by the navigators in the Helpset
     * If loader is null, the default ClassLoader is used.
     * @param helpset The URL to the HelpSet "file"
     *
     * @exception HelpSetException if there are problems parsing the helpset
     */
    public HelpSet(ClassLoader loader, URL helpset) throws HelpSetException {
	this(loader);
	this.helpset = helpset;	// so it can be used in parseInto()

	HelpSetFactory factory = new DefaultHelpSetFactory();

	parseInto(helpset, factory);
	HelpSet x = factory.parsingEnded(this); // use the error reporting

	if (x == null) {
	    // We had trouble parsing
	    // May need to revisit this...
            throw new HelpSetException("Could not parse\n"+errorMsg);
	}
    }


    /**
     * Locates a HelpSet file and return its URL.
     * Applies localization conventions.
     *
     * @param cl The classloader to use when searching for the resource
     * with the appropriate name. If cl is null the default 
     * ClassLoader is used.
     * @param shortName The shortname of the resource.
     * @param extension The extension of the resource.
     * @param locale The desired Locale
     * @see javax.help.HelpUtilities
     */

    public static URL findHelpSet(ClassLoader cl,
				  String shortName,
				  String extension,
				  Locale locale) {
	// Test for whether URL can be opened! - workaround Browser bugs
	return HelpUtilities.getLocalizedResource(cl,
						  shortName,
						  extension,
						  locale,
						  true);
    }

    /**
     * Locates a HelpSet file and return its URL.
     *
     * If the name does not end with the ".hs" extension, the
     * ".hs" extension is appended and localization rules
     * are applied to it.
     *
     * @param cl The classloader to use. If cl is null the default 
     * ClassLoader is used.
     * @param name The name of the resource.
     * @param locale The desired locale.
     */
    public static URL findHelpSet(ClassLoader cl,
                                 String name,
                                 Locale locale) {
	String shortName;
	String extension;
	if (name.endsWith(".hs")) {
	    shortName = name.substring(0, name.length()-3);
	    extension = ".hs";
	} else {
	    shortName = name;
	    extension = ".hs";
	}
	return findHelpSet(cl, shortName, extension, locale);
    }

    /**
     * As above but default on locale to Locale.getDefault()
     *
     * @param cl The ClassLoader to use. If cl is null the default 
     * ClassLoader is used.
     * @param name The name of the resource.
     * @return Null if not found.
     */
    public static URL findHelpSet(ClassLoader cl,
                                 String name) {
	return findHelpSet(cl, name, Locale.getDefault());
    }


    /**
     * Creates a presentation object for this HelpSet.
     * Consults the implRegistry of KeyData for 
     * the class name (as helpBrokerClass) and for the ClassLoader 
     * instance (as helpBrokerLoader) and then tries to instantiate 
     * that class.  It then invokes setHelpSet() with
     * this instance of HelpSet as the argument.  The resulting object is  
     * returned.
     * @see createHelpBroker(String)
     */
    public HelpBroker createHelpBroker() {
	return createHelpBroker(null);
    }

    /**
     * Creates a presentation object for this HelpSet.
     * Consults the implRegistry of KeyData for 
     * the class name (as helpBrokerClass) and for the ClassLoader 
     * instance (as helpBrokerLoader) and then tries to instantiate 
     * that class.  It then invokes setHelpSet() with
     * this instance of HelpSet as the argument.  The resulting object is  
     * returned.
     * @param presenationName A presentation name defined in the HelpSet 
     *                        that will dictate the presentation.
     * @return HelpBroker The created HelpBroker
     * @since 2.0
     * @see createHelpBroker()
     */
    public HelpBroker createHelpBroker(String presentationName) {
        HelpBroker back = null;

	String classname =
	    (String) getKeyData(implRegistry, helpBrokerClass);
	ClassLoader loader =
	    (ClassLoader) getKeyData(implRegistry, helpBrokerLoader);

	if (loader == null) {
	    loader = getLoader();
	}
	try {
	    Class c;
	    if (loader != null) {
		c = loader.loadClass(classname);
	    } else {
		c = Class.forName(classname);
	    }
	    back = (HelpBroker) c.newInstance();
	} catch (Throwable e) {
	    back = null;
	}

        if (back != null) {
            back.setHelpSet(this);
	    HelpSet.Presentation hsPres = null;
	    // If there is a presentation name find it otherwise get the
	    // default if one exists.
	    if (presentationName != null) {
		hsPres = getPresentation(presentationName);
	    } else {
		hsPres = getDefaultPresentation();
	    }
	    if (hsPres != null) {
		back.setHelpSetPresentation(hsPres);
	    }
	}
        return back;
    }

    /**
     * Adds a HelpSet, HelpSetEvents are generated.
     * Adding a composed HelpSet to another is equivalent to
     * adding all the HelpSets individually.
     *
     * @param hs The HelpSet to add.
     */
    public void add(HelpSet hs) {
	debug("add("+hs+")");
	helpsets.addElement(hs);
	fireHelpSetAdded(this, hs);
	combinedMap = null;	// invalidate the map
    }

    /**
     * Removes a HelpSet from this HelpSet; HelpSetEvents are generated
     * Return True if it is found, otherwise false.
     *
     * @param hs The HelpSet to remove. 
     * @return False if the hs is null or was not in this HelpSet
     */
    public boolean remove(HelpSet hs) {
	if (helpsets.removeElement(hs)) {
	    fireHelpSetRemoved(this, hs);
	    combinedMap = null;	// HERE - invalidate it - epll
	    return true;
	} else {
	    return false;
	}
    }

    /**
     * Enumerates all the HelpSets that have been added to this one.
     *
     * @return An enumeration of the HelpSets that have been added to
     * this HelpSet.
     */
    public Enumeration getHelpSets() {
	return helpsets.elements();
    }

    /**
     * Determines if a HelpSet is a sub-HelpSet of this object.
     *
     * @param hs The HelpSet to check
     * @return true If hs is contained in this HelpSet or in one of its children.
     */
    public boolean contains(HelpSet hs) {
	if (hs == this) {
	    return true;
	}
	for (Enumeration e = helpsets.elements();
	     e.hasMoreElements();) {
	    HelpSet child = (HelpSet) e.nextElement();
	    if (child.contains(hs)) {
		return true;
	    }
	}
	return false;
    }

    /**
     * Adds a listener for the HelpSetEvent posted after the model has
     * changed.
     * 
     * @param l - The listener to add.
     * @see javax.help.HelpSet#removeHelpSetListener. 
     * @throws IllegalArgumentException if l is null.
     */
    public void addHelpSetListener(HelpSetListener l) {
	debug("addHelpSetListener("+l+")");
	listenerList.add(HelpSetListener.class, l);
    }

    /**
     * Removes a listener previously added with addHelpSetListener
     *
     * @param l - The listener to remove.
     * @see javax.help.HelpSet#addHelpSetListener. 
     * @throws IllegalArgumentException if l is null.
     */
    public void removeHelpSetListener(HelpSetListener l) {
	listenerList.remove(HelpSetListener.class, l);
    }

    /**
     * Fires a helpSetAdded event.
     */
    protected void fireHelpSetAdded(Object source, HelpSet helpset){
	Object[] listeners = listenerList.getListenerList();
	HelpSetEvent e = null;

	for (int i = listeners.length - 2; i >= 0; i -= 2) {
	    if (listeners[i] == HelpSetListener.class) {
		if (e == null) {
		    e = new HelpSetEvent(this, helpset,
					 HelpSetEvent.HELPSET_ADDED);
		}
		((HelpSetListener)listeners[i+1]).helpSetAdded(e);
	    }	       
	}
    }

    /**
     * Fires a helpSetRemoved event.
     */
    protected void fireHelpSetRemoved(Object source, HelpSet helpset){
	Object[] listeners = listenerList.getListenerList();
	HelpSetEvent e = null;

	for (int i = listeners.length - 2; i >= 0; i -= 2) {
	    if (listeners[i] == HelpSetListener.class) {
		if (e == null) {
		    e = new HelpSetEvent(this, helpset,
					 HelpSetEvent.HELPSET_REMOVED);
		}
		((HelpSetListener)listeners[i+1]).helpSetRemoved(e);
	    }	       
	}
    }

    // ======= Labels, etc =======
    /**
     * Gets the title of this HelpSet.
     *
     * @return the title
     */
    public String getTitle() {
	if (title == null) {
	    return "";
	} else {
	    return title;
	}
    }

    /**
     * Sest the title for this HelpSet.  This is a bound property.
     *
     * @param title The title to set.
     */
    
    public void setTitle(String title) {
	String oldTitle = this.title;
	this.title = title;
	changes.firePropertyChange("title", oldTitle, title);
    }

    /**
     * Gets the locale for this HelpSet.
     * 
     * @return The locale.
     */
    public Locale getLocale() {
	return locale;
    }

    /**
     * Sets the locale for this HelpSet.
     * Strictly a private routine but the read-only property is bound.
     *
     * @param locale The locale to set.
     */
    private void setLocale(Locale l) {
	Locale oldLocale = locale;
	locale = l;
	changes.firePropertyChange("locale", oldLocale, locale);
    }

    /**
     * Returns 
     * the ID to visit when the user makes a "go home" gesture.
     * This can be identified in the project file, but may also be changed
     * programmatically or (possibly) via the UI.
     * 
     * @return The ID of home. A null is returned if homeID is null
     * or if an ID cannot be created for the homeID.
     */
    public ID getHomeID() {
	if (homeID == null) {
	    return null;
	} else {
	    try {
		return ID.create(homeID, this);
	    } catch (Exception ex) {
		return null;
	    }
	}
    }

    /**
     * Sets the Home ID for a HelpSet.  This is a bound property.
     *
     * @param The ID (in the Map) that identifies the default topic for this HelpSet. Null is valid homeID.
     */
    public void setHomeID(String homeID) {
	String oldID = homeID;
	this.homeID = homeID;
	changes.firePropertyChange("homeID", oldID, homeID);
    }

    // WARNING/HERE: In this implementation, the Map is not updated automatically
    // so you need to come get a new one - epll

    // Warning.  This is not handling recursive aggregation

    /**
     * The map for this HelpSet.  This map involves the closure of 
     * this HelpSet's children HelpSets.
     *
     * @return The map
     */
    public Map getCombinedMap() {
 	if (combinedMap == null) {
 	    combinedMap = new TryMap();
	    if (map != null) {
		combinedMap.add(map); // the local map
	    }
	    for (Enumeration e = helpsets.elements();
		 e.hasMoreElements(); ) {
		HelpSet hs = (HelpSet) e.nextElement();
		combinedMap.add(hs.getCombinedMap());
	    }
	}
	return combinedMap;
    }

    /**
     * Get the local (i.e. non-recursive) Map for this HelpSet.
     * This Map does not include the Maps for its children.
     *
     * @return The Map object that associates ID->URL. A null map is valid.
     */
    public Map getLocalMap() {
	return this.map;
    }

    /**
     * Set the Map for this HelpSet.  This Map object is not recursive; for example,
     * it does not include the Maps for its children.
     *
     * @param The Map object that associates ID->URL. A null map is a valid.
     */
    public void setLocalMap(Map map) {
	this.map = map;
    }

    /**
     * The URL that is the base for this HelpSet.
     *
     * @return The URL that is base to this HelpSet.
     */
    public URL getHelpSetURL() {
	return helpset;
    }

    /**
     * A classloader to use when locating classes.
     *
     * @return The ClassLoader to use when locating classes mentioned
     * in this HelpSet.
     */

    public ClassLoader getLoader() {
	return loader;
    }

    /**
     * NavigatorView describes the navigator views that are requested
     * by this HelpSet.
     *
     * @return The array of NavigatorView.
     */

    public NavigatorView[] getNavigatorViews() {
	NavigatorView back[] = new NavigatorView[views.size()];
	views.copyInto(back);
	return back;
    }

    /**
     * Gets the NavigatorView with a specific name.
     *
     * @param The name of the desired navigator view.
     */
    public NavigatorView getNavigatorView(String name) {
	debug("getNavigatorView("+name+")");
	for (int i=0; iURL map
    private URL helpset;	// the HelpSet from where to search
    private String homeID;
    private Locale locale = Locale.getDefault();

    private transient ClassLoader loader;	// encapsulates loading...

    private Vector views = new Vector();

    private Vector presentations = new Vector();

    private HelpSet.Presentation defaultPresentation = null;

    private Vector helpsets;	// All the helpsets added to this one

    private static HelpBroker defaultHelpBroker = null; // the default HelpBroker

    private Vector subHelpSets = new Vector();

    // Default and Local Hashtables for keys

    private static Hashtable defaultKeys;
    private Hashtable localKeys = new Hashtable();

    private PropertyChangeSupport changes = new PropertyChangeSupport(this);

    // ============= PRIVATE Parsing Class ========

    /**
     * Inner class for parsing a TOC stream.
     *
     * WARNING!! This class is an interim solution until when we move to a
     * real XML parser.  This is not a public class.  Clients should only use
     * the parse method in the enclosing class.
     */

    private static class HelpSetParser implements ParserListener {
	private Stack tagStack;	// the collection of active Parse tags
	private Locale defaultLocale;
	private Locale lastLocale;
	private HelpSet myHS;	// my HelpSet
	private Locale myHSLocale; // its locale
	private HelpSetFactory factory;	// the factory


	private String tagName;	  // genericly used for views and presentation 
	private String viewLabel;
	private String viewType;
	private String viewEngine;
        private String tagImage;
        private String helpActionImage;
	private String viewData;
        private String viewMergeType;
	private Hashtable htData;

	private boolean defaultPresentation = false;
	private boolean displayViews = true;
	private boolean displayViewImages = true;
	private Dimension size;
	private Point location;
	private String presentationTitle;
	private boolean toolbar;
	private Vector helpActions;
	private String helpAction;

	/**
	 * Creates a Parser (Listener) instance.
	 */
	HelpSetParser (HelpSetFactory factory) {
	    this.factory = factory;
	}

	/**
	 * Parses a reader into a HelpSet.
	 */
	synchronized void parseInto(Reader src,
				    HelpSet hs) 
	    throws IOException
        {
	    tagStack = new Stack();
	    defaultLocale = hs.getLocale();
	    lastLocale = defaultLocale;
	    myHS = hs;
	    myHSLocale = hs.getLocale();
	    Parser parser = new Parser(src); // the XML parser instance
	    parser.addParserListener(this);
	    parser.parse();
	}

	public void tagFound(ParserEvent e) {
            debug("tagFound " + e.getTag().name);
	    Locale locale = null;
	    LangElement le;
	    Tag tag = e.getTag();
	    String name = tag.name;
	    int x=0, y=0, width=0, height=0;
	    TagProperties attr = tag.atts;
	    Hashtable ht = (attr == null) ? null : attr.getHashtable();

	    if (attr != null) {
		String lang = attr.getProperty("xml:lang");
		locale = HelpUtilities.localeFromLang(lang);
                viewMergeType = attr.getProperty("mergetype");
		helpActionImage = attr.getProperty("image");
		String value = null;
		value = attr.getProperty("width");
		if (value != null) {
		    width = Integer.parseInt(value);
		}
		value = null;
		value = attr.getProperty("height");
		if (value != null) {
		    height = Integer.parseInt(value);
		}
		value = null;
		value = attr.getProperty("x");
		if (value != null) {
		    x = Integer.parseInt(value);
		}
		value = null;
		value = attr.getProperty("y");
		if (value != null) {
		    y = Integer.parseInt(value);
		}
		value = null;
		value = attr.getProperty("default");
		if (value != null && value.equals("true")) {
		    defaultPresentation = true;
		}
		value = null;
		value = attr.getProperty("displayviews");
		if (value != null && value.equals("false")) {
		    displayViews = false;
		}
		value = null;
		value = attr.getProperty("displayviewimages");
		if (value != null && value.equals("false")) {
		    displayViewImages = false;
		}
	    }
	    if (locale == null) {
		locale = lastLocale;
	    }
            
	    if (name.equals("helpset")) {
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    // Check and see if the locale is different from the
		    // defaultLocale. If it is then reset the locale.
 		    if (! locale.equals(defaultLocale) &&
			! locale.equals(myHSLocale)) {
			if (locale != null) {
			    myHS.setLocale(locale);
			    defaultLocale = locale;
			}
		    }
		    if (attr != null) {
		        String version = attr.getProperty("version");
			if (version != null && 
			    (version.compareTo("1.0") != 0 &&
			     version.compareTo("2.0") != 0)) {
			    parsingError("helpset.unknownVersion", version);
			}
		    }
		    addTag(tag, locale);
		}
		return;
	    }

	    if (tagStack.empty()) {
		parsingError("helpset.wrongTopLevel", name);
	    }

	    // Get the parents name
	    le = (LangElement) tagStack.peek();
	    String pname = ((Tag) le.getTag()).name; // the parent

	    if (name.equals("title")) {
		// TITLE tag
		if (tag.isEnd) {
		    removeTag(tag);		// processing was done in textFound()
		} else {
		    if ((! pname.equals("helpset")) &&
			(! pname.equals("presentation"))){
			wrongParent(name, pname);
		    }
 		    if (! locale.equals(defaultLocale) &&
			! locale.equals(myHSLocale)) {
			wrongLocale(locale, defaultLocale, myHSLocale);
		    }
		    addTag(tag, locale);
		}
	    } else if (name.equals("homeID")) {
		// HOMEID tags
		if (tag.isEnd) {
		    removeTag(tag);		// processing was done in textFound()
		} else {
		    if (! pname.equals("maps")) {
			wrongParent(name, pname);
		    }
		    addTag(tag, locale);
		}
	    } else if (name.equals("mapref")) {
		// MAPREF tags

		// Remove from stack if an empty tag
		if (tag.isEnd && !tag.isEmpty) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("maps")) {
			wrongParent(name, pname);
		    }
		    // add the tag if not an empty tag
		    if (! tag.isEmpty) {
			addTag(tag, locale);
		    }
		    // Process the tag
		    factory.processMapRef(myHS,
					  ht);
		}
	    } else if (name.equals("data")) {
		// DATA tag
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("view")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		    htData = ht;
		}
	    } else if (name.equals("name") ||
		       name.equals("type") ||
		       name.equals("image")){                           
		// NAME, TYPE, IMAGE tag
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    if ((! pname.equals("view")) && 
			(! pname.equals("presentation"))) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("label")) {
		// LABEL tag
		// Special processing to check the locale attribute.
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("view")) {
			wrongParent(name, pname);
		    } else {
			if (! locale.equals(defaultLocale) &&
			    ! locale.equals(myHSLocale)) {
			    wrongLocale(locale, defaultLocale, myHSLocale);
			}
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("view")) {
		// VIEW tag
		if (tag.isEnd) {
		    removeTag(tag);

                    if (tagImage != null) {
                        if (htData == null) {
                            htData = new Hashtable();
			}
                        htData.put("imageID", tagImage);
                    }
                    
                    if (viewMergeType != null) {
                        if(htData == null) {
                            htData = new Hashtable();
			}
                        htData.put("mergetype",viewMergeType);
                    }

		    factory.processView(myHS,
					tagName,
					viewLabel,
					viewType,
					ht,
					viewData,
					htData,
					locale);
                    tagName = null;
                    viewLabel = null;
                    viewType = null;
                    tagImage = null;
                    viewData = null;
                    htData = null;
                    viewMergeType = null;

		} else {
		    if (! pname.equals("helpset")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("presentation")) {
		// Presentation tag
		if (tag.isEnd) {
		    removeTag(tag);

		    factory.processPresentation(myHS,
						tagName,
						defaultPresentation,
						displayViews,
						displayViewImages,
						size,
						location,
						presentationTitle,
						tagImage,
						toolbar,
						helpActions);

                    tagName = null;
                    defaultPresentation = false;
                    displayViews = true;
                    displayViewImages = true;
                    size = null;
                    location = null;
                    presentationTitle = null;
		    tagImage = null;
		    toolbar = false;
		    helpActions = null;

		} else {
		    if (! pname.equals("helpset")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("size")) {
		// DATA tag
		if (tag.isEnd) {
		    if (size == null) {
			size = new Dimension(width, height);
		    } else {
			size.setSize(width, height);
		    }
		    width = 0;
		    height = 0;
		    if (!tag.isEmpty) {
			removeTag(tag);
		    }
		} else {
		    if (! pname.equals("presentation")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
			size = new Dimension();
		    }
		}
	    } else if (name.equals("location")) {
		// DATA tag
		if (tag.isEnd) {
		    if (location == null) {
			location = new Point(x, y);
		    } else {
			location.setLocation(x, y);
		    }
		    x = 0;
		    y = 0;
		    if (!tag.isEmpty) {
			removeTag(tag);
		    }
		} else {
		    if (! pname.equals("presentation")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
			location = new Point();
		    }
		}
	    } else if (name.equals("toolbar")) {
		// DATA tag
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("presentation")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
			helpActions = new Vector();
			toolbar = true;
		    }
		}
	    } else if (name.equals("helpaction")) {
		// DATA tag
		if (tag.isEnd) {
		    removeTag(tag);
		    if (helpAction != null) {
			Hashtable tmp = new Hashtable();		      
			helpActions.add(new HelpSetFactory.HelpAction(helpAction, tmp));
			if (helpActionImage != null) {
			    tmp.put("image", helpActionImage);
			    helpActionImage = null;
			}
			helpAction = null;
		    }
		} else {
		    if (! pname.equals("toolbar")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("maps")) {
		// MAPS tag
		if (tag.isEnd) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("helpset")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("subhelpset")) {
		// SUBHELPSET tag
		
		// Remove from stack if an empty tag
		if (tag.isEnd && !tag.isEmpty) {
		    removeTag(tag);
		} else {
		    // Add the tag if it isn't an inline tag
		    if (!tag.isEmpty) {
			addTag(tag, locale);
		    }
		    // Process the tag
		    factory.processSubHelpSet(myHS, ht);
		}
	    } else if (name.equals("impl")) {
		// Presentation tag
		if (tag.isEnd) {
		    removeTag(tag);
		    // Nothing to do here. Everything is done while
		    // processing the sub tags
		} else {
		    if (! pname.equals("helpset")) {
			wrongParent(name, pname);
		    } else {
			addTag(tag, locale);
		    }
		}
	    } else if (name.equals("helpsetregistry")) {
		if (tag.isEnd && !tag.isEmpty) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("impl")) {
			wrongParent(name, pname);
		    } else {
			if (!tag.isEnd) {
			    addTag(tag, locale);
			}
			if (attr != null) {
			    String hbClass = attr.getProperty("helpbrokerclass");
			    if (hbClass != null) {
				myHS.setKeyData(implRegistry,
						helpBrokerClass, 
						hbClass);
			    }
			}
		    }
		}
	    } else if (name.equals("viewerregistry")) {
		if (tag.isEnd && !tag.isEmpty) {
		    removeTag(tag);
		} else {
		    if (! pname.equals("impl")) {
			wrongParent(name, pname);
		    } else {
			if (!tag.isEnd) {
			    addTag(tag, locale);
			}
			if (attr != null) {
			    String viewerType = attr.getProperty("viewertype");
			    String viewerClass = attr.getProperty("viewerclass");
			    if (viewerType != null && viewerClass != null) {
				ClassLoader cl = HelpSet.class.getClassLoader();
				myHS.setKeyData(kitTypeRegistry,
						viewerType, viewerClass);
				myHS.setKeyData(kitLoaderRegistry,
						viewerType, cl);
			    }
			}
		    }
		}
	    }
	}

	public void piFound(ParserEvent e) {
	    factory.processPI(myHS, e.getTarget(), e.getData());
	}

	public void doctypeFound(ParserEvent e) {
	    factory.processDOCTYPE(e.getRoot(), e.getPublicId(), e.getSystemId());
	}

	private void checkNull(String name, String t) {
	    if (! t.equals("")) {
		parsingError("helpset.wrongText", name, t);
	    }
	}

	public void textFound(ParserEvent e) {
	    debug("textFound: ");
	    debug("  text: "+e.getText());

	    if (tagStack.empty()) {
		return;		// ignore
	    }
	    LangElement le = (LangElement) tagStack.peek();
	    Tag tag = le.getTag();
	    TagProperties attr = tag.atts;
	    Hashtable ht = (attr == null) ? null : attr.getHashtable();
	    String text = e.getText().trim();
	    String name = tag.name;

	    if (name.equals("helpset")) {
		// HELPSET tag
		checkNull("helpset", text);
		return;
	    }
	    int depth = tagStack.size();
	    String pname = "";
	    if (depth >= 2) {
		le = (LangElement) tagStack.elementAt(depth-2);
		pname = ((Tag) le.getTag()).name; // the parent
	    }

	    if (name.equals("title")) {
		// TITLE tag
		if (pname.equals("helpset")) {
		    factory.processTitle(myHS, text);
		} else {
		    presentationTitle = text.trim();
		}
	    } else if (name.equals("homeID")) {
		// HOMEID tag
		factory.processHomeID(myHS, text);
	    } else if (name.equals("mapref")) {
		checkNull("mapref", text);
	    } else if (name.equals("subhelpset")) {
		checkNull("subhelpset", text);
	    } else if (name.equals("data")) {
		// DATA tag -- this is in a view
		viewData = text.trim();
	    } else if (name.equals("label")) {
		// LABEL tag -- this is in a view
		viewLabel = text.trim();
	    } else if (name.equals("name")) {
		// NAME tag -- this is in a view
		tagName = text.trim();
	    } else if (name.equals("helpaction")) {
		// NAME tag -- this is in a view
		helpAction = text.trim();
	    } else if (name.equals("type")) {
		// TYPE tag -- this is in a view
		viewType = text.trim();
            } else if (name.equals("image")) {
                // IMAGE tag -- this is in the view
                tagImage = text.trim();
	    } else if (name.equals("view")) {
		// VIEW tag
		checkNull("view", text);
	    } else if (name.equals("maps")) {
		// MAP tag
		checkNull("maps", text);
            } else if (name.equals("mergetype")) {
                 checkNull("mergetype",text);
            }
	}

	/**
	 * Method used to parse a HelpSet.
	 */
	public void errorFound(ParserEvent e) {
	    // Ignore it for now
	}

	/**
	 * Method used to parse a HelpSet.
	 */
	public void commentFound(ParserEvent e) {
	    // Ignore it for now
	}
    
    	/**
	 * addTag keeps track of tags and their locale attributes.
	 */
	protected void addTag(Tag tag, Locale locale) {
	    LangElement el = new LangElement(tag, locale);
	    tagStack.push(el);
	    // It's possible for lastLocale not be specified ergo null.
	    // If it is then set lastLocale to null even if locale is null.
	    // It is impossible for locale to be null
	    if (lastLocale == null) {
		lastLocale = locale;
		return;
	    }
	    if (locale == null) {
		lastLocale = locale;
		return;
	    }
	    if (! lastLocale.equals(locale)) {
		lastLocale = locale;
	    }
	}

	/**
	 * removeTag removes a tag from the tagStack. The tagStack is
	 * used to keep track of tags and locales.
	 */
	protected void removeTag(Tag tag) {
	    LangElement el;
	    String name = tag.name;
	    Locale newLocale = null;

	    for (;;) {
		if (tagStack.empty()) 
		    unbalanced(name);
		el = (LangElement) tagStack.pop();
		if (el.getTag().name.equals(name)) {
		    if (tagStack.empty()) {
			newLocale = defaultLocale;
		    } else {
			el = (LangElement) tagStack.peek();
			newLocale = el.getLocale();
		    }
		    break;
		}
	    }
	    // It's possible for lastLocale not be specified ergo null.
	    // If it is then set lastLocale to null even if locale is null.
	    // It also possible for locale to be null so if lastLocale is set
	    // then reset lastLocale to null;
	    // Otherwise if lastLocale doesn't equal locale reset lastLocale to locale
	    if (lastLocale == null) {
		lastLocale = newLocale;
		return;
	    }
	    if (newLocale == null) {
		lastLocale = newLocale;
		return;
	    }
	    if (! lastLocale.equals(newLocale)) {
		lastLocale = newLocale;
	    }
	}

	/**
	 * Handy error message methods.
	 */

	private void parsingError(String key) {
	    String s = HelpUtilities.getText(key);
	    factory.reportMessage(s, false); // tree will be wrong
	}

	private void parsingError(String key, String s) {
	    String msg = HelpUtilities.getText(key, s);
	    factory.reportMessage(msg, false); // tree will be wrong
	}

	private void parsingError(String key, String s1, String s2) {
	    String msg = HelpUtilities.getText(key, s1, s2);
	    factory.reportMessage(msg, false); // tree will be wrong
	}

	private void wrongParent(String name, String pname) {
	    parsingError("helpset.wrongParent", name, pname);
	}
	
	private void unbalanced(String name) {
	    parsingError("helpset.unbalanced", name);
	}

	private void wrongLocale(Locale found, Locale l1, Locale l2) {
	    String msg = HelpUtilities.getText("helpset.wrongLocale",
					     found.toString(),
					     l1.toString(),
					     l2.toString());
	    factory.reportMessage(msg, true); // will continue
	}
    } // End of HelpSetParser

    /**
     * For printf debugging.
     */
    private final static boolean debug = false;
    private static void debug(String str) {
        if (debug) {
            System.out.println("HelpSet: " + str);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy