📄 browser.java
字号:
/* * Fire (Flexible Interface Rendering Engine) is a set of graphics widgets for creating GUIs for j2me applications. * Copyright (C) 2006-2008 Bluevibe (www.bluevibe.net) * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *//** * */package gr.fire.browser;import gr.fire.browser.util.HttpClient;import gr.fire.browser.util.Page;import gr.fire.browser.util.PageListener;import gr.fire.browser.util.Request;import gr.fire.core.CommandListener;import gr.fire.core.Component;import gr.fire.core.Container;import gr.fire.core.FireScreen;import gr.fire.core.Panel;import gr.fire.core.Theme;import gr.fire.ui.Alert;import gr.fire.ui.ProgressbarAnimation;import gr.fire.ui.TransitionAnimation;import gr.fire.util.FireConnector;import gr.fire.util.Lang;import gr.fire.util.Log;import gr.fire.util.StringUtil;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.util.Hashtable;import java.util.Vector;import javax.microedition.io.HttpConnection;import javax.microedition.lcdui.Command;import javax.microedition.lcdui.Displayable;import javax.microedition.lcdui.Font;import org.kxml2.io.KXmlParser;/** * The Browser parses XHTML from a given stream and renders it. * It has some basic rendering rules that are choosen to improve the * readability and usability of a page when rendered for a small screen. <br/> * * * The default width of the browser is the width of the screen.<br/> * * * TextPrimitive width is set as the width of the Browser unless noted otherwise * by the style of the tag.<br/> * * * TextPrimitive height is the height of the text calculated using the width * (according to the rules above) and the font of the text. <br/> * * * ImagePrimitive width is the width of the image unless noted otherwise by the style of the tag. <br/> * * @author padeler */public class Browser implements CommandListener, PageListener{ /** * Flag for the imageLoadingPolicy field. * No images are loaded. */ public static final byte NO_IMAGES=0x00; /** * Flag for the imageLoadingPolicy field. * Load images imediatelly */ public static final byte LOAD_IMAGES=0x01; /** * Flag for the imageLoadingPolicy field. This is the default browser behaivior. * Load images in a seperate thread after the full parsing of the page. * The browser will return the Page object and start a thread to load the rest of the images. * This will apply only for images that the width and height attributes are set. * Images that do not have their width and height attributes set, will be loaded imediatelly. */ public static final byte LOAD_IMAGES_ASYNC=0x02; /** * The listener that will receive the events generated by the page rendered by this browser (i.e. link clicks etc) * The listener will also receive the submit events generated by forms in the rendered pages. * If null, then the form handles the submit, with the default way (calls browser.displayPage()) */ CommandListener listener = this; PageListener pageListener = this; /** * If this field is set to false, then the browser will not request the images inside each page */ byte imageLoadingPolicy = LOAD_IMAGES_ASYNC; /** * The HttpClient used to request resources. */ HttpClient httpClient; private Hashtable knownTags = new Hashtable(); private int viewportWidth=-1; private boolean showLoadingGauge=true; /* ****** HTML Parsing support variables ******* */ private Vector tagStack = new Vector(); private ProgressbarAnimation gauge=null; /** * Constructor of a Browser instance with the default HttpClient. * The CommandListener and PageListener are set to this new Browser instance. * @see HttpClient * @see PageListener * @see CommandListener */ public Browser() { this(new HttpClient(new FireConnector())); } /** * Constructor of a Browser instance with the supplied httpclient. All other parameters are set to the default * @see #Browser() * @param httpClient */ public Browser(HttpClient httpClient) { this.httpClient = httpClient; { Class ie = new InlineTag().getClass(); registerTag(InlineTag.TAG_A,ie); registerTag(InlineTag.TAG_B,ie); registerTag(InlineTag.TAG_BR,ie); registerTag(InlineTag.TAG_EM,ie); registerTag(InlineTag.TAG_I,ie); registerTag(InlineTag.TAG_IMG,ie); registerTag(InlineTag.TAG_SPAN,ie); registerTag(InlineTag.TAG_STRONG,ie); registerTag(InlineTag.TAG_BIG,ie); registerTag(InlineTag.TAG_SMALL,ie); registerTag(InlineTag.TAG_TT,ie); registerTag(InlineTag.TAG_U,ie); registerTag(InlineTag.TAG_TD,ie); registerTag(InlineTag.TAG_INPUT,ie); registerTag(InlineTag.TAG_BUTTON,ie); registerTag(InlineTag.TAG_TEXTAREA,ie); registerTag(InlineTag.TAG_CENTER,ie); registerTag(InlineTag.TAG_LABEL,ie); registerTag(InlineTag.TAG_OPTION,ie); registerTag(InlineTag.TAG_SELECT,ie); } { Class be = new BlockTag().getClass(); registerTag(BlockTag.TAG_P,be); registerTag(BlockTag.TAG_BODY,be); registerTag(BlockTag.TAG_TABLE,be); registerTag(BlockTag.TAG_TR,be); registerTag(BlockTag.TAG_DIV,be); registerTag(BlockTag.TAG_TITLE,be); registerTag(BlockTag.TAG_META,be); registerTag(BlockTag.TAG_STYLE,be); registerTag(BlockTag.TAG_SCRIPT,be); registerTag(BlockTag.TAG_H1,be); registerTag(BlockTag.TAG_H2,be); registerTag(BlockTag.TAG_H3,be); registerTag(BlockTag.TAG_H4,be); registerTag(BlockTag.TAG_H5,be); registerTag(BlockTag.TAG_H6,be); registerTag(BlockTag.TAG_HR,be); registerTag(BlockTag.TAG_FORM,be); } { Class le = new ListBlockTag().getClass(); registerTag(ListBlockTag.TAG_UL,le); registerTag(ListBlockTag.TAG_LI,le); registerTag(ListBlockTag.TAG_OL,le); registerTag(ListBlockTag.TAG_DL,le); registerTag(ListBlockTag.TAG_DT,le); registerTag(ListBlockTag.TAG_DD,le); } } /** * Registers an XML tag to be handled by an instance of the given class. The class MUST be a subclass of Tag * @see HtmlUtil * @param name name of the tag * @param cl the class that will handle the action */ public void registerTag(String name,Class cl) { if(name!=null && cl!=null) { try { Tag t = (Tag)cl.newInstance(); } catch (Exception e) { Log.logError("Failed to register class for tag "+name+". ",e); throw new IllegalArgumentException("Class must be an instantiable subclass of Tag. "+e.getMessage()); } knownTags.put(name,cl); } else throw new NullPointerException("Tag name and class cannot be null"); } private void showGauge(String message) { if(!showLoadingGauge) return; if(gauge!=null) hideGauge(); gauge = new ProgressbarAnimation(message); Font font = FireScreen.getTheme().getFontProperty("titlebar.font"); FireScreen screen = FireScreen.getScreen(); int sw = screen.getWidth(); int mw = font.stringWidth(message); gauge.setWidth(sw); gauge.setHeight(font.getHeight()); screen.addComponent(gauge,6); } private void hideGauge() { if(gauge!=null){ FireScreen.getScreen().removeComponent(gauge); gauge=null; } } /** * Loads the page from the given URL using the supplied method and reqest parameters and data. * This method will use the supplied HttpClient {@link #httpClient} to make the request and then render the page.<br/> * * The resulting will be added to added to a Page instance and returned to the caller. * It will not handle "meta" tag information, but will return them inside the Page instance. <br/> * * This method is <b>synchronized</b> on the browser instance. * * @param url * @param method The method can be HttpConnection.GET or HttpConnection.POST * @param requestParameters params for the http request header * @param data if the method is HttpConnection.POST the post data if any must be in this byte array * @return * @throws UnsupportedEncodingException * @throws IOException * @throws Exception */ public synchronized Page loadPage(String url,String method,Hashtable requestParameters,byte []data) throws UnsupportedEncodingException,IOException,Exception { if(url.startsWith("ttp://") || url.startsWith("ttps://")) { url = "h"+url; Log.logWarn("Malformed url resolved to: "+url); } Page page = new Page(url); /* ********** Display a gauge *************** */ showGauge(StringUtil.proccessUrl(url,true)); /* ************************** Request the resource **************************** */ Request currentRequest = null; try{ currentRequest = httpClient.requestResource(url,method,requestParameters,data,true); if(currentRequest==null) { Log.logWarn("Failed to get resource from "+url); return null; } page.setAbsolutUrl(currentRequest.getURL()); InputStream in = currentRequest.getInputStream(); if (in == null) { Log.logWarn("Failed to read data from "+url); return null; } Log.logDebug("Base URL is: "+currentRequest.getBaseURL()); String encoding= currentRequest.getEncoding(); return loadPageFromStream(page,in,encoding); }catch(Exception e){ Log.logError("Failed to request page "+url+".",e); throw e; }finally{ if(currentRequest!=null){ try{ currentRequest.close(); }catch(IOException ex){ Log.logWarn("Connection not closed!", ex); } currentRequest=null; } hideGauge(); } } /** * Loads a page from the given InputStream using the given encoding. * * This method is <b>synchronized</b> on the browser instance. * * @param in * @param encoding * @return A Page instance containing the result of the request * @throws UnsupportedEncodingException * @throws IOException * @throws Exception */ public synchronized Page loadPage(InputStream in,String encoding) throws UnsupportedEncodingException,IOException,Exception { Page page = new Page(); /* ********** Display a gauge *************** */ showGauge("Loading..."); try{ return loadPageFromStream(page,in,encoding); }catch(Exception e){ Log.logError("Failed to request page from stream.",e); throw e; }finally{ hideGauge(); } } /* * The main loop of the Browser module. This uses the XmlPullParser to parse the xml from the inputstream and * then iterates through the tags of the document. Each known tag is handled by the class that is registered to handle it * using the registerTag method. */ private Page loadPageFromStream(Page page,InputStream in,String encoding) throws UnsupportedEncodingException,IOException,Exception { /* ******************************** clean old page stuff here **************************** */ tagStack.removeAllElements(); gauge.progress(); InputStreamReader reader=null; try{ Log.logDebug("Using Encoding: "+encoding); reader = new InputStreamReader(in, encoding); KXmlParser parser = new KXmlParser(); parser.setInput(reader); parser.setFeature(org.xmlpull.v1.XmlPullParser.FEATURE_RELAXED,true); int type=-1,oldType=-1; Theme th = FireScreen.getTheme(); Tag rootTag = new InlineTag(); rootTag.setForegroundColor(th.getIntProperty("xhtml.fg.color")); rootTag.setBackgroundColor(th.getIntProperty("xhtml.bg.color")); rootTag.setFont(th.getFontProperty("xhtml.font")); /* ********** Main XML parsing loop **************** */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -