⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htmlpane.java

📁 Semantic Web Ontology Editor
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
// (c) 2003 Allen I Holub. All rights reserved.
package com.holub.ui.HTML;

import com.hexidec.ekit.component.ExtendedHTMLDocument;
import com.hexidec.ekit.component.RelativeImageView;
import com.holub.net.UrlUtil;
import com.holub.tools.Log;
import com.holub.ui.AncestorAdapter;

import com.holub.ui.HTML.TagBehavior;
import com.holub.ui.HTML.FilterFactory;

import java.io.*;
import java.util.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.*;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.text.*;	// View Element ViewFactory
import javax.swing.text.html.*;
import javax.swing.event.*;
import javax.swing.border.*;

// See full documentation for this class in last-month's article
/*** ****************************************************************
 *  This class let's you build an HTML-based interface with JSP-like
 *	functionality that operates entirely within the confines of a
 *	client-side program---no web server is necessary.
 *	<code>HTMLPane</code> also fixes several problems in {@link JEditorPane}'s
 *	HTML support, but it is based on {@link JEditorPane}, so has many of its
 *	limitations.
 *	<p>
 *	<code>HTMLPane</code> augments {@link JEditorPane} in several ways:
 *	<ul>
 *	<li>An <code>HTMLPane</code> logs errors to the com.holub.ui logger
 *	rather than throwing exceptions in many situations. You can hook
 *	into these messages by creating a logger (described below).
 *	<li>I've improved the appearance of form elements a bit:
 *			<ul>
 *			<li>Radio buttons and text-input fields are now aligned properly
 *			with the surrounding text
 *			<li>The list created by a <code>&lt;select&gt;</code>
 *			element is now only a little wider than the contained text
 *			(instead of taking up the full screen).
 *			<li>Radio buttons and check boxes have transparent backgrounds so that
 *			they don't look weird against background textures and
 *			colors that aren't dark grey (<code>bgcolor="d0d0d0"</code>).
 *	</ul>
 *	<li>You can add {@linkplain #addTag custom tags} and handlers for them,
 *	so you add JSP-style behavior to your forms.
 *	<li>You can specify a local form-data handler that's invoked in
 *	response to both submit-style and cancel-style operations. That is,
 *	clicking a "Submit" button causes a chuck of code (that you provide)
 *	to execute rather than sending the form data to a remote server.
 *	<li>
 *	HTTP hyperlinks are supported, but note that the JDK 1.4 runtime
 *	does not support the format: "file://c:/file."
 *	You have to use "file:/c:/file" (one slash).
 *	Strictly speaking, the 1.4 behavior is actually "correct," but some
 *	the rules for forming a "correct" URL are not well known, and the
 *	lack of a support for a double slash might be frustrating.
 *	<li>
 *	Mailto: hyperlinks are supported, but only on the Windows platform.
 *	Subject lines have to be properly URL encoded, (with %20 used for spaces,
 *	etc.). For example:
 *	<PRE>
 *	&lt;a href="mailto:allen@holub.com?subject=foo%20bar"&gt;
 *	</PRE>
 *	Attempts to use mailto on other platforms result in a
 *	logged warning, but are otherwise silently absorbed.
 *	<li>
 *	The <code>&lt;a target=_blank ...&gt;</code> attribute now correctly
 *	causes the page to pop up in its own window. The window is a
 *	<code>pack()</code>ed frame that holds an HTMLPane, so your custom-tag
 *	handlers will work in the popup.
 *	<li>
 *	Standard http: and file: hyperlinks and relative URLs are handled
 *	internally, but only those hyperlinks that reference files that end
 *	in certain {@linkplain #redirect(URL) file
 *	extensions} are processed.
 *	Other protocols (e.g. ftp:) are not supported.
 *	<li>
 *	<code>HTMLPane</code> supports a
 *	{@linkplain #addHostMapping(String,String) host-mapping feature}
 *	that let's you specify maps between the "host" part of a URL and an
 *	arbitrary map-to URL. All hyperlinks aimed at the host will end up
 *	at the map-to location. This way you can map network URLs to
 *	file:// URLs for testing or non-network use.
 *	</ul>
 *	<p>
 *	<font size=+1><b>Logging</b></font>
 *	</p>
 *	The <code>HTMLPanel</code> logs errors and warnings to the
 *	com.holub.ui logger.
 *	To view the messages from all programs that use <code>HTMLPanel</code>,
 *	modify the .../jre/lib/logging.properties file,
 *	setting the <i>.level</i> and
 *	<i>java.util.logging.ConsoleHandler.level</i>
 *	properties to <i>ALL</i>. You can also
 *	put the following code into your program to turn on logging for
 *	that program only:
 *	<PRE>
 *  static
 *  {   Logger  log = Logger.getLogger("com.holub.ui");
 *      Handler h = new ConsoleHandler();
 *      h.  setLevel(Level.ALL);
 *      log.setLevel(Level.ALL);
 *      log.addHandler(h);
 *  }
 *  </PRE>
 *  You can turn logging off by specifying Level.OFF instead of ALL.
 *  The {@link com.holub.tools.Log} class provides convenience
 *  methods for controlling logging.
 *	<p>
 *  <a name="customTags">
 *	    <font size=+1><b>Custom Tags</b></font>
 *  </a>
 *	<p>
 *	You can define custom tags that can be used in your .html input,
 *	in a manner similar to a custom JSP tag. Set up a new tab by calling
 *	{@link #addTag addTag(...)}, passing it
 *	an object that identifies a {@linkplain TagHandler tag handler}
 *	that's activated when the tag is encountered.
 *	 (See {@link #addTag addTag(...)} for more information.)
 *	 <p>
 *	 Because java's {@link
 *	 javax.swing.JEditorPane}
 *	 underlies the current class, you can't define a namespace-style
 *	 custom tag: a name like
 *	 <code>&lt;holub:myTag ...&gt;</code> (that contains a colon)
 *	 isn't recognized. You can use underscores, but that's a kludge.
 *	 <p>
 *	 Also, the current implementation of custom tags does not permit the
 *	 element to have content. The problem is that the default parser
 *	 does not pair non-HTML tags. That is, <code>&lt;foo&gt;</code>
 *	 and <code>&lt;/foo&gt;</code> are treated as completely
 *	 independent tags with no connection between them. The only
 *	 solution is to effectively rewrite the parser, but that's
 *	 a lot of work for not much gain. Future versions of this
 *	 class might permit content, however.
 *	<p> Several pre-built custom tags are provided. Add support for
 *	these by issuing one of the following calls to you <code>HTMLPane</code>:
 *	<PRE>
 *  pane.{@link #addTag addTag}( "size"        , new {@link SizeHandler SizeHandler}()            );
 *  pane.{@link #addTag addTag}( "inputAction", new {@link InputActionHandler InputActionHandler}(this));
 *  pane.{@link #addTag addTag}( "inputNumber", new {@link InputNumberHandler InputNumberHandler}()    );
 *  pane.{@link #addTag addTag}( "inputDate"  , new {@link InputDateHandler InputDateHandler}()      );
 *  </PRE>
 * (These tags are all installed for you if you use the
 * {@link #HTMLPane(boolean)} constructor).
 *
 *	<PRE>
&lt;size  height=400 width=400&gt;
 *	</PRE>
 *	<p style="padding-left:2em">
 *		Specifies the size of the pane in pixels.
 *	</p>
 *	<PRE>
 *  <a name="inputAction">
&lt;inputAction name="myName" value="text"&gt
 *	</PRE>
 *	<p style="padding-left:2em">
 *	This tag inserts a submit-style button that causes actionPerformed
 *	messages to be sent to all registered action listeners (as if the
 *	submit button had been pressed). The method and action attributes
 *	of the passed FormActionEvent will be empty (not null) Strings, and the
 *	data Properties object holds the pair <code>name=<em>XXX</em></code>,
 *	where <em>name</em> was specified using the <em>name=xxx</em> attribute in
 *	the original tag, and <em>XXX</em> holds the value <em>true</em> if the button
 *	was pressed, <em>false</em> if it wasn't.
 *	Key=value pairs supplied by custom
 *	tag handlers [added using {@link #addTag addTag(...)}] are also available, but
 *	the data supplied from standard HTML tags
 *	(<em>&lt;input&gt;</em>, <em>&lt;textarea&gt;</em>, and <em>&lt;select&gt;</em>)
 *	<span style="text-decoration:underline;">is not available</span>.
 *	The value attribute also defines the text
 *	on the button face. This tag is here to make
 *	it easy to implement a "cancel"  or "quit" operation,
 *	but you can actually use it as a generic button if don't need the
 *	form data from the
 *	<em>&lt;input&gt;</em>, <em>&lt;textarea&gt;</em>, or <em>&lt;select&gt;</em>
 *	tags.
 *	</p>
 *	</a>
 *	<PRE>
&lt;inputNumber name="fred" value="0.0" min="0" max="100" precision="2" size=<em>n</em>&gt;
 *	</PRE>
 *	<p style="padding-left:2em">
 *	Like an &lt;input type=text&gt; tag, but inputs a numeric value
 *	in the range <em>min</em> &le; <em>N</em> &le; <em>max</em>, with up to <em>precision</em> digits
 *	permitted to the right of the decimal point (<em>precision can be zero</em>).
 *	The optional <em>size</em> attribute is the width of the field in columns.
 *	</p>
 *	 <PRE>
&lt;inputDate name="fred" value="10/15/03" size=<em>n</em>&gt;
 *	 </PRE>
 *	<p style="padding-left:2em">
 *	A localized date-input field that does data validation when it looses focus or you hit Enter.
 *	Most common date formats are recognized, and a popup dialog lets you choose dates from
 *	a calendar.
 *	The initial value, if present, must specify a date. (An empty string isn't permitted.)
 *	If no value= attribute is specified, today's date is used as the initial value.
 *	The optional <em>size</em> attribute is the width of the field in columns.
 *	(An approximation is used to size the control.)
 *	</p>
 *
 *	<p>
 *	<font size=+1><b>Form Processing</b></font>
 *	 <p>
 *	 Normally, when an HTML form is submitted, the JEditorPane tries to
 *	 actually execute and HTTP POST or GET operation on a remote server,
 *	 passing it the data associated with the form elements as name=value
 *	 pairs.
 *	 <p>
 *	 You can modify form-processing behavior, so that a form is submitted
 *	 to the current program rather than to some server out on the net somewhere.
 *	 Just add an {@link java.awt.event.ActionListener} to the HTMLPane by
 *	 calling {@link #addActionListener addActionListener(...)}. The
 *	 {@link java.awt.event.ActionListener#actionPerformed} method of the listener
 *	 is called when the user hits the submit button. The associated
 *	 <code>ActionEvent</code> object is actually an instance of the
 *	 {@link FormActionEvent} class, and you can get the submit
 *	 data from it.
 *	 You may add as many action listeners as you like (they are all passed
 *	 same event object). This way, the handlers can
 *	 examine the <code>action=</code> attribute of the <code>&lt;form&gt;</code>
 *	 tag and process data only if the associated URL is of interest.
 *	 Once you've added any form handlers,
 *	 <u>all</u> form submissions will go to them rather than being posted to the
 *	 target URL. Your handler can relay the data to the web if it likes, but
 *	 it must do so if you want that behavior.
 *	 <p>
 *	 Here's an example of a simple form-submission handler that just prints
 *	 all the form-related information on standard output.
 *	 <PRE>
 *  pane.addActionListener
 *  (   new ActionListener()
 *      {   public void actionPerformed( ActionEvent event )
 *          {
 *              FormActionEvent act = (FormActionEvent)event;
 *
 *              System.out.println("\n"+ act.getActionCommand() );
 *              System.out.println("\t"+"method=" + act.method() );
 *              System.out.println("\t"+"action=" + act.action() );
 *              act.data().list( System.out );
 *              System.out.println("");
 *              try
 *              {   act.source().setPage    // display a "success" page
 *                  ( new URL(
 *                      "file://c:/src/com/holub/ui/HTML/test/submit.html")
 *                  );
 *              }
 *              catch( Exception e )
 *              {   e.printStackTrace();
 *              }
 *              System.out.println("");
 *          }
 *      }
 *  );
 *  </PRE>
 *	<p>
 *	<font size=+1><b>Known Problems</b></font>
 *	<p>
 *	This class is based on {@link JEditorPane}, which does not
 *	use the world's best HTML parser. The following problems that are caused
 *	by Sun's parser aren't fixed in the current implementation:
 *	<ol>
 *	<li>The parser is dog slow.
 *	<li>CSS support is seriously broken. Styles are useless.
 *	<li>None of the new HTML 4	or XHTML tags are handled.
 *	<li>The parser doesn't handle tables very well.
 *		Very simple table nesting is okay, but complicated stuff fails
 *		miserably.
 *	<li><code>&lt;applet&gt;</code> tags are not supported---they are
 *		actually obsolescent as of HTML 4---but <code>&lt;object&gt;</code>
 *		tags are supported.
 *		Use the latter to embed your applets in a <code>&lt;form&gt;</code>.
 *		See <a href="http://java.sun.com/j2se/1.4/docs/guide/plugin/developerGuide/usingTags.html">
 *		the Java-plugin docs</a> for a discussion of the correct way to do this.
 *	<li>The JDK 1.4 parser parser does not handle
 *		<code>&lt;input type=submit name=x value=y&gt;</code>
 *		correctly (The problem is fixed in JDK ver. 1.5).
 *		In particular, the name=value string is not placed in the
 *		form data as it should be, so you cannot use multiple
 *		type=submit input fields in a single form.
 *		The new &lt;button&gt; and &lt;input type=button&gt; elements aren't
 *		supported either, so you can't use that tag.
 *		<p>
 *		I've added a &lt;inputAction value="Text"&rt; tag for simple
 *		situations, but the implementation of the cancel tag does not
 *		give you access to the data that would com in with a normal
 *		submit operation.
 *	<li>The <code>JEditorPane</code> base class doesn't understand
 *		<code>&lt;script&gt;</code>
 *		tags (or JavaScript)---it just
 *		displays as normal text the contents of all
 *		<code>&lt;script&gt;</code> elements that are not nested inside
 *		comments.
 *		Unfortunately,
 *		javadoc-generated HTML doesn't follow the nest-script-in-comments
 *		convention, so you can't easily use <code>JEditorPane</code>
 *		as a Java-documentation browser.
 *	<li>The {@link JEditorPane} doesn't do frames correctly when you customize
 *		it (as I've done here).
 *		Frames appear to work, but pages displayed within
 *		frames are processed as if you were using a standard {@link
 *		javax.swing.JEditorPane}, with
 *		none of the features described here available to you. Consequently,
 *		you can't really use HTML frames. You can, however, create several
 *		HTMLPane instances and arrange them inside a JPanel (or other
 *		container) using a GridbagLayout or GridLayout.
 *	</ol>
 *	<p>
 *	I'm hoping that at least some {@link EditorKit} behavior
 *	will eventually get fixed. My guess is that the more fundamental
 *	structural problems (like the broken frame stuff) will probably
 *	stay broken, so the only long term solution is to toss the
 *	Sun implementation and replace it with something that works.
 *	<p>
 *	<DL>
 *	  <DT><B>Requires:</B></DT>
 *	  <DD>JDK1.4 (Regular expressions and
 *	  	<code>assert</code> statements are used.)
 *	  </DD>
 *	</DL>
 *
 * <!-- ====================== distribution terms ===================== -->
 * <p><blockquote
 * 	style="border-style: solid; border-width:thin; padding: 1em 1em 1em 1em;">
 * <center>
 * 			Copyright &copy; 2003, Allen I. Holub. All rights reserved.
 * </center>
 * <br>
 * <br>
 * 		This code is distributed under the terms of the
 * 		<a href="http://www.gnu.org/licenses/gpl.html"
 * 		>GNU Public License</a> (GPL)
 * 		with the following ammendment to section 2.c:
 * 		<p>
 * 		As a requirement for distributing this code, your splash screen,
 * 		about box, or equivalent must include an my name, copyright,
 * 		<em>and URL</em>. An acceptable message would be:
 * <center>
 * 		This program contains Allen Holub's <em>XXX</em> utility.<br>
 * 				(c) 2003 Allen I. Holub. All Rights Reserved.<br>
 * 						http://www.holub.com<br>
 * </center>
 * 		If your progam does not run interactively, then the foregoing
 * 		notice must appear in your documentation.
 * </blockquote>
 * <!-- =============================================================== -->
 * @author Allen I. Holub
 */

