001: /* UiManager.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Tue May 5 10:12:21 2007, Created by henrichen
010: }}IS_NOTE
011:
012: Copyright (C) 2007 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.zkmob;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.OutputStream;
024: import java.util.Hashtable;
025: import java.util.Vector;
026:
027: import javax.microedition.io.Connector;
028: import javax.microedition.io.HttpConnection;
029: import javax.microedition.lcdui.Alert;
030: import javax.microedition.lcdui.AlertType;
031: import javax.microedition.lcdui.Command;
032: import javax.microedition.lcdui.Display;
033: import javax.microedition.lcdui.Displayable;
034: import javax.microedition.lcdui.Image;
035: import javax.microedition.lcdui.Item;
036: import javax.xml.parsers.ParserConfigurationException;
037: import javax.xml.parsers.SAXParser;
038: import javax.xml.parsers.SAXParserFactory;
039:
040: import org.xml.sax.Attributes;
041: import org.xml.sax.SAXException;
042: import org.zkoss.zkmob.factory.AlertFactory;
043: import org.zkoss.zkmob.factory.ChoiceGroupFactory;
044: import org.zkoss.zkmob.factory.CommandFactory;
045: import org.zkoss.zkmob.factory.DateFieldFactory;
046: import org.zkoss.zkmob.factory.FormFactory;
047: import org.zkoss.zkmob.factory.GaugeFactory;
048: import org.zkoss.zkmob.factory.ImageItemFactory;
049: import org.zkoss.zkmob.factory.ListFactory;
050: import org.zkoss.zkmob.factory.ListItemFactory;
051: import org.zkoss.zkmob.factory.SpacerFactory;
052: import org.zkoss.zkmob.factory.StringItemFactory;
053: import org.zkoss.zkmob.factory.TextBoxFactory;
054: import org.zkoss.zkmob.factory.TextFieldFactory;
055: import org.zkoss.zkmob.factory.TickerFactory;
056: import org.zkoss.zkmob.factory.ZkFactory;
057: import org.zkoss.zkmob.ui.ZkDesktop;
058: import org.zkoss.zkmob.ui.ZkForm;
059:
060: /**
061: * The static facade for UI component management.
062: */
063: public class UiManager {
064: private static Hashtable _uiFactoryMap = new Hashtable(16);
065: //predefined a SAXParserFactory
066: private static SAXParserFactory _factory = SAXParserFactory
067: .newInstance();
068:
069: //predefined Ui component factory
070: static {
071: //virtual components
072: new ZkFactory("zk");
073: new TickerFactory("tc");
074: new ListItemFactory("li");
075: new CommandFactory("cm");
076:
077: //top level window
078: new FormFactory("fr");
079: new AlertFactory("al");
080: new ListFactory("ls");
081: new TextBoxFactory("tb");
082:
083: //items (MIDP 1.0)
084: new DateFieldFactory("df");
085: new GaugeFactory("gg");
086: new ImageItemFactory("ii");
087: new StringItemFactory("si");
088: new TextFieldFactory("tf");
089: new ChoiceGroupFactory("cg");
090:
091: //items (MIDP 2.0)
092: new SpacerFactory("sp");
093: }
094:
095: /** register an UiFactory to a Ui tag name.
096: * @param name the Ui tag name
097: * @param uiFactory an UiFactory used to create an Ui component
098: */
099: public static void registerUiFactory(String name,
100: UiFactory uiFactory) {
101: _uiFactoryMap.put(name, uiFactory);
102: }
103:
104: public static SAXParser getSAXParser() {
105: try {
106: return _factory.newSAXParser();
107: } catch (ParserConfigurationException e) {
108: throw new IllegalStateException(e.toString());
109: } catch (SAXException e) {
110: throw new IllegalStateException(e.toString());
111: } catch (RuntimeException e) {
112: e.printStackTrace();
113: throw e;
114: }
115: }
116:
117: public static void alert(Display disp, Throwable e) {
118: final Alert alert = new Alert("Exception:", e.toString(), null,
119: AlertType.ERROR);
120: alert.setTimeout(Alert.FOREVER);
121: disp.setCurrent(alert);
122: }
123:
124: /**
125: * given Ui tag name and create an associated Ui component.
126: * @param parent the parent component
127: * @param tag the Ui tag name
128: * @param attrs the Ui tag attributes
129: * @param hostURL the host URL
130: */
131: public static ZkComponent create(ZkComponent parent, String tag,
132: Attributes attrs, String hostURL, String pathURL) {
133: UiFactory uiFactory = (UiFactory) _uiFactoryMap.get(tag);
134:
135: if (uiFactory != null) {
136: return uiFactory.create(parent, tag, attrs, hostURL,
137: pathURL);
138: }
139:
140: throw new IllegalArgumentException(
141: "Cannot find the UiFactory of the RMIL tag: " + tag);
142: }
143:
144: public static void loadPageOnThread(Browser browser, String url) {
145: new Thread(new PageRequest(browser, url)).start();
146: }
147:
148: /* package */static void loadPage(Browser browser, String url) {
149: try {
150: myLoadPage(browser, url);
151: } catch (Throwable e) {
152: e.printStackTrace();
153: alert(browser.getDisplay(), e);
154: }
155: }
156:
157: public static String getHostURL(HttpConnection conn) {
158: return conn.getProtocol() + "://" + conn.getHost()
159: + (conn.getPort() != 80 ? (":" + conn.getPort()) : "");
160: }
161:
162: public static String getPathURL(HttpConnection conn) {
163: String url = conn.getURL();
164: int j = url.lastIndexOf('/');
165: if (j >= 0) {
166: url = url.substring(0, j + 1); //include the '/'
167: }
168: return url;
169: }
170:
171: public static String prefixURL(String hostURL, String pathURL,
172: String url) {
173: if (url != null && !url.startsWith("http://")
174: && !url.startsWith("https://") && !url.startsWith("~.")) {
175: url = (url.startsWith("/") ? hostURL : pathURL) + url;
176: }
177: return url;
178: }
179:
180: public static Vector createComponents(ZkComponent parent,
181: InputStream is, String hostURL, String pathURL)
182: throws IOException, SAXException {
183: // Load the responsed page, the current Displayable is put in _current
184: final PageHandler handler = new PageHandler(parent, hostURL,
185: pathURL);
186: getSAXParser().parse(is, handler);
187: return handler.getRoots();
188: }
189:
190: private static void myLoadPage(Browser browser, String url)
191: throws IOException, SAXException {
192: HttpConnection conn = null;
193: InputStream is = null;
194:
195: try {
196: conn = (HttpConnection) Connector.open(url);
197: is = request(conn, null);
198:
199: loadPage(browser, is, url, getHostURL(conn),
200: getPathURL(conn));
201: } finally {
202: if (is != null)
203: is.close();
204: if (conn != null)
205: conn.close();
206: }
207: }
208:
209: public static ZkDesktop loadPage(Browser browser, InputStream is,
210: String url, String hostURL, String pathURL)
211: throws IOException, SAXException {
212: final ZkDesktop zk = createComponents(browser, is, hostURL,
213: pathURL);
214:
215: //notify server to remove old desktop
216: final Object current = browser.getDisplay().getCurrent();
217: if (current instanceof ZkComponent) {
218: final ZkDesktop oldZk = ((ZkComponent) current)
219: .getZkDesktop();
220: if (oldZk != null && !"zkMobile".equals(oldZk.getId())) {
221: oldZk.removeDesktop(); //notify server to remove desktop
222: }
223: }
224:
225: //associate new desktop to browser
226: browser.setDesktop(zk, url);
227: return zk;
228: }
229:
230: private static ZkDesktop createComponents(Browser browser,
231: InputStream is, String hostURL, String pathURL)
232: throws IOException, SAXException {
233: // Load the responsed page, the current Displayable is put in _current
234: final PageHandler handler = new PageHandler(hostURL, pathURL);
235: getSAXParser().parse(is, handler);
236: return handler.getZk();
237: }
238:
239: /** utility to load Image on a separate thread.
240: *
241: * @param item Imageable item to be setup the loaded image
242: * @param url the Image url
243: */
244: public static void loadImageOnThread(Imageable item,
245: String hostURL, String pathURL, String url) {
246: if (url != null) {
247: final ZkDesktop zk = ((ZkComponent) item).getZkDesktop();
248: if (zk != null) {
249: final String imagesrc = UiManager.prefixURL(hostURL,
250: pathURL, url); //image
251: new Thread(new ImageRequest(item, imagesrc)).start();
252: }
253: }
254: }
255:
256: /** utility to be called by {@link ImageRequest} only.
257: *
258: * @param url The image url
259: * @return the Image object
260: */
261: /*package*/static Image loadImage(String url) {
262: try {
263: return myLoadImage(url);
264: } catch (Throwable e) {
265: e.printStackTrace();
266: }
267: return null;
268: }
269:
270: private static Image myLoadImage(String url) throws IOException {
271: HttpConnection conn = null;
272: InputStream is = null;
273:
274: try {
275: if (url.startsWith("~.")) {
276: url = url.substring(2);
277: is = UiManager.class.getResourceAsStream(url);
278: } else {
279: conn = (HttpConnection) Connector.open(url);
280: is = request(conn, null);
281: }
282: // Load the response
283: return Image.createImage(is);
284: } finally {
285: if (is != null)
286: is.close();
287: if (conn != null)
288: conn.close();
289: }
290: }
291:
292: public static InputStream request(HttpConnection conn,
293: String request) throws IOException {
294: OutputStream os = null;
295: int rc;
296:
297: try {
298: // Set the request method and headers
299: conn.setRequestMethod(HttpConnection.POST);
300: conn.setRequestProperty("Content-Type",
301: "application/x-www-form-urlencoded");
302: conn.setRequestProperty("User-Agent",
303: "ZK Mobile/1.0 (RMIL)");
304: conn.setRequestProperty("Content-Language", "en-US");
305:
306: // Getting the output stream may flush the headers
307: os = conn.openOutputStream();
308: if (request != null) {
309: os.write(request.getBytes());
310: }
311: // Getting the response code will open the connection,
312: // send the request, and read the HTTP response headers.
313: // The headers are stored until requested.
314: rc = conn.getResponseCode();
315: if (rc != HttpConnection.HTTP_OK) {
316: throw new IOException("HTTP response code: " + rc);
317: }
318:
319: return conn.openInputStream();
320: } catch (ClassCastException e) {
321: throw new IllegalArgumentException("Not an HTTP URL");
322: } catch (RuntimeException e) {
323: e.printStackTrace();
324: throw e;
325: } finally {
326: if (os != null)
327: os.close();
328: }
329: }
330:
331: /**
332: * parse a "width,height" into int[] where int[0] is width, int[1] is height.
333: * @param sizestr The size in string format of "width, height"
334: * @return int[] where int[0] is width, int[1] is height.
335: */
336: public static int[] parseSize(String sizestr) {
337: int[] size = new int[2]; //[0]: width; [1]: height
338: int j = sizestr.indexOf(",");
339: if (j < 0) { //not found
340: return null;
341: } else {
342: String wstr = sizestr.substring(0, j).trim();
343: String hstr = sizestr.substring(j + 1).trim();
344: size[0] = Integer.parseInt(wstr);
345: size[1] = Integer.parseInt(hstr);
346: }
347: return size;
348: }
349:
350: /**
351: * Utility to apply common properties to Item component.
352: */
353: public static void applyItemProperties(ZkComponent parent,
354: Item component, Attributes attrs) {
355: setItemAttr(component, "lo", attrs.getValue("lo")); //layout
356: setItemAttr(component, "ps", attrs.getValue("ps")); //preferredSize
357: if (parent instanceof ZkForm) {
358: ((ZkForm) parent).appendChild((ZkComponent) component);
359: }
360: }
361:
362: /**
363: * Given Item, attribute name, and value; then set the attribute of the Item if match.
364: * @param item The Item to be set
365: * @param attr The attribute name
366: * @param val The value
367: */
368: public static void setItemAttr(Item item, String attr, String val) {
369: if ("lb".equals(attr)) {
370: item.setLabel(val);
371: } else if ("lo".equals(attr)) {
372: item.setLayout(val == null ? Item.LAYOUT_DEFAULT : Integer
373: .parseInt(val));
374: } else if ("ps".equals(attr)) {
375: int[] sz = val == null ? new int[] { -1, -1 }
376: : parseSize(val);
377: item.setPreferredSize(sz[0], sz[1]);
378: }
379: }
380:
381: public static void registerCommand(ZkComponent owner, Command cmd,
382: ZkDesktop zk) {
383: owner.addCommand(cmd); //add into owner
384: if (owner instanceof Item) {
385: ((Item) owner).setItemCommandListener(zk
386: .getItemCommandListener());
387: } else if (owner instanceof Displayable) {
388: ((Displayable) owner).setCommandListener(zk
389: .getCommandListener());
390: }
391: }
392: }
|