📄 browser.java
字号:
//#condition polish.usePolishGui
/*
* Created on 11-Jan-2006 at 19:20:28.
*
* Copyright (c) 2007 Michael Koch / Enough Software
*
* This file is part of J2ME Polish.
*
* J2ME Polish is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* J2ME Polish 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with J2ME Polish; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Commercial licenses are also available, please
* refer to the accompanying LICENSE.txt or visit
* http://www.j2mepolish.org for details.
*/
package de.enough.polish.browser;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Stack;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import de.enough.polish.browser.protocols.HttpProtocolHandler;
import de.enough.polish.browser.protocols.ResourceProtocolHandler;
import de.enough.polish.io.RedirectHttpConnection;
import de.enough.polish.io.StringReader;
import de.enough.polish.util.HashMap;
import de.enough.polish.xml.SimplePullParser;
import de.enough.polish.xml.XmlPullParser;
//#if polish.LibraryBuild
//# import de.enough.polish.ui.FakeContainerCustomItem;
//#else
import de.enough.polish.ui.Container;
//#endif
import de.enough.polish.ui.Container;
import de.enough.polish.ui.Gauge;
import de.enough.polish.ui.Item;
import de.enough.polish.ui.Style;
/**
* TODO: Write good docs.
*
* polish.Browser.UserAgent
* polish.Browser.MaxRedirects
* polish.Browser.Gzip
* polish.Browser.POISupport
* polish.Browser.PaintDownloadIndicator
*
* @see HttpProtocolHandler
* @see ResourceProtocolHandler
* @see RedirectHttpConnection
*/
public abstract class Browser
//#if polish.LibraryBuild
//# extends FakeContainerCustomItem
//#else
extends Container
//#endif
implements Runnable
{
private static final String BROKEN_IMAGE = "resource://broken.png";
private HashMap imageCache = new HashMap();
protected String currentDocumentBase = null;
protected HashMap protocolHandlers = new HashMap();
protected HashMap tagHandlers = new HashMap();
protected Stack history = new Stack();
//#if polish.Browser.PaintDownloadIndicator
//# protected Gauge loadingIndicator;
//# private boolean isStoppedWorking;
//#endif
private Thread loadingThread;
private boolean isRunning;
private boolean isWorking;
private boolean isCancelRequested;
private String nextUrl;
/**
* Creates a new Browser without any protocol handlers, tag handlers or style.
*/
public Browser()
{
//#style browser?
this( (String[])null, (TagHandler[])null, (ProtocolHandler[]) null , de.enough.polish.ui.StyleSheet.browserStyle );
}
/**
* Creates a new Browser without any protocol handler or tag handlers.
*
* @param style the style of this browser
*/
public Browser( Style style )
{
this( (String[])null, (TagHandler[])null, (ProtocolHandler[]) null, style );
}
/**
* Creates a new Browser with the specified handlers and style.
*
* @param protocolHandlers the tag handlers
*/
public Browser( ProtocolHandler[] protocolHandlers )
{
//#if polish.css.style.browser && !polish.LibraryBuild
//#style browser
this(protocolHandlers, de.enough.polish.ui.StyleSheet.browserStyle );
//#else
//# this(protocolHandlers, null);
//#endif
}
/**
* Creates a new Browser with the specified handlers and style.
*
* @param protocolHandlers the tag handlers
* @param style the style to use for the browser item
*/
public Browser( ProtocolHandler[] protocolHandlers, Style style )
{
this( (String[])null, (TagHandler[])null, protocolHandlers, style);
}
/**
* Creates a new Browser with the specified handlers and style.
*
* @param tagNames the names of the tags that the taghandler should handle (this allows to use a single taghandler for several tags)
* @param tagHandlers the tag handlers
* @param protocolHandlers the protocol handlers
*/
public Browser( String[] tagNames, TagHandler[] tagHandlers, ProtocolHandler[] protocolHandlers )
{
//#if polish.css.style.browser && !polish.LibraryBuild
//#style browser
this(tagNames, tagHandlers, protocolHandlers, de.enough.polish.ui.StyleSheet.browserStyle );
//#else
//# this(tagNames,tagHandlers, protocolHandlers, null);
//#endif
}
/**
* Creates a new Browser with the specified handlers and style.
*
* @param tagNames the names of the tags that the taghandler should handle (this allows to use a single taghandler for several tags)
* @param tagHandlers the tag handlers
* @param protocolHandlers the protocol handlers
* @param style the style of this browser
*/
public Browser( String[] tagNames, TagHandler[] tagHandlers, ProtocolHandler[] protocolHandlers, Style style )
{
super( true, style );
if (tagHandlers != null && tagNames != null && tagNames.length == tagHandlers.length) {
for (int i = 0; i < tagHandlers.length; i++) {
TagHandler handler = tagHandlers[i];
addTagHandler(tagNames[i], handler);
}
}
if (protocolHandlers != null) {
for (int i = 0; i < protocolHandlers.length; i++) {
ProtocolHandler handler = protocolHandlers[i];
addProtocolHandler( handler );
}
}
//#if polish.Browser.PaintDownloadIndicator
//#style browserDownloadIndicator
//# this.loadingIndicator = new Gauge(null, false, Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
//#endif
this.loadingThread = new Thread( this );
this.loadingThread.start();
}
/**
* Instantiates and returns the default tag handlers for "http", "https" and "resource" URLs.
*
* @return new default tag handlers
* @see HttpProtocolHandler
* @see ResourceProtocolHandler
*/
protected static ProtocolHandler[] getDefaultProtocolHandlers() {
return new ProtocolHandler[] { new HttpProtocolHandler("http"), new HttpProtocolHandler("https"), new ResourceProtocolHandler("resource") };
}
public void addTagCommand(String tagName, Command command)
{
TagHandler handler = getTagHandler(tagName);
if (handler != null )
{
handler.addTagCommand( tagName, command );
}
}
public void addAttributeCommand(String attributeName, String attributeValue, Command command)
{
addAttributeCommand(null, attributeName, attributeValue, command);
}
public void addAttributeCommand(String tagName, String attributeName, String attributeValue, Command command)
{
TagHandler handler = getTagHandler(tagName);
if (handler != null )
{
handler.addAttributeCommand( tagName, attributeName, attributeValue, command );
}
}
public void addProtocolHandler(ProtocolHandler handler)
{
this.protocolHandlers.put(handler.getProtocolName(), handler);
}
public void addProtocolHandler(String protocolName, ProtocolHandler handler)
{
this.protocolHandlers.put(protocolName, handler);
}
protected ProtocolHandler getProtocolHandler(String protocolName)
{
return (ProtocolHandler) this.protocolHandlers.get(protocolName);
}
protected ProtocolHandler getProtocolHandlerForURL(String url)
throws IOException
{
int pos = url.indexOf(':');
if (pos < 0)
{
throw new IOException("malformed url");
}
String protocol = url.substring(0, pos);
ProtocolHandler handler = (ProtocolHandler) this.protocolHandlers.get(protocol);
if (handler == null)
throw new IOException("protocol handler not found");
return handler;
}
public void addTagHandler(String tagName, TagHandler handler)
{
this.tagHandlers.put(new TagHandlerKey(tagName), handler);
}
public void addTagHandler(String tagName, String attributeName, String attributeValue, TagHandler handler)
{
TagHandlerKey key = new TagHandlerKey(tagName, attributeName, attributeValue);
//#debug
//# System.out.println("Browser.addTagHandler: adding key: " + key);
this.tagHandlers.put(key, handler);
}
public TagHandler getTagHandler(String tagName)
{
TagHandlerKey key = new TagHandlerKey(tagName);
return (TagHandler) this.tagHandlers.get(key);
}
public TagHandler getTagHandler(String tagName, String attributeName, String attributeValue)
{
TagHandlerKey key = new TagHandlerKey(tagName, attributeName, attributeValue);
return (TagHandler) this.tagHandlers.get(key);
}
/**
* @param parser the parser to read the page from
*/
private void parsePage(SimplePullParser parser)
{
// Clear out all items in the browser.
clear();
// Clear image cache when visiting a new page.
this.imageCache.clear();
while (parser.next() != SimplePullParser.END_DOCUMENT)
{
if (parser.getType() == SimplePullParser.START_TAG
|| parser.getType() == SimplePullParser.END_TAG)
{
boolean openingTag = parser.getType() == SimplePullParser.START_TAG;
//#debug
//# System.out.println( "looking for handler for " + parser.getName() + ", openingTag=" + openingTag );
HashMap attributeMap = new HashMap();
TagHandler handler = getTagHandler(parser, attributeMap);
if (handler != null)
{
//#debug
//# System.out.println("Michael: Calling handler: " + parser.getName() + " " + attributeMap);
handler.handleTag(this, parser, parser.getName(), openingTag, attributeMap);
}
else
{
//#debug
//# System.out.println( "no handler for " + parser.getName() );
}
}
else if (parser.getType() == SimplePullParser.TEXT)
{
handleText(parser.getText().trim());
}
else
{
System.out.println("unknown type: " + parser.getType() + ", name=" + parser.getName());
}
} // end while (parser.next() != PullParser.END_DOCUMENT)
//#debug
//# System.out.println("end of document...");
}
private TagHandler getTagHandler(SimplePullParser parser, HashMap attributeMap)
{
TagHandlerKey key;
TagHandler handler = null;
for (int i = 0; i < parser.getAttributeCount(); i++)
{
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
attributeMap.put(attributeName, attributeValue);
key = new TagHandlerKey(parser.getName(),
attributeName,
attributeValue);
handler = (TagHandler) this.tagHandlers.get(key);
if (handler != null)
{
break;
}
}
if (handler == null)
{
key = new TagHandlerKey(parser.getName());
handler = (TagHandler) this.tagHandlers.get(key);
}
return handler;
}
/**
* Handles norml text.
*
* @param text the text
*/
protected abstract void handleText(String text);
/**
* Loads a page from a given <code>Reader</code>.
*
* @param reader the reader to load the page from
* @throws IOException of an error occurs
*/
public void loadPage(Reader reader)
throws IOException
{
XmlPullParser xmlReader = new XmlPullParser(reader);
xmlReader.relaxed = true;
parsePage(xmlReader);
}
/**
* "http://foo.bar.com/baz/blah.html" => "http://foo.bar.com"
* <p>
* "resource://baz/blah.html" => "resource://"
*/
protected String protocolAndHostOf(String url)
{
if ("resource://".regionMatches(true, 0, url, 0, 11))
{
return "resource://";
}
else if ("http://".regionMatches(true, 0, url, 0, 7))
{
int hostStart = url.indexOf("//");
// figure out what error checking to do here
hostStart+=2;
// look for next '/'. If none, assume rest of string is hostname
int hostEnd = url.indexOf("/", hostStart);
if (hostEnd != -1)
{
return url.substring(0, hostEnd);
}
else
{
return url;
}
}
else
{
// unsupported protocol
return url;
}
}
/**
* Takes a possibly relative URL, and generate an absolute URL, merging with
* the current documentbase if needed.
*
* <ol>
* <li> If URL starts with http:// or resource:// leave it alone
* <li> If URL starts with '/', prepend document base protocol and host name.
* <li> Otherwise, it's a relative URL, so prepend current document base and
* directory path.
* </ol>
*
* @param url the (possibly relative) URL
* @return absolute URL
*/
public String makeAbsoluteURL(String url)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -