All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.microemu.device.impl.DeviceImpl Maven / Gradle / Ivy

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);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy