// HTMLParser Library $Name: v1_6_20060319 $ - A java-based parser for HTML // http://sourceforge.org/projects/htmlparser // Copyright (C) 2005 Derrick Oswald // // Revision Control Information // // $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/parserapplications/filterbuilder/Filter.java,v $ // $Author: derrickoswald $ // $Date: 2005/04/12 11:27:42 $ // $Revision: 1.2 $ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // package org.htmlparser.parserapplications.filterbuilder; import java.awt.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Hashtable; import java.util.Vector; import javax.swing.*; import javax.swing.border.*; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.parserapplications.filterbuilder.layouts.VerticalLayoutManager; /** * Base class for all filters. * Provides common functionality applicable to all filters. */ public abstract class Filter extends JComponent implements NodeFilter { /** * Create a new filter from the class name. * @param class_name The class to instatiate. * @return The constructed filter object. */ public static Filter instantiate (String class_name) { Filter ret; ret = null; try { Class cls = Class.forName (class_name); ret = (Filter)cls.newInstance (); mWrappers.put (ret.getNodeFilter ().getClass ().getName (), class_name); } catch (ClassNotFoundException cnfe) { System.out.println ("can't find class " + class_name); } catch (InstantiationException ie) { System.out.println ("can't instantiate class " + class_name); } catch (IllegalAccessException ie) { System.out.println ("class " + class_name + " has no public constructor"); } catch (ClassCastException cce) { System.out.println ("class " + class_name + " is not a Filter"); } return (ret); } /** * Map from cilter class to wrapper. * Populated as part of each wrapper being loaded. */ protected static Hashtable mWrappers = new Hashtable (); /** * Create a filter. * Set up the default display. * Only a border with the label of the filter name, * returned by <code>getDescription()</code>, * and an icon, returned by <code>getIcon()</code>. */ public Filter () { JLabel label; Dimension dimension; Insets insets; setToolTipText (getDescription ()); // none of these quite does it: // new BoxLayout (this, BoxLayout.Y_AXIS)); // new GridLayout (0, 1)); setLayout (new VerticalLayoutManager ()); setSelected (false); label = new JLabel (getDescription (), getIcon (), SwingConstants.LEFT); label.setBackground (Color.green); label.setAlignmentX (Component.LEFT_ALIGNMENT); label.setHorizontalAlignment (SwingConstants.LEFT); add (label); dimension = label.getMaximumSize (); insets = getInsets (); dimension.setSize (dimension.width + insets.left + insets.right, dimension.height + insets.top + insets.bottom); setSize (dimension); } /** * Get the name of the filter. * @return A descriptive name for the filter. */ public abstract String getDescription (); /** * Get the underlying node filter object. * @return The node filter object suitable for serialization. */ public abstract NodeFilter getNodeFilter (); /** * Assign the underlying node filter for this wrapper. * @param filter The filter to wrap. * @param context The parser to use for conditioning this filter. * Some filters need contextual information to provide to the user, * i.e. for tag names or attribute names or values, * so the Parser context is provided. */ public abstract void setNodeFilter (NodeFilter filter, Parser context); /** * Get the underlying node filter's subordinate filters. * @return The node filter object's contained filters. */ public abstract NodeFilter[] getSubNodeFilters (); /** * Assign the underlying node filter's subordinate filters. * @param filters The filters to insert into the underlying node filter. */ public abstract void setSubNodeFilters (NodeFilter[] filters); /** * Convert this filter into Java code. * Output whatever text necessary and return the variable name. * @param out The output buffer. * @param context Three integers as follows: * <li>indent level - the number of spaces to insert at the beginning of each line</li> * <li>filter number - the next available filter number</li> * <li>filter array number - the next available array of filters number</li> * @return The variable name to use when referencing this filter (usually "filter" + context[1]++) */ public abstract String toJavaCode (StringBuffer out, int[] context); /** * Get the icon for the filter. * Loads the resource specified by * <code>getIconSpec()</code> as an icon. * @return The icon or null if it was not found. */ public Icon getIcon () { ImageIcon ret; ret = null; try { ret = new ImageIcon (getClass ().getResource (getIconSpec ())); } catch (NullPointerException npe) { System.err.println ("can't find icon " + getIconSpec ()); } return (ret); } /** * Get the resource name for the icon. * @return The icon resource specification. */ public abstract String getIconSpec (); // // Component overrides // /** * Returns a string representation of this component and its values. * @return A string representation of this component. */ public String toString () { return (getDescription () + " [" + this.getClass ().getName () + "]"); } // // utilities // /** * Serialize an object to a byte array. * @param object The object to be pickled. * @return The serialized object. * @exception IOException If the output stream complains (unlikely). */ public static byte[] pickle (Object object) throws IOException { ByteArrayOutputStream bos; ObjectOutputStream oos; byte[] ret; bos = new ByteArrayOutputStream (); oos = new ObjectOutputStream (bos); oos.writeObject (object); oos.close (); ret = bos.toByteArray (); return (ret); } /** * Reconstitute a serialized object. * @param data The pickled object. * @return The reconstituted object. * @exception IOException If the input stream complains. * @exception ClassNotFoundException If the serialized object class cannot * be located. */ public static Object unpickle (byte[] data) throws IOException, ClassNotFoundException { ByteArrayInputStream bis; ObjectInputStream ois; Object ret; bis = new ByteArrayInputStream (data); ois = new ObjectInputStream (bis); ret = ois.readObject (); ois.close (); return (ret); } /** * Serialize a byte array to a String. * Convert each byte from the serialized object into a couple of hexadecimal * characters. * @param data The serialized object as a byte array. * @return The string representing the serialized object. */ public static String serialize (byte[] data) { String string; StringBuffer ret; ret = new StringBuffer (data.length * 2); for (int i = 0; i < data.length; i++) { string = Integer.toString (0xff & data[i], 16); if (string.length () < 2) ret.append ("0"); ret.append (string); } return (ret.toString ()); } /** * Convert a sequence of hexadecimal characters back into a byte array. * @param string The string to convert (must be correct hex characters). * @return The bytes as an array. */ public static byte[] deserialize (String string) { byte[] ret; ret = new byte[string.length () / 2]; for (int i = 0; i < string.length (); i += 2) ret[i/2] = (byte)Integer.parseInt (string.substring (i, i + 2), 16); // todo: hopelessly inefficient return (ret); } /** * Returns a string serialization of the filters. * @param filters The list of filters to serialize. * @return A string representation of the filters. * @exception IOException If serialization fails. */ public static String deconstitute (Filter[] filters) throws IOException { StringBuffer ret; ret = new StringBuffer (1024); for (int i = 0; i < filters.length; i++) { ret.append ("["); ret.append (serialize (pickle (filters[i].getNodeFilter ()))); ret.append ("]"); } return (ret.toString ()); } /** * Returns the filters represented by the string. * @param string The string with serialized node filters. * @param context The context from which to extract meaningful values * for GUI choices (which aren't serialized). * @return The filters gleaned from the string. * @see #wrap */ public static Filter[] reconstitute (String string, Parser context) { Filter[] ret; Vector vector; int index; String code; Object object; Filter filter; vector = new Vector (); try { while (string.startsWith ("[")) { index = string.indexOf (']'); if (-1 != index) { code = string.substring (1, index); string = string.substring (index + 1); object = unpickle (deserialize (code)); if (object instanceof NodeFilter) { filter = wrap ((NodeFilter)object, context); if (null != filter) vector.addElement (filter); } else break; } else break; } } catch (Exception e) { e.printStackTrace (); } ret = new Filter[vector.size ()]; vector.copyInto (ret); return (ret); } /** * Get the enclosed sub filter list if any. * Todo: rationalize with FilterBuilder's method(s) of the same name. * @param component The component that's supposedly enclosing the list. * @return The enclosed component or <code>null</code> otherwise. */ protected static SubFilterList getEnclosed (Component component) { Component[] list; if (component instanceof Container) { list = ((Container)component).getComponents (); for (int i = 0; i < list.length; i++) if (list[i] instanceof SubFilterList) return ((SubFilterList)list[i]); } return (null); } /** * Returns a wrapped filter. * @param filter A filter to be wrapped by GUI components. * @param context The context within which to wrap the object. * Some wrappers need context to set up useful choices for the user. * @return The filter to wrap. */ public static Filter wrap (NodeFilter filter, Parser context) { String class_name; NodeFilter[] filters; SubFilterList list; Filter ret; ret = null; class_name = filter.getClass ().getName (); class_name = (String)mWrappers.get (class_name); if (null != class_name) { try { ret = Filter.instantiate (class_name); ret.setNodeFilter (filter, context); // recurse into subfilters filters = ret.getSubNodeFilters (); if (0 != filters.length) { list = getEnclosed (ret); if (null != list) { ret.setSubNodeFilters (new NodeFilter[0]); // clean out the unwrapped filters for (int i = 0; i < filters.length; i++) list.addFilter (wrap (filters[i], context)); } else throw new IllegalStateException ("filter can't have subnodes without a SubFilterList on the wrapper"); } } catch (Exception e) { e.printStackTrace (); } } else System.out.println (class_name + " is not registered for wrapping."); return (ret); } /** * Set the 'selected look' for the component. * @param selected If <code>true</code>, 'select' this component, * otherwise 'deselect' it. */ public void setSelected (boolean selected) { if (selected) setBorder ( new CompoundBorder ( new EtchedBorder (), new CompoundBorder ( new LineBorder(Color.blue, 2), new EmptyBorder (1, 1, 1, 1)))); else setBorder ( new CompoundBorder ( new EtchedBorder (), new EmptyBorder (3,3,3,3))); } /** * Set the expanded state for the component. * This sets invisible all but the JLabel component in the * comand component. * @param expanded If <code>true</code>, 'expand' this component, * otherwise 'collapse' it. */ public void setExpanded (boolean expanded) { Component[] components; components = getComponents (); for (int i = 0; i < components.length; i++) if (!(components[i] instanceof JLabel)) components[i].setVisible (expanded); } /** * Append count spaces to the buffer. * @param out The buffer to append to. * @param count The number of spaces to append. */ public static void spaces (StringBuffer out, int count) { for (int i = 0; i < count; i++) out.append (' '); } /** * Append a newline to the buffer. * @param out The buffer to append to. */ public static void newline (StringBuffer out) { out.append ('\n'); } }