org.microemu.device.impl.DeviceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of microemulator Show documentation
Show all versions of microemulator Show documentation
MicroEmulator one jar assembly for distribution.
The newest version!
/**
* MicroEmulator
* Copyright (C) 2002-2005 Bartek Teodorczyk
*
* It is licensed under the following two licenses as alternatives:
* 1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
* 2. Apache License (the "AL") Version 2.0
*
* You may not use this file except in compliance with at least one of
* the above two licenses.
*
* You may obtain a copy of the LGPL at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
*
* You may obtain a copy of the AL at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the LGPL or the AL for the specific language governing permissions and
* limitations.
*/
package org.microemu.device.impl;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Image;
import nanoxml.XMLElement;
import nanoxml.XMLParseException;
import org.microemu.app.util.IOUtils;
import org.microemu.device.Device;
import org.microemu.device.DeviceDisplay;
import org.microemu.device.EmulatorContext;
import org.microemu.device.FontManager;
import org.microemu.device.InputMethod;
public abstract class DeviceImpl implements Device {
private String name;
private static EmulatorContext context;
private Image normalImage;
private Image overImage;
private Image pressedImage;
private Vector buttons;
private Vector softButtons;
private boolean hasPointerEvents;
private boolean hasPointerMotionEvents;
// TODO not implemented yet
private boolean hasRepeatEvents;
private Map systemProperties;
private int skinVersion;
public static final String DEFAULT_LOCATION = "org/microemu/device/default/device.xml";
public static final String RESIZABLE_LOCATION = "org/microemu/device/resizable/device.xml";
/**
* @deprecated
*/
private String descriptorLocation;
private static Map specialInheritanceAttributeSet;
public DeviceImpl() {
// Permits null values.
systemProperties = new HashMap();
buttons = new Vector();
softButtons = new Vector();
}
public static DeviceImpl create(EmulatorContext context, ClassLoader classLoader, String descriptorLocation,
Class defaultDeviceClass) throws IOException {
XMLElement doc = loadDeviceDescriptor(classLoader, descriptorLocation);
// saveDevice(doc);
DeviceImpl device = null;
for (Enumeration e = doc.enumerateChildren(); e.hasMoreElements();) {
XMLElement tmp = (XMLElement) e.nextElement();
if (tmp.getName().equals("class-name")) {
try {
Class deviceClass = Class.forName(tmp.getContent(), true, classLoader);
device = (DeviceImpl) deviceClass.newInstance();
} catch (ClassNotFoundException ex) {
throw new IOException(ex.getMessage());
} catch (InstantiationException ex) {
throw new IOException(ex.getMessage());
} catch (IllegalAccessException ex) {
throw new IOException(ex.getMessage());
}
break;
}
}
if (device == null) {
try {
device = (DeviceImpl) defaultDeviceClass.newInstance();
} catch (InstantiationException ex) {
throw new IOException(ex.getMessage());
} catch (IllegalAccessException ex) {
throw new IOException(ex.getMessage());
}
}
device.context = context;
device.descriptorLocation = descriptorLocation;
device.loadConfig(classLoader, besourceBase(descriptorLocation), doc);
return device;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#init()
*/
public void init() {
}
/**
* @deprecated use Device.create(EmulatorContext context, ClassLoader
* classLoader, String descriptorLocation);
*/
public void init(EmulatorContext context) {
init(context, DEFAULT_LOCATION);
}
/**
* @deprecated use Device.create(EmulatorContext context, ClassLoader
* classLoader, String descriptorLocation);
*/
public void init(EmulatorContext context, String descriptorLocation) {
this.context = context;
if (descriptorLocation.startsWith("/")) {
this.descriptorLocation = descriptorLocation.substring(1);
} else {
this.descriptorLocation = descriptorLocation;
}
try {
String base = descriptorLocation.substring(0, descriptorLocation.lastIndexOf("/"));
XMLElement doc = loadDeviceDescriptor(getClass().getClassLoader(), descriptorLocation);
loadConfig(getClass().getClassLoader(), base, doc);
} catch (IOException ex) {
System.out.println("Cannot load config: " + ex);
}
}
/**
* @deprecated
*/
public String getDescriptorLocation() {
return descriptorLocation;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#destroy()
*/
public void destroy() {
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getName()
*/
public String getName() {
return name;
}
public static EmulatorContext getEmulatorContext() {
return context;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getInputMethod()
*/
public InputMethod getInputMethod() {
return context.getDeviceInputMethod();
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getFontManager()
*/
public FontManager getFontManager() {
return context.getDeviceFontManager();
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getDeviceDisplay()
*/
public DeviceDisplay getDeviceDisplay() {
return context.getDeviceDisplay();
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getNormalImage()
*/
public Image getNormalImage() {
return normalImage;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getOverImage()
*/
public Image getOverImage() {
return overImage;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getPressedImage()
*/
public Image getPressedImage() {
return pressedImage;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getSoftButtons()
*/
public Vector getSoftButtons() {
return softButtons;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getButtons()
*/
public Vector getButtons() {
return buttons;
}
protected void loadConfig(ClassLoader classLoader, String base, XMLElement doc) throws IOException {
String deviceName = doc.getStringAttribute("name");
if (deviceName != null) {
name = deviceName;
} else {
name = base;
}
loadSkinVersion(doc);
hasPointerEvents = false;
hasPointerMotionEvents = false;
hasRepeatEvents = false;
((FontManagerImpl) getFontManager()).setAntialiasing(false);
/*
* parseDisplay have to be performed first to check if device display
* has resizable flag set, parseInput skips rectangle or polygon element
* then, also normalImage, overImage and pressedImage aren't needed
*/
parseDisplay(classLoader, base, doc.getChild("display"));
for (Enumeration e = doc.enumerateChildren(); e.hasMoreElements();) {
XMLElement tmp = (XMLElement) e.nextElement();
if (tmp.getName().equals("system-properties")) {
parseSystemProperties(tmp);
} else if (tmp.getName().equals("img") && !((DeviceDisplayImpl) getDeviceDisplay()).isResizable()) {
try {
if (tmp.getStringAttribute("name").equals("normal")) {
normalImage = loadImage(classLoader, base, tmp.getStringAttribute("src"));
} else if (tmp.getStringAttribute("name").equals("over")) {
overImage = loadImage(classLoader, base, tmp.getStringAttribute("src"));
} else if (tmp.getStringAttribute("name").equals("pressed")) {
pressedImage = loadImage(classLoader, base, tmp.getStringAttribute("src"));
}
} catch (IOException ex) {
System.out.println("Cannot load " + tmp.getStringAttribute("src"));
return;
}
} else if (tmp.getName().equals("fonts")) {
parseFonts(classLoader, base, tmp);
} else if (tmp.getName().equals("input") || tmp.getName().equals("keyboard")) {
// "keyboard" is for backward compatibility
parseInput(tmp);
}
}
}
private void loadSkinVersion(XMLElement doc) {
String xmlns = doc.getStringAttribute("xmlns");
if (xmlns == null) {
skinVersion = 20000;
} else {
if (xmlns.endsWith("/2.0.2/")) {
skinVersion = 20002;
} else {
skinVersion = 20000;
}
}
}
private void parseDisplay(ClassLoader classLoader, String base, XMLElement tmp) throws IOException {
DeviceDisplayImpl deviceDisplay = (DeviceDisplayImpl) getDeviceDisplay();
String resizable = tmp.getStringAttribute("resizable", "false");
if (resizable.equalsIgnoreCase("true")) {
deviceDisplay.setResizable(true);
} else {
deviceDisplay.setResizable(false);
}
for (Enumeration e_display = tmp.enumerateChildren(); e_display.hasMoreElements();) {
XMLElement tmp_display = (XMLElement) e_display.nextElement();
if (tmp_display.getName().equals("numcolors")) {
deviceDisplay.setNumColors(Integer.parseInt(tmp_display.getContent()));
} else if (tmp_display.getName().equals("iscolor")) {
deviceDisplay.setIsColor(parseBoolean(tmp_display.getContent()));
} else if (tmp_display.getName().equals("numalphalevels")) {
deviceDisplay.setNumAlphaLevels(Integer.parseInt(tmp_display.getContent()));
} else if (tmp_display.getName().equals("background")) {
deviceDisplay.setBackgroundColor(new Color(Integer.parseInt(tmp_display.getContent(), 16)));
} else if (tmp_display.getName().equals("foreground")) {
deviceDisplay.setForegroundColor(new Color(Integer.parseInt(tmp_display.getContent(), 16)));
} else if (tmp_display.getName().equals("rectangle")) {
Rectangle rect = getRectangle(tmp_display);
if (deviceDisplay.isResizable()) {
rect.x = 0;
rect.y = 0;
}
deviceDisplay.setDisplayRectangle(rect);
} else if (tmp_display.getName().equals("paintable")) {
deviceDisplay.setDisplayPaintable(getRectangle(tmp_display));
}
}
for (Enumeration e_display = tmp.enumerateChildren(); e_display.hasMoreElements();) {
XMLElement tmp_display = (XMLElement) e_display.nextElement();
if (tmp_display.getName().equals("img")) {
if (tmp_display.getStringAttribute("name").equals("up")
|| tmp_display.getStringAttribute("name").equals("down")) {
// deprecated, moved to icon
SoftButton icon = deviceDisplay.createSoftButton(skinVersion, tmp_display
.getStringAttribute("name"), getRectangle(tmp_display.getChild("paintable")), loadImage(
classLoader, base, tmp_display.getStringAttribute("src")), loadImage(classLoader, base,
tmp_display.getStringAttribute("src")));
getSoftButtons().addElement(icon);
} else if (tmp_display.getStringAttribute("name").equals("mode")) {
// deprecated, moved to status
if (tmp_display.getStringAttribute("type").equals("123")) {
deviceDisplay.setMode123Image(new PositionedImage(loadImage(classLoader, base, tmp_display
.getStringAttribute("src")), getRectangle(tmp_display.getChild("paintable"))));
} else if (tmp_display.getStringAttribute("type").equals("abc")) {
deviceDisplay.setModeAbcLowerImage(new PositionedImage(loadImage(classLoader, base, tmp_display
.getStringAttribute("src")), getRectangle(tmp_display.getChild("paintable"))));
} else if (tmp_display.getStringAttribute("type").equals("ABC")) {
deviceDisplay.setModeAbcUpperImage(new PositionedImage(loadImage(classLoader, base, tmp_display
.getStringAttribute("src")), getRectangle(tmp_display.getChild("paintable"))));
}
}
} else if (tmp_display.getName().equals("icon")) {
Image iconNormalImage = null;
Image iconPressedImage = null;
for (Enumeration e_icon = tmp_display.enumerateChildren(); e_icon.hasMoreElements();) {
XMLElement tmp_icon = (XMLElement) e_icon.nextElement();
if (tmp_icon.getName().equals("img")) {
if (tmp_icon.getStringAttribute("name").equals("normal")) {
iconNormalImage = loadImage(classLoader, base, tmp_icon.getStringAttribute("src"));
} else if (tmp_icon.getStringAttribute("name").equals("pressed")) {
iconPressedImage = loadImage(classLoader, base, tmp_icon.getStringAttribute("src"));
}
}
}
SoftButton icon = deviceDisplay.createSoftButton(skinVersion, tmp_display.getStringAttribute("name"),
getRectangle(tmp_display.getChild("paintable")), iconNormalImage, iconPressedImage);
getSoftButtons().addElement(icon);
} else if (tmp_display.getName().equals("status")) {
if (tmp_display.getStringAttribute("name").equals("input")) {
Rectangle paintable = getRectangle(tmp_display.getChild("paintable"));
for (Enumeration e_status = tmp_display.enumerateChildren(); e_status.hasMoreElements();) {
XMLElement tmp_status = (XMLElement) e_status.nextElement();
if (tmp_status.getName().equals("img")) {
if (tmp_status.getStringAttribute("name").equals("123")) {
deviceDisplay.setMode123Image(new PositionedImage(loadImage(classLoader, base,
tmp_status.getStringAttribute("src")), paintable));
} else if (tmp_status.getStringAttribute("name").equals("abc")) {
deviceDisplay.setModeAbcLowerImage(new PositionedImage(loadImage(classLoader, base,
tmp_status.getStringAttribute("src")), paintable));
} else if (tmp_status.getStringAttribute("name").equals("ABC")) {
deviceDisplay.setModeAbcUpperImage(new PositionedImage(loadImage(classLoader, base,
tmp_status.getStringAttribute("src")), paintable));
}
}
}
}
}
}
}
private void parseFonts(ClassLoader classLoader, String base, XMLElement tmp) throws IOException {
FontManagerImpl fontManager = (FontManagerImpl) getFontManager();
String hint = tmp.getStringAttribute("hint");
boolean antialiasing = false;
if (hint != null && hint.equals("antialiasing")) {
antialiasing = true;
}
fontManager.setAntialiasing(antialiasing);
for (Enumeration e_fonts = tmp.enumerateChildren(); e_fonts.hasMoreElements();) {
XMLElement tmp_font = (XMLElement) e_fonts.nextElement();
if (tmp_font.getName().equals("font")) {
String face = tmp_font.getStringAttribute("face").toLowerCase();
String style = tmp_font.getStringAttribute("style").toLowerCase();
String size = tmp_font.getStringAttribute("size").toLowerCase();
if (face.startsWith("face_")) {
face = face.substring("face_".length());
}
if (style.startsWith("style_")) {
style = style.substring("style_".length());
}
if (size.startsWith("size_")) {
size = size.substring("size_".length());
}
for (Enumeration e_defs = tmp_font.enumerateChildren(); e_defs.hasMoreElements();) {
XMLElement tmp_def = (XMLElement) e_defs.nextElement();
if (tmp_def.getName().equals("system")) {
String defName = tmp_def.getStringAttribute("name");
String defStyle = tmp_def.getStringAttribute("style");
int defSize = Integer.parseInt(tmp_def.getStringAttribute("size"));
fontManager.setFont(face, style, size, fontManager.createSystemFont(defName, defStyle, defSize,
antialiasing));
} else if (tmp_def.getName().equals("ttf")) {
String defSrc = tmp_def.getStringAttribute("src");
String defStyle = tmp_def.getStringAttribute("style");
int defSize = Integer.parseInt(tmp_def.getStringAttribute("size"));
fontManager.setFont(face, style, size, fontManager.createTrueTypeFont(getResourceUrl(
classLoader, base, defSrc), defStyle, defSize, antialiasing));
}
}
}
}
}
private void parseInput(XMLElement tmp) {
DeviceDisplayImpl deviceDisplay = (DeviceDisplayImpl) getDeviceDisplay();
boolean resizable = deviceDisplay.isResizable();
for (Enumeration e_keyboard = tmp.enumerateChildren(); e_keyboard.hasMoreElements();) {
XMLElement tmp_keyboard = (XMLElement) e_keyboard.nextElement();
if (tmp_keyboard.getName().equals("haspointerevents")) {
hasPointerEvents = parseBoolean(tmp_keyboard.getContent());
} else if (tmp_keyboard.getName().equals("haspointermotionevents")) {
hasPointerMotionEvents = parseBoolean(tmp_keyboard.getContent());
} else if (tmp_keyboard.getName().equals("hasrepeatevents")) {
hasRepeatEvents = parseBoolean(tmp_keyboard.getContent());
} else if (tmp_keyboard.getName().equals("button")) {
Shape shape = null;
Hashtable inputToChars = new Hashtable();
for (Enumeration e_button = tmp_keyboard.enumerateChildren(); e_button.hasMoreElements();) {
XMLElement tmp_button = (XMLElement) e_button.nextElement();
if (tmp_button.getName().equals("chars")) {
String input = tmp_button.getStringAttribute("input", "common");
Vector stringArray = new Vector();
for (Enumeration e_chars = tmp_button.enumerateChildren(); e_chars.hasMoreElements();) {
XMLElement tmp_chars = (XMLElement) e_chars.nextElement();
if (tmp_chars.getName().equals("char")) {
stringArray.addElement(tmp_chars.getContent());
}
}
char[] charArray = new char[stringArray.size()];
for (int i = 0; i < stringArray.size(); i++) {
String str = (String) stringArray.elementAt(i);
if (str.length() > 0) {
charArray[i] = str.charAt(0);
} else {
charArray[i] = ' ';
}
}
inputToChars.put(input, charArray);
} else if (tmp_button.getName().equals("rectangle") && !resizable) {
shape = getRectangle(tmp_button);
} else if (tmp_button.getName().equals("polygon") && !resizable) {
shape = getPolygon(tmp_button);
}
}
int keyCode = tmp_keyboard.getIntAttribute("keyCode", Integer.MIN_VALUE);
getButtons().addElement(
deviceDisplay.createButton(skinVersion, tmp_keyboard.getStringAttribute("name"), shape,
keyCode, tmp_keyboard.getStringAttribute("key"), tmp_keyboard
.getStringAttribute("keyboardChars"), inputToChars, tmp_keyboard
.getBooleanAttribute("modeChange", false)));
} else if (tmp_keyboard.getName().equals("softbutton")) {
Vector commands = new Vector();
Shape shape = null;
Rectangle paintable = null;
Font font = null;
for (Enumeration e_button = tmp_keyboard.enumerateChildren(); e_button.hasMoreElements();) {
XMLElement tmp_button = (XMLElement) e_button.nextElement();
if (tmp_button.getName().equals("rectangle") && !resizable) {
shape = getRectangle(tmp_button);
} else if (tmp_button.getName().equals("polygon") && !resizable) {
shape = getPolygon(tmp_button);
} else if (tmp_button.getName().equals("paintable")) {
paintable = getRectangle(tmp_button);
} else if (tmp_button.getName().equals("command")) {
commands.addElement(tmp_button.getContent());
} else if (tmp_button.getName().equals("font")) {
font = getFont(tmp_button.getStringAttribute("face"), tmp_button.getStringAttribute("style"),
tmp_button.getStringAttribute("size"));
}
}
int keyCode = tmp_keyboard.getIntAttribute("keyCode", Integer.MIN_VALUE);
SoftButton button = deviceDisplay.createSoftButton(skinVersion,
tmp_keyboard.getStringAttribute("name"), shape, keyCode,
tmp_keyboard.getStringAttribute("key"), paintable,
tmp_keyboard.getStringAttribute("alignment"), commands, font);
getButtons().addElement(button);
getSoftButtons().addElement(button);
}
}
}
private void parseSystemProperties(XMLElement tmp) {
for (Enumeration e_prop = tmp.enumerateChildren(); e_prop.hasMoreElements();) {
XMLElement tmp_prop = (XMLElement) e_prop.nextElement();
if (tmp_prop.getName().equals("system-property")) {
systemProperties.put(tmp_prop.getStringAttribute("name"), tmp_prop.getStringAttribute("value"));
}
}
}
private static Font getFont(String face, String style, String size) {
int meFace = 0;
if (face.equalsIgnoreCase("system")) {
meFace |= Font.FACE_SYSTEM;
} else if (face.equalsIgnoreCase("monospace")) {
meFace |= Font.FACE_MONOSPACE;
} else if (face.equalsIgnoreCase("proportional")) {
meFace |= Font.FACE_PROPORTIONAL;
}
int meStyle = 0;
String testStyle = style.toLowerCase();
if (testStyle.indexOf("plain") != -1) {
meStyle |= Font.STYLE_PLAIN;
}
if (testStyle.indexOf("bold") != -1) {
meStyle |= Font.STYLE_BOLD;
}
if (testStyle.indexOf("italic") != -1) {
meStyle |= Font.STYLE_ITALIC;
}
if (testStyle.indexOf("underlined") != -1) {
meStyle |= Font.STYLE_UNDERLINED;
}
int meSize = 0;
if (size.equalsIgnoreCase("small")) {
meSize |= Font.SIZE_SMALL;
} else if (size.equalsIgnoreCase("medium")) {
meSize |= Font.SIZE_MEDIUM;
} else if (size.equalsIgnoreCase("large")) {
meSize |= Font.SIZE_LARGE;
}
return Font.getFont(meFace, meStyle, meSize);
}
private Rectangle getRectangle(XMLElement source) {
Rectangle rect = new Rectangle();
for (Enumeration e_rectangle = source.enumerateChildren(); e_rectangle.hasMoreElements();) {
XMLElement tmp_rectangle = (XMLElement) e_rectangle.nextElement();
if (tmp_rectangle.getName().equals("x")) {
rect.x = Integer.parseInt(tmp_rectangle.getContent());
} else if (tmp_rectangle.getName().equals("y")) {
rect.y = Integer.parseInt(tmp_rectangle.getContent());
} else if (tmp_rectangle.getName().equals("width")) {
rect.width = Integer.parseInt(tmp_rectangle.getContent());
} else if (tmp_rectangle.getName().equals("height")) {
rect.height = Integer.parseInt(tmp_rectangle.getContent());
}
}
return rect;
}
private Polygon getPolygon(XMLElement source) {
Polygon poly = new Polygon();
for (Enumeration e_poly = source.enumerateChildren(); e_poly.hasMoreElements();) {
XMLElement tmp_point = (XMLElement) e_poly.nextElement();
if (tmp_point.getName().equals("point")) {
poly.addPoint(Integer.parseInt(tmp_point.getStringAttribute("x")), Integer.parseInt(tmp_point
.getStringAttribute("y")));
}
}
return poly;
}
private boolean parseBoolean(String value) {
if (value.toLowerCase().equals(new String("true").toLowerCase())) {
return true;
} else {
return false;
}
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#hasPointerEvents()
*/
public boolean hasPointerEvents() {
return hasPointerEvents;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#hasPointerMotionEvents()
*/
public boolean hasPointerMotionEvents() {
return hasPointerMotionEvents;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#hasRepeatEvents()
*/
public boolean hasRepeatEvents() {
return hasRepeatEvents;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#hasRepeatEvents()
*/
public boolean vibrate(int duration) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.microemu.device.DeviceA#getSystemProperties()
*/
public Map getSystemProperties() {
return this.systemProperties;
}
private static void saveDevice(XMLElement doc) {
File configFile = new File(".", "device-tmp.xml");
FileWriter fw = null;
try {
fw = new FileWriter(configFile);
doc.write(fw);
fw.close();
} catch (IOException ex) {
System.out.println(ex);
} finally {
IOUtils.closeQuietly(fw);
}
}
private static XMLElement loadDeviceDescriptor(ClassLoader classLoader, String descriptorLocation)
throws IOException {
InputStream descriptor = classLoader.getResourceAsStream(descriptorLocation);
if (descriptor == null) {
throw new IOException("Cannot find descriptor at: " + descriptorLocation);
}
XMLElement doc;
try {
doc = loadXmlDocument(descriptor);
} finally {
IOUtils.closeQuietly(descriptor);
}
String parent = doc.getStringAttribute("extends");
if (parent != null) {
return inheritXML(loadDeviceDescriptor(classLoader, expandResourcePath(besourceBase(descriptorLocation),
parent)), doc, "/");
}
return doc;
}
private static void inheritanceConstInit() {
if (specialInheritanceAttributeSet == null) {
specialInheritanceAttributeSet = new Hashtable();
specialInheritanceAttributeSet.put("//FONTS/FONT", new String[] { "face", "style", "size" });
}
}
/**
* Very simple xml inheritance for devices.
*/
static XMLElement inheritXML(XMLElement parent, XMLElement child, String parentName) {
inheritanceConstInit();
if (parent == null) {
return child;
}
parent.setContent(child.getContent());
for (Enumeration ena = child.enumerateAttributeNames(); ena.hasMoreElements();) {
String key = (String) ena.nextElement();
parent.setAttribute(key, child.getAttribute(key));
}
for (Enumeration enc = child.enumerateChildren(); enc.hasMoreElements();) {
XMLElement c = (XMLElement) enc.nextElement();
String fullName = (parentName + "/" + c.getName()).toUpperCase(Locale.ENGLISH);
// System.out.println("processing [" + fullName + "]");
boolean inheritWithName = false;
if (c.getStringAttribute("name") != null) {
inheritWithName = true;
} else {
// Find if element has siblings
inheritWithName = ((child.getChildCount(c.getName()) > 1) || (parent.getChildCount(c.getName()) > 1));
}
XMLElement p;
if (inheritWithName) {
String[] equalAttributes = (String[]) specialInheritanceAttributeSet.get(fullName);
if (equalAttributes != null) {
p = parent.getChild(c.getName(), c.getStringAttributes(equalAttributes));
} else {
p = parent.getChild(c.getName(), c.getStringAttribute("name"));
}
} else {
p = parent.getChild(c.getName());
}
boolean inheritOverride = c.getBooleanAttribute("override", false);
if (inheritOverride) {
// System.out.println("inheritXML override parent:" +
// parent.toString());
// System.out.println("inheritXML override c :" + c.toString());
// System.out.println("inheritXML override p :" + p.toString());
c.removeAttribute("override");
if (p != null) {
parent.removeChild(p);
p = null;
}
}
// System.out.println("inheritXML " + c.getName());
if (p == null) {
parent.addChild(c);
} else {
inheritXML(p, c, fullName);
}
}
return parent;
}
private static XMLElement loadXmlDocument(InputStream descriptor) throws IOException {
XMLElement doc = new XMLElement();
try {
doc.parse(descriptor, 1);
} catch (XMLParseException ex) {
throw new IOException(ex.toString());
}
return doc;
}
private static String besourceBase(String descriptorLocation) {
return descriptorLocation.substring(0, descriptorLocation.lastIndexOf("/"));
}
private static String expandResourcePath(String base, String src) throws IOException {
String expandedSource;
if (src.startsWith("/")) {
expandedSource = src;
} else {
expandedSource = base + "/" + src;
}
if (expandedSource.startsWith("/")) {
expandedSource = expandedSource.substring(1);
}
return expandedSource;
}
private URL getResourceUrl(ClassLoader classLoader, String base, String src) throws IOException {
String expandedSource = expandResourcePath(base, src);
URL result = classLoader.getResource(expandedSource);
if (result == null) {
throw new IOException("Cannot find resource: " + expandedSource);
}
return result;
}
private Image loadImage(ClassLoader classLoader, String base, String src) throws IOException {
URL url = getResourceUrl(classLoader, base, src);
return ((DeviceDisplayImpl) getDeviceDisplay()).createSystemImage(url);
}
}