//public class HTMLPane extends JEditorPane
// EkitCore needs to extend from JTextPane
// HTMLPane handles well customized tags
public class HTMLPane extends JTextPane
{
	private FilterFactory filterProvider = FilterFactory.NULL_FACTORY;

	private static	final Logger log = Logger.getLogger("com.holub.ui");

	/** A map of actual host names to replacement names, set by
	 *	 {@link #addHostMapping}
	 */
	private static  Map	  hostMap	 = null;

	/** Maps tags to Publishers of {@linkplain TagHandler handlers} for
	 *	 that tag
	 */
	private Map tagHandlers =
						Collections.synchronizedMap(new HashMap());

	/** A list of all components provided by a TagHandler that
	 *	 support the {@link TagBehavior} interface.
	 */

	private ActionListener actionListeners = null;


	/** A list of all JComponents that act as stand in for custom
	 *	tags that also implement TagBehavior.
	 */
	private Collection contributors = new LinkedList();

	/**
	 *	The name used as a key to get the tag-name attribute out of
	 *	the attributes passed to a TagHandler object.
	 */
	public static final String TAG_NAME = "<tagName>";

	/**
	 * All controls created from HTML tags (except for multi-line text input)
	 * are positioned so that they're aligned
	 * properly with respect to the text baseline. This way a radio button,
	 * for example, will line up with the text next to it. If you create
	 * a control of your own to be displayed in place of to a custom tag,
	 * you may want to issue a:
	 * <PRE>
	 * widget.setAlignmentY( BASELINE_ALIGNMENT );
	 * </PRE>
	 * request to get it aligned the same way as the standard controls
	 */

	public static final float BASELINE_ALIGNMENT = 0.70F;

	//@constructor-start
	/**
	 *	Create an empty pane. Populate it by calling
	 *	{@link JEditorPane#setPage(URL)} or {@link JEditorPane#setText(String)}
	 *	<PRE>
 	 *	HTMLPane form  = new HTMLPane();
	 *	form.setPage( new URL("file://test.html") );
	 *	</PRE>
	 *	(For reasons that are not clear to me, the URL and String versions
	 *	of the base-class constructors don't work when called from
	 *	a derived-class constructor, so these base-class constructors
	 *	are not exposed here.)
	 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -