📄 htmlpane.java
字号:
public HTMLPane()
{
// modified
//registerEditorKitForContentType( "text/html",
// "com.holub.ui.HTMLPane$HTMLPaneEditorKit" );
//setEditorKitForContentType( "text/html", new HTMLPaneEditorKit() );
setEditorKit( new HTMLPaneEditorKit() );
setContentType ( "text/html" );
// modified
//addHyperlinkListener ( new HyperlinkHandler() );
//setEditable ( false );
// Set up to shut down pages gracefully when the parent window
// shuts down. Note that this doesn't work when somebody closes
// the outermost frame by clicking the "X" box, because the
// handler for that event (which typically calls System.exit()) is
// processed before the ancestor event is generated. This omission
// is not a big deal, since the program is shutting down anyway,
// but don't put a println in the following code and be surprised
// when it doesn't get executed.
addAncestorListener
( new AncestorAdapter()
{ public void ancestorAdded(AncestorEvent e)
{ for( Component c=HTMLPane.this; c!=null; c=c.getParent())
{ if( c instanceof Window )
{ ((Window)c).addWindowListener
( new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ handlePageShutdown();
}
}
);
break;
}
}
}
}
);
}
/**
* Since destructors aren't possible, provide a method to handle page
* shut down. Notify the JComponents associated with the custom tags that
* the page is shutting down and do some local housekeeping.
*/
protected void handlePageShutdown()
{
for( Iterator i = contributors.iterator(); i.hasNext(); )
((TagBehavior) i.next() ).destroy();
contributors.clear();
}
/************************************************************************
* If the argument is true, pre-install all custom-tag handlers
* <a href="#customTags">described earlier</a>,
* otherwise install none of the custom-tag handlers.
* The no-arg constructor doesn't install any handlers, so
* <code>new HTMLPane()</code> and <code>new HTMLPane(false)</code>
* are equivalent.
* @param installDefaultTags
*/
public HTMLPane( boolean installDefaultTags )
{ this();
if( installDefaultTags )
{ addTag( "size" , new SizeHandler() );
addTag( "inputAction", new InputActionHandler(this));
addTag( "inputNumber", new InputNumberHandler() );
addTag( "inputDate" , new InputDateHandler() );
}
}
//@constructor-end
/**
* The {@link JEditorPane} uses an editor kits to get a factory of
* {@link View} objects, each of which is responsible for rendering
* an HTML element on the screen. This kit returns a factory that
* creates custom views, and it also modifies the behavior of the
* underlying {@link Document} slightly.
*/
public class HTMLPaneEditorKit extends HTMLEditorKit
{
public ViewFactory getViewFactory()
{ return new CustomViewFactory();
}
public Document createDefaultDocument()
{ //HTMLDocument doc = (HTMLDocument)( super.createDefaultDocument() );
// <0 for synchronous load. Delays the pop up, but allows
// tags that set window size, etc. Default value is 4.
//doc.setAsynchronousLoadPriority(-1);
// The number of tokens to buffer before displaying them.
// A smaller number makes the screen to appear a bit more
// responsive because the system doesn't pause for a long
// time before displaying anything.
//
// doc.setTokenThreshold(10);
//
// This is the default value. If it's false, then
// custom tags won't be recognized.
//
// doc.setPreservesUnknownTags( true );
// the createDefaultDocument in the EkitCore
StyleSheet styles = getStyleSheet();
StyleSheet ss = new StyleSheet();
ss.addStyleSheet(styles);
ExtendedHTMLDocument doc = new ExtendedHTMLDocument(ss);
doc.setParser(getParser());
doc.setAsynchronousLoadPriority(4);
doc.setTokenThreshold(100);
return doc;
//return doc;
}
/** Return a parser that wraps the real one. This is the
* only convenient way to get a handle to the input
* stream that the parser uses: Supply an input-stream
* decorator that preprocesses the input before
* the parser reads it.
* <p>Using a preprocessor at all
* is a kludge, but creating a DOM from user
* supplied HTML and inserting it into the
* HTMLDocument is nasty, and probably slower.
* <p>
* <code>Parser</code> and <code>ParserCallback</code>
* are both inner classes of the {@link HTMLEditorKit}
* base class.
*/
protected Parser getParser()
{ final Parser p = super.getParser();
return new Parser()
{ public void parse( Reader r,
ParserCallback callBack,
boolean ignoreCharSet
) throws IOException
{ p.parse( filterProvider.inputFilter(r),
callBack, ignoreCharSet );
}
};
}
}
//@editor-kit-end
/*******************************************************************
* Create Views for the various HTML elements. This factory differs from
* the standard one in that it can create views that handle the
* modifications that I've made to EditorKit. For the most part, it
* just delegates to its base class.
*/
private final class CustomViewFactory extends HTMLEditorKit.HTMLFactory
{
// Create views for elements.
// Note that the views are not created as the elements
// are encountered; rather, they're created more or less
// at random as the elements are displayed. Don't do anything here
// that depends on the order in which elements appear in the input.
//
// Also note that undefined start-element tags are not in any way
// linked to the matching end-element tag. They two might move
// around arbitrarily.
public View create(Element element)
{ // dumpElement( element );
HTML.Tag kind = (HTML.Tag)(
element.getAttributes().getAttribute(
javax.swing.text.StyleConstants.NameAttribute) );
if( (kind==HTML.Tag.INPUT) || (kind==HTML.Tag.SELECT)
|| (kind==HTML.Tag.TEXTAREA) )
{
// Create special views that understand Forms and
// route submit operations to form observers only
// if observers are registered.
//
FormView view = (actionListeners != null)
? new LocalFormView( element )
: (FormView)( super.create(element) )
;
String type = (String)( element.getAttributes().
getAttribute(HTML.Attribute.TYPE));
return view;
}
else if( kind instanceof HTML.UnknownTag )
{ // Handling a custom element. End tags are silently ignored.
if( element.getAttributes().
getAttribute(HTML.Attribute.ENDTAG) == null)
{
final Component view = doTag( element );
if( view != null )
{ return new ComponentView(element)
{ protected Component createComponent()
{ return view;
}
};
}
// else fall through and return default (invisible) View
}
} else if(kind instanceof HTML.Tag)
{ // EkitCore handles IMG tag
HTML.Tag tagType = (HTML.Tag)kind;
if(tagType == HTML.Tag.IMG)
{
return new RelativeImageView(element);
}
}
return super.create(element);
}
}
//@view-factory-end
/*******************************************************************
* Handle a request to process a custom tag. If no handler for
* a given tag is found, the fact is logged to the com.holub.ui
* logger, and the tag is ignored.
*
* @param element The element that we're handling
*
*
* @return a JComponent to use as the view or <code>null</code>
* if there is no view.
*/
private final Component doTag( Element element )
{
if( element == null ) // it does happen!
return null;
String name = element.getName();
if( name == null )
name = "Unknown" ;
// Extract the attributes and tag name from the Element:
Properties attributes = new Properties();
AttributeSet set = element.getAttributes();
for( Enumeration i = set.getAttributeNames(); i.hasMoreElements(); )
{ Object current = i.nextElement ();
String attributeName = current.toString ();
Object attributeValue = set.getAttribute (current);
attributes.put
( (current instanceof StyleConstants)? TAG_NAME: attributeName,
attributeValue.toString()
);
}
// Now look for a handler for the tag. If there isn't one, just
// return null, which effectively causes the tag to be ignored.
TagHandler handler = (TagHandler)( tagHandlers.get(name) );
if( handler == null )
{ log.warning( "Couldn't find handler for <" +name+ ">" );
return null;
}
// There is a handler, call it to do the work. Return whatever
// component the handler returns.
JComponent component = handler.handleTag(this,attributes);
if( component instanceof TagBehavior )
contributors.add( component );
return ( component );
}
//@do-tag-end
/*******************************************************************
* Special handling for elements that can occur inside forms.
*/
public final class LocalFormView extends javax.swing.text.html.FormView
{
public LocalFormView( Element element )
{ super(element);
}
/** Chase up through the form hierarchy to find the
* <code><form></code> tag that encloses the current
* <code><input></code> tag. There's a similar
* method in the base class, but it's private so I can't use it.
*/
private Element findFormTag()
{ for(Element e=getElement(); e != null; e=e.getParentElement() )
if(e.getAttributes().getAttribute(StyleConstants.NameAttribute)
==HTML.Tag.FORM )
return e;
throw new Error("HTMLPane.LocalFormView Can't find <form>");
}
/** Override the base-class method that actually submits the form
* data to process it locally instead if the URL in the action
* field matches the "local" URL.
*/
protected void submitData(String data)
{ //System.out.println("Data [" + data + "]");
AttributeSet attributes = findFormTag().getAttributes();
String action =
(String)attributes.getAttribute(HTML.Attribute.ACTION);
String method =
(String)attributes.getAttribute(HTML.Attribute.METHOD);
String name =
(String)attributes.getAttribute(HTML.Attribute.NAME);
if( action == null ) action = "";
if( method == null ) method = "";
if (name == null) name = "";
// modified
//handleSubmit( method.toLowerCase(), action, data );
handleSubmit( method.toLowerCase(), action, name, data );
}
/** Override the base-class image-submit-button class. Given the tag:
* <PRE>
* <input type="image" src="grouchoGlasses.gif"
* name=groucho value="groucho.pressed">
* </PRE>
* The data will hold only two properties:
* <PRE>
* groucho.y=23
* groucho.x=58
* </PRE>
* Where 23 and 58 are the image-relative positions of the mouse when
* the user clicked. (Note that the value= field is ignored.)
* Image tags are useful primarily for implementing a cancel button.
* <p>
* This method does nothing but chain to the standard submit-
* processing code, which can figure out what's going on by
* looking at the attribute names.
*/
protected void imageSubmit(String data)
{ submitData(data);
}
/** Special processing for the reset button. I really want to
* override the base-class resetForm() method, but it's package-
* access restricted to javax.swing.text.html.
* I can, however, override the actionPerformed method
* that calls resetForm() (Ugh).
*/
public void actionPerformed( ActionEvent e )
{ String type = (String)( getElement().getAttributes().
getAttribute(HTML.Attribute.TYPE));
if( type.equals("reset") )
doReset( );
super.actionPerformed(e);
}
/** Make transparent any standard components used for input.
* The default components are all opaque with a gray (0xd0d0d0)
* background, which looks awful when you've set the background
* color to something else (or set it to an image) in the
* <code><body></code> tag. Setting opaque-mode
* off lets the specified background color show through the
* <code><input></code> fields.
*/
// modified
/*protected Component createComponent()
{ JComponent widget = (JComponent)( super.createComponent() );
// The widget can be null for things like type=hidden fields
if( widget != null )
{
if( !(widget instanceof JButton) )
widget.setOpaque(false);
// Adjust the alignment of everything except multiline text
// fields so that the control straddles the text baseline
// instead of sitting on it. This adjustment will make
// buttons and the text within a single-line text-input
// field align vertically with any adjacent text.
if( !(widget instanceof JScrollPane) ) // <input>
{ widget.setAlignmentY( BASELINE_ALIGNMENT );
}
else
{ // a JList is a <select>, a JTextArea is a <textarea>
Component contained =
((JScrollPane)widget).getViewport().getView();
// If it's a select, change the width from the default
// (full screen) to a bit wider than the actual contained
// text.
if( contained instanceof JList )
{ widget.setSize( contained.getPreferredSize() );
Dimension idealSize = contained.getPreferredSize();
idealSize.width += 20;
idealSize.height += 5;
widget.setMinimumSize ( idealSize );
widget.setMaximumSize ( idealSize );
widget.setPreferredSize( idealSize );
widget.setSize ( idealSize );
}
}
}
return widget;
}*/
}
//@local-form-view-end
/*******************************************************************
* Used by {@link HTMLPane} to pass form-submission information to
* any ActionListener objects.
* When a form is submitted by the user, an actionPerformed() message
* that carries a FormActionEvent is sent to all registered
* action listeners. They can use the event object to get the
* method and action attributes of the form tag as well as the
* set of data provided by the form elements.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -