Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.codename1.ui.util;
import com.codename1.io.Log;
import com.codename1.ui.*;
import com.codename1.ui.animations.AnimationObject;
import com.codename1.ui.animations.Timeline;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.plaf.Border;
import com.codename1.ui.plaf.CSSBorder;
import com.codename1.ui.plaf.RoundBorder;
import com.codename1.ui.plaf.RoundRectBorder;
import com.codename1.ui.plaf.Style;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Loads resources from the binary resource file generated by the Codename One Designer.
* A resource is loaded entirely into memory since random file access is not supported
* in all platforms. Any other approach would be inefficient. This means that memory must
* be made available to accommodate the resource file.
*
* @author Shai Almog
*/
public class Resources {
private static boolean enableMediaQueries = true;
/**
* Magic numbers to prevent data corruption
*/
static final byte MAGIC_THEME_LEGACY = (byte)0xF7;
static final byte MAGIC_ANIMATION_LEGACY = (byte)0xF8;
static final byte MAGIC_INDEXED_IMAGE_LEGACY = (byte)0xF4;
static final byte MAGIC_FONT_LEGACY = (byte)0xF6;
static final byte MAGIC_INDEXED_FONT_LEGACY = (byte)0xFB;
static final byte MAGIC_IMAGE_LEGACY = (byte)0xF3;
static final byte MAGIC_SVG = (byte)0xF5;
static final byte MAGIC_TIMELINE = (byte)0xEF;
static final byte MAGIC_FONT = (byte)0xFC;
static final byte MAGIC_IMAGE = (byte)0xFD;
static final byte MAGIC_L10N = (byte)0xF9;
static final byte MAGIC_DATA = (byte)0xFA;
static final byte MAGIC_UI = (byte)0xEE;
static final byte MAGIC_HEADER = (byte)0xFF;
static final byte MAGIC_PASSWORD = (byte)0xFE;
/**
* This variable is used by new GUI builder apps to keep track of the applications resources
*/
private static Resources globalResources;
/**
* This variable is used to cache the system resources file CN1Resource.res
*/
private static Resources systemResource;
/**
* @return the failOnMissingTruetype
*/
public static boolean isFailOnMissingTruetype() {
return failOnMissingTruetype;
}
public static void setEnableMediaQueries(boolean enable) {
enableMediaQueries = enable;
}
public static boolean isEnableMediaQueries() {
return enableMediaQueries;
}
/**
* @param aFailOnMissingTruetype the failOnMissingTruetype to set
*/
public static void setFailOnMissingTruetype(boolean aFailOnMissingTruetype) {
failOnMissingTruetype = aFailOnMissingTruetype;
}
short majorVersion;
short minorVersion;
private static byte[] key;
/**
* Temporary member for compatibility with older versions, in future versions
* this will supersede the MAGIC_THEME property
*/
static final byte MAGIC_THEME = (byte)0xF2;
static final int BORDER_TYPE_EMPTY = 0;
static final int BORDER_TYPE_LINE = 1;
static final int BORDER_TYPE_ROUNDED = 2;
static final int BORDER_TYPE_ETCHED_LOWERED = 4;
static final int BORDER_TYPE_ETCHED_RAISED = 5;
static final int BORDER_TYPE_BEVEL_RAISED = 6;
static final int BORDER_TYPE_BEVEL_LOWERED = 7;
static final int BORDER_TYPE_IMAGE = 8;
static final int BORDER_TYPE_IMAGE_HORIZONTAL = 10;
static final int BORDER_TYPE_IMAGE_VERTICAL = 11;
static final int BORDER_TYPE_DASHED = 12;
static final int BORDER_TYPE_DOTTED = 13;
static final int BORDER_TYPE_DOUBLE = 14;
static final int BORDER_TYPE_GROOVE = 15;
static final int BORDER_TYPE_RIDGE = 16;
static final int BORDER_TYPE_INSET = 17;
static final int BORDER_TYPE_OUTSET = 18;
static final int BORDER_TYPE_IMAGE_SCALED = 19;
static final int BORDER_TYPE_IMAGE_ROUND = 20;
static final int BORDER_TYPE_UNDERLINE = 21;
// for use by the resource editor
private static Class classLoader = Resources.class;
private String[] metaData;
/**
* These variables are useful for caching the last loaded resource which might
* happen frequently in the UI builder when moving between applications screens
*/
private static Object cachedResource;
private static String lastLoadedName;
private static int lastLoadedDPI;
private static boolean runtimeMultiImages;
private static final String systemResourceLocation = "/CN1Resource.res";
private static boolean failOnMissingTruetype = true;
/**
* This flag should be off and it is off by default, some special case implementations for development
* e.g. the AWT implementation activate this flag in order to use the EncodedImage multi-image support
* which is entirely for development only!
* @deprecated do not use this method!
*/
public static void setRuntimeMultiImageEnabled(boolean b) {
runtimeMultiImages = b;
}
static void setClassLoader(Class cls) {
classLoader = cls;
}
private int dpi = -1;
/**
* Hashtable containing the mapping between element types and their names in the
* resource hashtable
*/
private HashMap resourceTypes = new HashMap();
/**
* A cache within the resource allowing us to preserve some resources in memory
* so they can be utilized by a theme when it is loaded
*/
private HashMap resources = new HashMap();
private DataInputStream input;
// for internal use by the resource editor, creates an empty resource
Resources() {
}
Resources(InputStream input, int dpi) throws IOException {
this.dpi = dpi;
openFile(input);
}
void clear() {
majorVersion = 0;
minorVersion = 0;
resourceTypes.clear();
resources.clear();
input = null;
}
Timeline readTimeline(DataInputStream input) throws IOException {
int duration = input.readInt();
int width = input.readInt();
int height = input.readInt();
AnimationObject[] animations = new AnimationObject[input.readShort()];
int alen = animations.length;
for(int iter = 0 ; iter < alen ; iter++) {
String name = input.readUTF();
int startTime = input.readInt();
int animDuration = input.readInt();
int x = input.readInt();
int y = input.readInt();
Image i = getImage(name);
if(i == null) {
animations[iter] = AnimationObject.createAnimationImage(name, this, x, y);
} else {
animations[iter] = AnimationObject.createAnimationImage(i, x, y);
}
animations[iter].setStartTime(startTime);
animations[iter].setEndTime(startTime + animDuration);
int frameDelay = input.readInt();
if(frameDelay > -1) {
int frameWidth = input.readInt();
int frameHeight = input.readInt();
animations[iter].defineFrames(frameWidth, frameHeight, frameDelay);
}
if(input.readBoolean()) {
animations[iter].defineMotionX(input.readInt(), startTime, animDuration, x, input.readInt());
}
if(input.readBoolean()) {
animations[iter].defineMotionY(input.readInt(), startTime, animDuration, y, input.readInt());
}
if(input.readBoolean()) {
animations[iter].defineWidth(input.readInt(), startTime, animDuration, input.readInt(), input.readInt());
}
if(input.readBoolean()) {
animations[iter].defineHeight(input.readInt(), startTime, animDuration, input.readInt(), input.readInt());
}
if(input.readBoolean()) {
animations[iter].defineOpacity(input.readInt(), startTime, animDuration, input.readInt(), input.readInt());
}
if(input.readBoolean()) {
animations[iter].defineOrientation(input.readInt(), startTime, animDuration, input.readInt(), input.readInt());
}
}
Timeline tl = Timeline.createTimeline(duration, animations, new Dimension(width, height));
return tl;
}
/**
* This method is used by the Codename One Designer
*/
void startingEntry(String id, byte magic) {
}
/**
* This method allows overriding the data of a resource file with another resource file thus replacing
* or enhancing existing content with platform specific content. E.g. default icons for the application
* can be overriden on a specific platform
*
* @param input a new resource file
* @throws IOException exception thrown from the stream
*/
public void override(InputStream input) throws IOException {
openFileImpl(input);
}
void openFile(InputStream input) throws IOException {
clear();
openFileImpl(input);
}
private void openFileImpl(InputStream input) throws IOException {
this.input = new DataInputStream(input);
int resourceCount = this.input.readShort();
if(resourceCount < 0) {
throw new IOException("Invalid resource file!");
}
boolean password = false;
keyOffset = 0;
for(int iter = 0 ; iter < resourceCount ; iter++) {
byte magic = this.input.readByte();
String id = this.input.readUTF();
if(password) {
magic = (byte)decode(magic & 0xff);
char[] chars = id.toCharArray();
int clen = chars.length;
for(int i = 0 ; i < clen ; i++) {
chars[i] = (char)decode(chars[i] & 0xffff);
}
id = new String(chars);
}
startingEntry(id, magic);
switch(magic) {
case MAGIC_PASSWORD:
checkKey(id);
password = true;
continue;
case MAGIC_HEADER:
readHeader();
continue;
case MAGIC_THEME:
setResource(id, MAGIC_THEME, loadTheme(id, magic == MAGIC_THEME));
continue;
case MAGIC_IMAGE:
Image img = createImage();
img.setImageName(id);
setResource(id, magic, img);
continue;
case MAGIC_FONT:
setResource(id, magic, loadFont(this.input, id, false));
continue;
case MAGIC_DATA:
setResource(id, magic, createData());
continue;
case MAGIC_UI:
setResource(id, magic, createData());
continue;
case MAGIC_L10N:
setResource(id, magic, loadL10N());
continue;
// legacy file support to be removed
case MAGIC_IMAGE_LEGACY:
setResource(id, MAGIC_IMAGE, createImage());
continue;
case MAGIC_INDEXED_IMAGE_LEGACY:
setResource(id, MAGIC_IMAGE, createPackedImage8());
continue;
case MAGIC_THEME_LEGACY:
setResource(id, MAGIC_THEME, loadTheme(id, magic == MAGIC_THEME));
continue;
case MAGIC_FONT_LEGACY:
setResource(id, MAGIC_FONT, loadFont(this.input, id, false));
continue;
case MAGIC_INDEXED_FONT_LEGACY:
setResource(id, MAGIC_FONT, loadFont(this.input, id, true));
continue;
default:
throw new IOException("Corrupt theme file unrecognized magic number: " + Integer.toHexString(magic & 0xff));
}
}
}
/**
* Sets the password to use for password protected resource files
*
* @param password the password or null to clear the password
*/
public static void setPassword(String password) {
try {
if(password == null) {
key = null;
return;
}
key = password.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
// won't happen
ex.printStackTrace();
}
}
void checkKey(String id) {
if(key == null) {
throw new IllegalStateException("This is a password protected resource");
}
char l = (char)decode(id.charAt(0));
char w = (char)decode(id.charAt(1));
if(l != 'l' || w != 'w') {
throw new IllegalStateException("Incorrect password");
}
}
int keyOffset;
private int decode(int val) {
val = key[keyOffset] ^ val;
keyOffset++;
if(keyOffset == key.length) {
keyOffset = 0;
}
return val;
}
/**
* Reads the header of the resource file
*/
private void readHeader() throws IOException {
int size = input.readShort();
majorVersion = input.readShort();
minorVersion = input.readShort();
metaData = new String[input.readShort()];
int mlen = metaData.length;
for(int iter = 0 ; iter < mlen ; iter++) {
metaData[iter] = input.readUTF();
}
}
/**
* Returns the version number for this resource file.
* This value relates to the value from the header defined by the resource file
* specification. 0 is returned for legacy versions of the resource file format.
*
* @return major version number for the resource file
*/
public int getMajorVersion() {
return majorVersion;
}
/**
* Returns the minor version number for this resource file
* This value relates to the value from the header defined by the resource file
* specification.
*
* @return minor version number for the resource file
*/
public int getMinorVersion() {
return minorVersion;
}
/**
* Returns optional meta-data associated with the resource file
*
* @return optional meta-data associated with the file
*/
public String[] getMetaData() {
return metaData;
}
/**
* Returns the names of the resources within this bundle
*
* @return array of names of all the resources in this bundle
*/
public String[] getResourceNames() {
String[] arr = new String[resourceTypes.size()];
Iterator e = resourceTypes.keySet().iterator();
int alen = arr.length;
for(int iter = 0 ; iter < alen ; iter++) {
arr[iter] = (String)e.next();
}
return arr;
}
/**
* Returns the names of the data resources within this bundle
*
* @return array of names of the data resources in this bundle
*/
public String[] getDataResourceNames() {
return getResourceTypeNames(MAGIC_DATA);
}
/**
* Returns the names of the ui resources within this bundle
*
* @return array of names of the ui resources in this bundle
*/
public String[] getUIResourceNames() {
return getResourceTypeNames(MAGIC_UI);
}
/**
* For internal use only
*/
void setResource(String id, byte type, Object value) {
if(value == null) {
resources.remove(id);
resourceTypes.remove(id);
} else {
resources.put(id, value);
resourceTypes.put(id, new Byte(type));
}
}
/**
* Returns the names of the localization bundles within this bundle
*
* @return array of names of the localization resources in this bundle
*/
public String[] getL10NResourceNames() {
return getResourceTypeNames(MAGIC_L10N);
}
/**
* Returns the names of the fonts within this bundle
*
* @return array of names of the font resources in this bundle
*/
public String[] getFontResourceNames() {
ArrayList vec = new ArrayList();
Iterator e = resourceTypes.keySet().iterator();
while(e.hasNext()) {
String c = (String)e.next();
if(isFont(c)) {
vec.add(c);
}
}
return toStringArray(vec);
}
/**
* Returns the names of the images within this bundle
*
* @return array of names of the image resources in this bundle
*/
public String[] getThemeResourceNames() {
ArrayList vec = new ArrayList();
Iterator e = resourceTypes.keySet().iterator();
while(e.hasNext()) {
String c = (String)e.next();
if(isTheme(c)) {
vec.add(c);
}
}
return toStringArray(vec);
}
/**
* Returns the names of the images within this bundle
*
* @return array of names of the image resources in this bundle
*/
public String[] getImageResourceNames() {
ArrayList vec = new ArrayList();
Iterator e = resourceTypes.keySet().iterator();
while(e.hasNext()) {
String c = e.next();
if(isImage(c)) {
vec.add(c);
}
}
return toStringArray(vec);
}
/**
* For internal use only
*/
byte getResourceType(String name) {
Byte b = (Byte)resourceTypes.get(name);
if(b == null) {
return (byte)0;
}
return b.byteValue();
}
private String[] getResourceTypeNames(byte b) {
ArrayList vec = new ArrayList();
Iterator e = resourceTypes.keySet().iterator();
while(e.hasNext()) {
String c = e.next();
if(((Byte)resourceTypes.get(c)).byteValue() == b) {
vec.add(c);
}
}
return toStringArray(vec);
}
private static String[] toStringArray(ArrayList v) {
String[] s = new String[v.size()];
int slen = v.size();
for(int iter = 0 ; iter < slen ; iter++) {
s[iter] = (String)v.get(iter);
}
return s;
}
/**
* Returns true if this is a generic data resource
*
* @param name the name of the resource
* @return true if the resource is a data resource
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isL10N(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_L10N;
}
/**
* Returns true if this is a theme resource
*
* @param name the name of the resource
* @return true if the resource is a theme
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isTheme(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_THEME_LEGACY || b == MAGIC_THEME;
}
/**
* Returns true if this is a font resource
*
* @param name the name of the resource
* @return true if the resource is a font
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isFont(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_FONT || b == MAGIC_FONT_LEGACY || b == MAGIC_INDEXED_FONT_LEGACY;
}
/**
* Returns true if this is an animation resource
*
* @param name the name of the resource
* @return true if the resource is an animation
* @throws NullPointerException if the resource doesn't exist
* @deprecated animations are no longer distinguished from images in the resource file, use Image.isAnimation instead
*/
public boolean isAnimation(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_ANIMATION_LEGACY;
}
/**
* Returns true if this is a data resource
*
* @param name the name of the resource
* @return true if the resource is a data resource
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isData(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_DATA;
}
/**
* Returns true if this is a UI resource
*
* @param name the name of the resource
* @return true if the resource is a UI resource
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isUI(String name) {
byte b = ((Byte)resourceTypes.get(name)).byteValue();
return b == MAGIC_UI;
}
/**
* Returns true if this is an image resource
*
* @param name the name of the resource
* @return true if the resource is an image
* @throws NullPointerException if the resource doesn't exist
*/
public boolean isImage(String name) {
Byte bt = (Byte)resourceTypes.get(name);
if(bt == null) {
return false;
}
byte b = bt.byteValue();
return b == MAGIC_IMAGE_LEGACY || b == MAGIC_ANIMATION_LEGACY ||
b == MAGIC_INDEXED_IMAGE_LEGACY || b == MAGIC_IMAGE ||
b == MAGIC_TIMELINE;
}
/**
* Opens a multi-layer resource file that supports overriding features on a specific
* platform. Notice that the ".res" extension MUST not be given to this method!
*
* @param resource a local reference to a resource using the syntax of Class.getResourceAsStream(String)
* however the extension MUST not be included in the name! E.g. to reference /x.res use /x
* @return a resource object
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources openLayered(String resource) throws IOException {
return openLayered(resource, -1);
}
/**
* Creates a resource object from the local JAR resource identifier
*
* @param resource a local reference to a resource using the syntax of Class.getResourceAsStream(String)
* @return a resource object
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources open(String resource) throws IOException {
return open(resource, -1);
}
/**
* Creates a resource object from the given input stream
*
* @param resource stream from which to read the resource
* @return a resource object
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources open(InputStream resource) throws IOException {
return open(resource, -1);
}
/**
* Opens a multi-layer resource file that supports overriding features on a specific
* platform. Notice that the ".res" extension MUST not be given to this method!
*
* @param resource a local reference to a resource using the syntax of Class.getResourceAsStream(String)
* however the extension MUST not be included in the name! E.g. to reference /x.res use /x
* @param dpi the dpi used for the loaded images
* @return a resource object
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources openLayered(String resource, int dpi) throws IOException {
Resources r = open(resource + ".res", dpi);
String[] over = Display.getInstance().getPlatformOverrides();
int olen = over.length;
for(int iter = 0 ; iter < olen ; iter++) {
InputStream i = Display.getInstance().getResourceAsStream(classLoader, resource + "_" + over[iter] + ".ovr");
if(i != null) {
r.override(i);
i.close();
}
}
return r;
}
/**
* Creates a resource object from the local JAR resource identifier
*
* @param resource a local reference to a resource using the syntax of Class.getResourceAsStream(String)
* @return a resource object
* @param dpi the dpi used for the loaded images
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources open(String resource, int dpi) throws IOException {
try {
if (resource.equals(Resources.systemResourceLocation) && systemResource != null) {
return systemResource;
}
if(lastLoadedName != null && lastLoadedName.equals(resource) && lastLoadedDPI == dpi) {
Resources r = (Resources)Display.getInstance().extractHardRef(cachedResource);
if(r != null) {
return r;
}
}
InputStream is = Display.getInstance().getResourceAsStream(classLoader, resource);
if(is == null) {
throw new IOException(resource + " not found");
}
Resources r = new Resources(is, dpi);
is.close();
if(resource.equals(Resources.systemResourceLocation)){
systemResource = r;
return r;
}
lastLoadedDPI = dpi;
lastLoadedName = resource;
cachedResource = Display.getInstance().createSoftWeakRef(r);
return r;
} catch(RuntimeException err) {
// intercept exceptions since user code might not deal well with runtime exceptions
Log.e(err);
throw new IOException(err.getMessage());
}
}
/**
* Creates a resource object from the given input stream
*
* @param resource stream from which to read the resource
* @param dpi the dpi used for the loaded images
* @return a resource object
* @throws java.io.IOException if opening/reading the resource fails
*/
public static Resources open(InputStream resource, int dpi) throws IOException {
return new Resources(resource, dpi);
}
/**
* Returns the image resource from the file
*
* @param id name of the image resource
* @return cached image instance
*/
public Image getImage(String id) {
return (Image)resources.get(id);
}
/**
* Returns the data resource from the file
*
* @param id name of the data resource
* @return newly created input stream that allows reading the data of the resource
*/
public InputStream getData(String id) {
byte[] data = (byte[])resources.get(id);
if(data == null) {
return null;
}
return new ByteArrayInputStream(data);
}
/**
* Returns the ui resource from the file
*
* @param id name of the ui resource
* @return newly created input stream that allows reading the ui of the resource
*/
InputStream getUi(String id) {
byte[] d = (byte[])resources.get(id);
if(d == null) {
return null;
}
return new ByteArrayInputStream(d);
}
/**
* Returns a hashmap containing localized String key/value pairs for the given locale name
*
* @param id the name of the locale resource
* @param locale name of the locale resource
* @return Hashtable containing key value pairs for localized data
*/
public Hashtable getL10N(String id, String locale) {
return (Hashtable)((Hashtable)resources.get(id)).get(locale);
}
/**
* Returns an enumration of the locales supported by this resource id
*
* @param id the name of the locale resource
* @return enumeration of strings containing bundle names
*/
public Enumeration listL10NLocales(String id) {
return ((Hashtable)resources.get(id)).keys();
}
/**
* Returns a collection of the l10 locale names
*
* @param id the name of the locale resource
* @return collection of strings containing bundle names
*/
public Collection l10NLocaleSet(String id) {
return ((Hashtable)resources.get(id)).keySet();
}
/**
* Returns the font resource from the file
*
* @param id name of the font resource
* @return cached font instance
*/
public Font getFont(String id) {
return (Font)resources.get(id);
}
/**
* Returns the theme resource from the file
*
* @param id name of the theme resource
* @return cached theme instance
*/
public Hashtable getTheme(String id) {
Hashtable h = (Hashtable)resources.get(id);
// theme can be null in valid use cases such as the resource editor
if(h != null && h.containsKey("uninitialized")) {
Enumeration e = h.keys();
while(e.hasMoreElements()) {
String key = (String)e.nextElement();
if(key.endsWith("font") || (key.endsWith("Image") && !key.endsWith("scaledImage"))) {
Object value = h.get(key);
if(value == null) {
throw new IllegalArgumentException("Couldn't find resource: " + key);
}
// the resource was not already loaded when we loaded the theme
// it must be loaded now so we can resolve the temporary name
if(value instanceof String) {
Object o;
// we need to trigger multi image logic in the resource editor
if(key.endsWith("Image")) {
o = getImage((String)value);
} else {
o = resources.get(value);
}
if(o == null) {
throw new IllegalArgumentException("Theme entry for " + key + " could not be found: " + value);
}
h.put(key, o);
}
}
// if this is a border we might need to do additional work for older versions
// of Codename One and for the case of an image border where the images might not have
// been loaded yet when the border was created
if(key.endsWith("order")) {
Border b = confirmBorder(h, key);
h.put(key, b);
}
}
h.remove("uninitialized");
}
return h;
}
private Border confirmBorder(Hashtable h, String key) {
Object val = h.get(key);
if(val == null) {
return null;
}
if(!(val instanceof Border)) {
String[] value = (String[])val;
if(value == null) {
throw new IllegalArgumentException("Couldn't find resource: " + key);
}
// the resource was not already loaded when we loaded the theme
// it must be loaded now so we can resolve the temporary name
Border imageBorder = createImageBorder(value);
return imageBorder;
}
return (Border)val;
}
private Border createImageBorder(String[] value) {
if(value[0].equals("h")) {
return Border.createHorizonalImageBorder(getImage(value[1]),
getImage(value[2]), getImage(value[3]));
}
if(value[0].equals("v")) {
return Border.createVerticalImageBorder(getImage(value[1]),
getImage(value[2]), getImage(value[3]));
}
if(value[0].equals("s")) {
Image[] images = new Image[value.length - 1];
int ilen = images.length;
for(int iter = 0 ; iter < ilen ; iter++) {
images[iter] = getImage(value[iter + 1]);
}
return Border.createImageScaledBorder(images[0], images[1], images[2],
images[3], images[4], images[5], images[6], images[7], images[8]);
}
Image[] images = new Image[value.length];
int vlen = value.length;
for(int iter = 0 ; iter < vlen ; iter++) {
images[iter] = getImage(value[iter]);
}
switch(images.length) {
case 2:
return Border.createImageBorder(images[0], images[1], null);
case 3:
return Border.createImageBorder(images[0], images[1], images[2]);
case 8:
return Border.createImageBorder(images[0], images[1], images[2],
images[3], images[4], images[5], images[6], images[7], null);
default:
return Border.createImageBorder(images[0], images[1], images[2],
images[3], images[4], images[5], images[6], images[7], images[8]);
}
}
Object getResourceObject(String res) {
return resources.get(res);
}
Image createImage() throws IOException {
return createImage(input);
}
Image createImage(DataInputStream input) throws IOException {
if(majorVersion == 0 && minorVersion == 0) {
byte[] data = new byte[input.readInt()];
input.readFully(data, 0, data.length);
return EncodedImage.create(data);
} else {
int type = input.readByte() & 0xff;
switch(type) {
// PNG file
case 0xf1:
// JPEG File
case 0xf2:
byte[] data = new byte[input.readInt()];
input.readFully(data, 0, data.length);
if(minorVersion > 3) {
int width = input.readInt();
int height = input.readInt();
boolean opaque = input.readBoolean();
return EncodedImage.create(data, width, height, opaque);
}
return EncodedImage.create(data);
// Indexed image
case 0xF3:
return createPackedImage8();
// SVG
case 0xF5: {
int svgSize = input.readInt();
if(Image.isSVGSupported()) {
byte[] s = new byte[svgSize];
input.readFully(s);
String baseURL = input.readUTF();
boolean animated = input.readBoolean();
loadSVGRatios(input);
byte[] fallback = new byte[input.readInt()];
if(fallback.length > 0) {
input.readFully(fallback, 0, fallback.length);
}
return Image.createSVG(baseURL, animated, s);
} else {
svgSize -= input.skip(svgSize);
while(svgSize > 0) {
svgSize -= input.skip(svgSize);
}
// read the base url, the animated property and screen ratios to skip them as well...
input.readUTF();
input.readBoolean();
input.readFloat();
input.readFloat();
byte[] fallback = new byte[input.readInt()];
input.readFully(fallback, 0, fallback.length);
return EncodedImage.create(fallback);
}
}
// SVG with multi-image
case 0xf7: {
int svgSize = input.readInt();
if(Image.isSVGSupported()) {
byte[] s = new byte[svgSize];
input.readFully(s);
String baseURL = input.readUTF();
boolean animated = input.readBoolean();
Image img = readMultiImage(input, true);
Image svg = createSVG(animated, s);
if(svg.getSVGDocument() == null) {
return img;
}
return svg;
} else {
svgSize -= input.skip(svgSize);
while(svgSize > 0) {
svgSize -= input.skip(svgSize);
}
String baseURL = input.readUTF();
// read the animated property to skip it as well...
input.readBoolean();
return readMultiImage(input);
}
}
// mutli image
case 0xF6:
return readMultiImage(input);
case 0xEF:
Timeline tl = readTimeline(input);
return tl;
// Fail this is the wrong data type
default:
throw new IOException("Illegal type while creating image: " + Integer.toHexString(type));
}
}
}
com.codename1.ui.Image createSVG(boolean animated, byte[] data) throws IOException {
return Image.createSVG(null, animated, data);
}
private Image readMultiImage(DataInputStream input) throws IOException {
return readMultiImage(input, false);
}
Image readMultiImage(DataInputStream input, boolean skipAll) throws IOException {
EncodedImage resultImage = null;
if(dpi == -1) {
dpi = Display.getInstance().getDeviceDensity();
}
int dpiCount = input.readInt();
int bestFitOffset = 0;
int bestFitDPI = 0;
int[] lengths = new int[dpiCount];
int[] dpis = new int[dpiCount];
boolean found = false;
for(int iter = 0 ; iter < dpiCount ; iter++) {
int currentDPI = input.readInt();
lengths[iter] = input.readInt();
dpis[iter] = currentDPI;
if(bestFitDPI != dpi && dpi >= currentDPI && currentDPI >= bestFitDPI) {
bestFitDPI = currentDPI;
bestFitOffset = iter;
found = true;
}
}
if(!found) {
// special case for low DPI devices when running with high resolution resources
// we want to pick the loweset resolution possible
bestFitDPI = dpis[0];
bestFitOffset = 0;
for(int iter = 1 ; iter < dpiCount ; iter++) {
if(dpis[iter] < bestFitDPI) {
bestFitDPI = dpis[iter];
bestFitOffset = iter;
}
}
}
if(runtimeMultiImages && !skipAll) {
byte[][] data = new byte[dpiCount][];
for(int iter = 0 ; iter < lengths.length ; iter++) {
int size = lengths[iter];
data[iter] = new byte[size];
input.readFully(data[iter], 0, size);
}
return EncodedImage.createMulti(dpis, data);
} else {
for(int iter = 0 ; iter < lengths.length ; iter++) {
int size = lengths[iter];
if(!skipAll && bestFitOffset == iter) {
byte[] multiImageData = new byte[size];
input.readFully(multiImageData, 0, size);
resultImage = EncodedImage.create(multiImageData);
} else {
while(size > 0) {
size -= input.skip(size);
}
}
}
}
return resultImage;
}
void loadSVGRatios(DataInputStream input) throws IOException {
input.readFloat();
input.readFloat();
}
private byte[] createData() throws IOException {
byte[] data = new byte[input.readInt()];
input.readFully(data);
return data;
}
Font loadFont(DataInputStream input, String id, boolean packed) throws IOException {
if(majorVersion == 0 && minorVersion == 0) {
Image bitmap;
if(packed) {
bitmap = createPackedImage8();
} else {
bitmap = createImage(input);
}
int charCount = input.readShort();
int[] cutOffsets = new int[charCount];
int[] charWidth = new int[charCount];
for(int iter = 0 ; iter < charCount ; iter++) {
cutOffsets[iter] = input.readShort();
charWidth[iter] = input.readByte();
}
String charset = input.readUTF();
Font old = Font.getBitmapFont(id);
if(old != null) {
return old;
}
return Font.createBitmapFont(id, bitmap, cutOffsets, charWidth, charset);
}
// read a system font fallback
int fallback = input.readByte() & 0xff;
// do we have an emedded truetype font? Do we support embedded fonts?
boolean trueTypeIncluded = input.readBoolean();
Font font = null;
/*if(trueTypeIncluded) {
int size = input.readInt();
if(Font.isTrueTypeFileSupported()) {
font = Font.createTrueTypeFont(input);
} else {
while(size > 0) {
size -= input.skip(size);
}
}
}*/
boolean lookupIncluded = input.readBoolean();
if(lookupIncluded) {
String lookup = input.readUTF();
if(font == null && Font.isCreationByStringSupported()) {
font = Font.create(lookup);
}
}
boolean bitmapIncluded = input.readBoolean();
if(bitmapIncluded) {
font = loadBitmapFont(input, id, font);
}
if(font != null) {
return font;
}
return Font.createSystemFont(fallback & (Font.FACE_MONOSPACE | Font.FACE_PROPORTIONAL | Font.FACE_SYSTEM),
fallback & (Font.STYLE_BOLD | Font.STYLE_ITALIC | Font.STYLE_PLAIN | Font.STYLE_UNDERLINED),
fallback & (Font.SIZE_LARGE | Font.SIZE_MEDIUM| Font.SIZE_SMALL));
}
void readRenderingHint(DataInputStream i) throws IOException {
i.readByte();
}
Font loadBitmapFont(DataInputStream input, String id, com.codename1.ui.Font font) throws IOException {
Image bitmap = createImage(input);
int charCount = input.readShort();
int[] cutOffsets = new int[charCount];
int[] charWidth = new int[charCount];
for(int iter = 0 ; iter < charCount ; iter++) {
cutOffsets[iter] = input.readShort();
}
for(int iter = 0 ; iter < charCount ; iter++) {
charWidth[iter] = input.readByte();
}
String charset = input.readUTF();
readRenderingHint(input);
if(font == null) {
if(Font.isBitmapFontEnabled()) {
Font old = Font.getBitmapFont(id);
if(old != null) {
// Returning bitmap font from cache, to prevent collision with an
// old resource file use Font.clearBitmapCache()
return old;
}
return Font.createBitmapFont(id, bitmap, cutOffsets, charWidth, charset);
}
}
return font;
}
Font createTrueTypeFont(Font f, String fontName, String fileName, float fontSize, int sizeSetting) {
switch(sizeSetting) {
case 0: // small
fontSize = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL).getHeight();
break;
case 1: // medium
fontSize = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM).getHeight();
break;
case 2: // large
fontSize = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE).getHeight();
break;
case 3: // millimetres
fontSize = Display.getInstance().convertToPixels((int)(fontSize * 10), true) / 10.0f;
break;
case 4: // pixels
break;
case 5: // rem
fontSize = Font.getDefaultFont().getHeight() * fontSize;
break;
case 6: // vw
fontSize = CN.getDisplayWidth() * fontSize / 100f;
break;
case 7: // vh
fontSize = CN.getDisplayHeight() * fontSize / 100f;
break;
case 8: // vmin
fontSize = Math.min(CN.getDisplayWidth(), CN.getDisplayHeight()) * fontSize / 100f;
break;
case 9: // vmax
fontSize = Math.max(CN.getDisplayWidth(), CN.getDisplayHeight()) * fontSize / 100f;
break;
}
if(!failOnMissingTruetype) {
try {
Font ttf = Font.createTrueTypeFont(fontName, fileName);
if (ttf != null) {
return ttf.derive(fontSize, f.getStyle());
}
return f;
} catch (Exception ex) {
return f;
}
}
return Font.createTrueTypeFont(fontName, fileName).derive(fontSize, f.getStyle());
}
Hashtable loadTheme(String id, boolean newerVersion) throws IOException {
Hashtable theme = new Hashtable();
String densityStr = Display.getInstance().getDensityStr();
String platformName = Display.getInstance().getPlatformName();
if ("HTML5".equals(platformName)) {
platformName = Display.getInstance().getProperty("HTML5.platformName", "mac");
}
String deviceType = Display.getInstance().isDesktop() ? "desktop" : Display.getInstance().isTablet() ? "tablet" : "phone";
String platformPrefix = "platform-"+platformName+"-";
String densityPrefix = "density-"+densityStr+"-";
String devicePrefix = "device-"+deviceType+"-";
String platformDensityPrefix = platformPrefix+densityPrefix;
String devicePlatformPrefix = devicePrefix+platformPrefix;
String devicePlatformDensityPrefix = devicePlatformPrefix+densityPrefix;
theme.put("name", id);
// marks the theme as uninitialized so we can finish "wiring" cached resources
theme.put("uninitialized", Boolean.TRUE);
int size = input.readShort();
List fontKeys = new ArrayList();
Map fontScaleRules = null;
class MediaRule {
int matchCount;
int bestMatchScore;
String rawKey;
String translatedKey;
}
Map mediaRules = new HashMap();
int defaultFontSizeSetPriority = 0;
for(int iter = 0 ; iter < size ; iter++) {
String key = input.readUTF();
if(key.startsWith("@")) {
theme.put(key, input.readUTF());
if (enableMediaQueries) {
if (key.endsWith("-font-scale")) {
if (fontScaleRules == null) {
fontScaleRules = new LinkedHashMap();
}
fontScaleRules.put(key, Float.parseFloat((String) theme.get(key)));
}
}
if (key.equals("@defaultFontSizeInt") && defaultFontSizeSetPriority < 1) {
int themeMedianFontSize = Integer.parseInt((String) theme.get(key));
if (themeMedianFontSize > 0) {
double adjustedFontSize = themeMedianFontSize * CN.convertToPixels(1f) * 25.4 / (CN.isDesktop() ? 96f : 160f);
Font.setDefaultFont(Font.createTrueTypeFont(Font.NATIVE_MAIN_REGULAR, (float) adjustedFontSize / CN.convertToPixels(1f)));
defaultFontSizeSetPriority = 1;
}
}
if (CN.isTablet() && key.equals("@defaultTabletFontSizeInt") && defaultFontSizeSetPriority < 2) {
int themeMedianFontSize = Integer.parseInt((String) theme.get(key));
if (themeMedianFontSize > 0) {
double adjustedFontSize = themeMedianFontSize * CN.convertToPixels(1f) * 25.4 / (CN.isDesktop() ? 96f : 160f);
Font.setDefaultFont(Font.createTrueTypeFont(Font.NATIVE_MAIN_REGULAR, (float) adjustedFontSize / CN.convertToPixels(1f)));
defaultFontSizeSetPriority = 2;
}
}
if (CN.isDesktop() && key.equals("@defaultDesktopFontSizeInt") && defaultFontSizeSetPriority < 3) {
int themeMedianFontSize = Integer.parseInt((String) theme.get(key));
if (themeMedianFontSize > 0) {
double adjustedFontSize = themeMedianFontSize * CN.convertToPixels(1f) * 25.4 / (CN.isDesktop() ? 96f : 160f);
Font.setDefaultFont(Font.createTrueTypeFont(Font.NATIVE_MAIN_REGULAR, (float) adjustedFontSize / CN.convertToPixels(1f)));
defaultFontSizeSetPriority = 3;
}
}
continue;
}
if (enableMediaQueries) {
String subkey = key;
boolean mediaMatch = true;
int matchCount = 0;
int bestMatchScore = 0;
if (subkey.startsWith("device-")) {
if (!subkey.startsWith(devicePrefix)) {
mediaMatch = false;
} else {
subkey = subkey.substring(devicePrefix.length());
matchCount++;
bestMatchScore = Math.max(50, bestMatchScore);
}
}
if (mediaMatch && subkey.startsWith("platform-")) {
if (!subkey.startsWith(platformPrefix)) {
mediaMatch = false;
} else {
subkey = subkey.substring(platformPrefix.length());
matchCount++;
bestMatchScore = Math.max(100, bestMatchScore);
}
}
if (mediaMatch && subkey.startsWith("density-")) {
if (!subkey.startsWith(densityPrefix)) {
mediaMatch = false;
} else {
subkey = subkey.substring(densityPrefix.length());
matchCount++;
bestMatchScore = Math.max(10, bestMatchScore);
}
}
if (mediaMatch) {
if (mediaRules == null) {
mediaRules = new HashMap();
}
MediaRule rule = mediaRules.get(subkey);
boolean replace = false;
if (rule == null) {
replace = true;
}
if (!replace && rule.matchCount <= matchCount) {
replace = true;
}
if (!replace && rule.bestMatchScore <= bestMatchScore) {
replace = true;
}
if (replace) {
if (rule == null) {
rule = new MediaRule();
mediaRules.put(subkey, rule);
}
rule.bestMatchScore = bestMatchScore;
rule.matchCount = matchCount;
rule.rawKey = key;
rule.translatedKey = subkey;
}
}
}
// if this is a simple numeric value
if(key.endsWith("Color")) {
theme.put(key, Integer.toHexString(input.readInt()));
continue;
}
if(key.endsWith("align") || key.endsWith("textDecoration")) {
theme.put(key, new Integer(input.readShort()));
continue;
}
// if this is a short numeric value for transparency
if(key.endsWith("ransparency")) {
theme.put(key, "" + (input.readByte() & 0xff));
continue;
}
if (key.endsWith("fgAlpha")) {
theme.put(key, (input.readInt() & 0xff));
continue;
}
if(key.endsWith("opacity")) {
theme.put(key, "" + (input.readInt() & 0xff));
continue;
}
if (key.endsWith("elevation")) {
theme.put(key, (input.readInt() & 0xff));
continue;
}
if (key.endsWith("iconGap")) {
theme.put(key, input.readFloat());
continue;
}
if (key.endsWith("iconGapUnit")) {
theme.put(key, input.readByte());
continue;
}
if (key.endsWith("surface")) {
theme.put(key, (input.readBoolean()));
continue;
}
// if this is a padding or margin then we will have the 4 values as bytes
if(key.endsWith("adding") || key.endsWith("argin")) {
if(minorVersion > 7) {
float p1 = input.readFloat();
float p2 = input.readFloat();
float p3 = input.readFloat();
float p4 = input.readFloat();
theme.put(key, "" + p1 + "," + p2 + "," + p3 + "," + p4);
} else {
int p1 = input.readByte() & 0xff;
int p2 = input.readByte() & 0xff;
int p3 = input.readByte() & 0xff;
int p4 = input.readByte() & 0xff;
theme.put(key, "" + p1 + "," + p2 + "," + p3 + "," + p4);
}
continue;
}
// padding and or margin type
if(key.endsWith("Unit")) {
byte p1 = input.readByte();
byte p2 = input.readByte();
byte p3 = input.readByte();
byte p4 = input.readByte();
theme.put(key, new byte[] {p1, p2, p3, p4});
continue;
}
// border
if(key.endsWith("order")) {
int borderType = input.readShort() & 0xffff;
Object b = createBorder(input, borderType);
theme.put(key, b);
continue;
}
// if this is a font
if(key.endsWith("ont")) {
Font f;
// is this a new font?
if(input.readBoolean()) {
String fontId = input.readUTF();
f = (Font)resources.get(fontId);
// if the font is not yet loaded
if(f == null) {
theme.put(key, fontId);
continue;
}
} else {
f = Font.createSystemFont(input.readByte(), input.readByte(), input.readByte());
if(minorVersion > 4) {
boolean hasTTF = input.readBoolean();
if(hasTTF) {
String fileName = input.readUTF();
String fontName = input.readUTF();
int sizeSetting = input.readInt();
float fontSize = input.readFloat();
if(Font.isTrueTypeFileSupported()) {
fontKeys.add(key);
f = createTrueTypeFont(f, fontName, fileName, fontSize, sizeSetting);
}
}
}
}
theme.put(key, f);
continue;
}
// the background property
if(key.endsWith("ackground")) {
int type = input.readByte() & 0xff;
int pos = key.indexOf('.');
if(pos > -1) {
key = key.substring(0, pos);
} else {
key = "";
}
theme.put(key + Style.BACKGROUND_TYPE, new Byte((byte)type));
switch(type) {
// Scaled Image
case 0xF1:
// Tiled Both Image
case MAGIC_INDEXED_IMAGE_LEGACY:
// the image name coupled with the type
theme.put(key + Style.BG_IMAGE, input.readUTF());
break;
// Aligned Image
case 0xf5:
// Tiled Vertically Image
case 0xF2:
// Tiled Horizontally Image
case 0xF3:
// the image name coupled with the type and with alignment information
String imageName = input.readUTF();
theme.put(key + Style.BG_IMAGE, imageName);
byte align = input.readByte();
theme.put(key + Style.BACKGROUND_ALIGNMENT, new Byte(align));
break;
// Horizontal Linear Gradient
case 0xF6:
// Vertical Linear Gradient
case 0xF7:
Float c = new Float(0.5f);
theme.put(key + Style.BACKGROUND_GRADIENT, new Object[] {new Integer(input.readInt()), new Integer(input.readInt()),c, c, new Float(1)});
break;
// Radial Gradient
case 0xF8:
int c1 = input.readInt();
int c2 = input.readInt();
float f1 = input.readFloat();
float f2 = input.readFloat();
float radialSize = 1;
if(minorVersion > 1) {
radialSize = input.readFloat();
}
theme.put(key + Style.BACKGROUND_GRADIENT, new Object[] {new Integer(c1),
new Integer(c2),
new Float(f1),
new Float(f2),
new Float(radialSize)});
break;
}
continue;
}
// if this is a background image bgImage
if(key.endsWith("derive")) {
theme.put(key, input.readUTF());
continue;
}
// if this is a background image bgImage
if(key.endsWith("bgImage")) {
String imageId = input.readUTF();
Image i = getImage(imageId);
// if the font is not yet loaded
if(i == null) {
theme.put(key, imageId);
continue;
}
theme.put(key, i);
continue;
}
if(key.endsWith("scaledImage")) {
if(input.readBoolean()) {
theme.put(key, "true");
} else {
theme.put(key, "false");
}
continue;
}
if(key.endsWith(Style.BACKGROUND_TYPE) || key.endsWith(Style.BACKGROUND_ALIGNMENT)) {
theme.put(key, new Byte(input.readByte()));
continue;
}
if(key.endsWith(Style.BACKGROUND_GRADIENT)) {
if(minorVersion < 2) {
theme.put(key, new Object[] {
new Integer(input.readInt()),
new Integer(input.readInt()),
new Float(input.readFloat()),
new Float(input.readFloat())
});
} else {
theme.put(key, new Object[] {
new Integer(input.readInt()),
new Integer(input.readInt()),
new Float(input.readFloat()),
new Float(input.readFloat()),
new Float(input.readFloat())
});
}
continue;
}
// thow an exception no idea what this is
throw new IOException("Error while trying to read theme property: " + key);
}
if (enableMediaQueries) {
if (mediaRules != null && !mediaRules.isEmpty()) {
for (MediaRule rule : mediaRules.values()) {
theme.put(rule.translatedKey, theme.get(rule.rawKey));
}
}
if (fontScaleRules != null && !fontKeys.isEmpty()) {
float scale = 1f;
for (Map.Entry rule : fontScaleRules.entrySet()) {
String key = rule.getKey();
String skey = key.substring(1);
if (skey.startsWith("device-")) {
if (skey.startsWith(devicePrefix)) {
skey = skey.substring(devicePrefix.length());
} else {
continue;
}
}
if (skey.startsWith("platform-")) {
if (skey.startsWith(platformPrefix)) {
skey = skey.substring(platformPrefix.length());
} else {
continue;
}
}
if (skey.startsWith("density-")) {
if (skey.startsWith(densityPrefix)) {
skey = skey.substring(densityPrefix.length());
} else {
continue;
}
}
if ("font-scale".equals(skey)) {
scale *= rule.getValue();
}
}
if (Math.abs(scale-1f) > 0.01) {
for (String fontKey : fontKeys) {
Font f = (Font) theme.get(fontKey);
if (f != null && f.isTTFNativeFont()) {
try {
f = f.derive(f.getPixelSize() * scale, f.getStyle());
theme.put(fontKey, f);
} catch (Exception ex) {
Log.p("Failed to derive font " + f + " while loading font key " + fontKey + " from resource file. " + ex.getMessage());
Log.e(ex);
}
}
}
}
}
}
return theme;
}
private Object createBorder(DataInputStream input, int type) throws IOException {
switch(type) {
// empty border
case 0xff01:
return Border.getEmpty();
// Line border
case 0xff02:
// use theme colors?
if(minorVersion > 8) {
if(input.readBoolean()) {
if(input.readBoolean()) {
return Border.createLineBorder(input.readFloat());
}
return Border.createLineBorder((int)input.readFloat());
} else {
if(input.readBoolean()) {
return Border.createLineBorder(input.readFloat(), input.readInt());
}
return Border.createLineBorder((int)input.readFloat(), input.readInt());
}
}
if(input.readBoolean()) {
return Border.createLineBorder(input.readByte());
} else {
return Border.createLineBorder(input.readByte(), input.readInt());
}
// Underline border
case 0xff14:
// use theme colors?
if(input.readBoolean()) {
if(input.readBoolean()) {
return Border.createUndelineBorder(input.readFloat());
}
return Border.createUndelineBorder((int)input.readFloat());
} else {
if(input.readBoolean()) {
return Border.createUnderlineBorder(input.readFloat(), input.readInt());
}
return Border.createUnderlineBorder((int)input.readFloat(), input.readInt());
}
// Rounded border
case 0xff03:
// use theme colors?
if(input.readBoolean()) {
return Border.createRoundBorder(input.readByte(), input.readByte());
} else {
return Border.createRoundBorder(input.readByte(), input.readByte(), input.readInt());
}
// Etched Lowered border
case 0xff04:
// use theme colors?
if(input.readBoolean()) {
return Border.createEtchedLowered();
} else {
return Border.createEtchedLowered(input.readInt(), input.readInt());
}
// Etched raised border
case 0xff05:
// use theme colors?
if(input.readBoolean()) {
return Border.createEtchedRaised();
} else {
return Border.createEtchedRaised(input.readInt(), input.readInt());
}
// Bevel raised
case 0xff07:
// use theme colors?
if(input.readBoolean()) {
return Border.createBevelRaised();
} else {
return Border.createBevelRaised(input.readInt(), input.readInt(), input.readInt(), input.readInt());
}
// Bevel lowered
case 0xff06:
// use theme colors?
if(input.readBoolean()) {
return Border.createBevelLowered();
} else {
return Border.createBevelLowered(input.readInt(), input.readInt(), input.readInt(), input.readInt());
}
// Image border
case 0xff08:
Object[] imageBorder = readImageBorder(input);
return imageBorder;
// horizontal Image border
case 0xff09:
return readImageBorder(input, "h");
// vertical Image border
case 0xff10:
return readImageBorder(input, "v");
// scaled Image border
case 0xff11:
return readScaledImageBorder(input);
// round border
case 0xff12:
return RoundBorder.create().
rectangle(input.readBoolean()).
color(input.readInt()).
opacity(input.readInt()).
stroke(input.readFloat(), input.readBoolean()).
strokeColor(input.readInt()).
strokeOpacity(input.readInt()).
shadowBlur(input.readFloat()).
shadowOpacity(input.readInt()).
shadowSpread(input.readInt(), input.readBoolean()).
shadowX(input.readFloat()).
shadowY(input.readFloat());
// round rect border
case 0xff13:
RoundRectBorder out = RoundRectBorder.create().
stroke(input.readFloat(), input.readBoolean()).
strokeColor(input.readInt()).
strokeOpacity(input.readInt()).
shadowBlur(input.readFloat()).
shadowOpacity(input.readInt()).
shadowSpread(input.readFloat()).
shadowX(input.readFloat()).
shadowY(input.readFloat()).
cornerRadius(input.readFloat()).
bezierCorners(input.readBoolean());
if (input.readBoolean()) {
out.topOnlyMode(true);
}
if (input.readBoolean()) {
out.bottomOnlyMode(true);
}
return out;
//topOnlyMode(input.readBoolean()).
//bottomOnlyMode(input.readBoolean());
// round rect border with top-left, top-right, bottom-right, bottom-left corners
// specified independently
case 0xff15:
return RoundRectBorder.create().
stroke(input.readFloat(), input.readBoolean()).
strokeColor(input.readInt()).
strokeOpacity(input.readInt()).
shadowBlur(input.readFloat()).
shadowOpacity(input.readInt()).
shadowSpread(input.readFloat()).
shadowX(input.readFloat()).
shadowY(input.readFloat()).
cornerRadius(input.readFloat()).
bezierCorners(input.readBoolean()).
topLeftMode(input.readBoolean()).
topRightMode(input.readBoolean()).
bottomRightMode(input.readBoolean()).
bottomLeftMode(input.readBoolean());
case 0xff16:
// CSS border
String cssStyles = input.readUTF();
try {
return new CSSBorder(this, cssStyles);
} catch (Throwable t) {
Log.p("Failed to load CSS border: "+cssStyles);
Log.e(t);
return Border.createEmpty();
}
}
return null;
}
private String[] readImageBorder(DataInputStream input, String orientation) throws IOException {
String[] imageBorder = new String[4];
imageBorder[0] = orientation;
for(int iter = 1 ; iter < 4 ; iter++) {
imageBorder[iter] = input.readUTF();
}
return imageBorder;
}
private String[] readScaledImageBorder(DataInputStream input) throws IOException {
String[] a = readImageBorder(input);
String[] b = new String[a.length + 1];
System.arraycopy(a, 0, b, 1, a.length);
b[0] = "s";
return b;
}
private String[] readImageBorder(DataInputStream input) throws IOException {
// Read number of images can be 2, 3, 8 or 9
int size = input.readByte();
String[] imageBorder = new String[size];
for(int iter = 0 ; iter < size ; iter++) {
imageBorder[iter] = input.readUTF();
}
return imageBorder;
}
private Hashtable loadL10N() throws IOException {
Hashtable> l10n = new Hashtable>();
int keys = input.readShort();
int languages = input.readShort();
String[] keyArray = new String[keys];
for(int iter = 0 ; iter < keys ; iter++) {
String key = input.readUTF();
keyArray[iter] = key;
}
for(int iter = 0 ; iter < languages ; iter++) {
Hashtable currentLanguage = new Hashtable();
String lang = input.readUTF();
l10n.put(lang, currentLanguage);
for(int valueIter = 0 ; valueIter < keys ; valueIter++) {
currentLanguage.put(keyArray[valueIter], input.readUTF());
}
}
return l10n;
}
/**
* Creates a packed image from the input stream for an 8 bit packed image
*/
private Image createPackedImage8() throws IOException {
// read the length of the palette;
int size = input.readByte() & 0xff;
// 0 means the last bit overflowed, there is no sense for 0 sized palette
if(size == 0) {
size = 256;
}
int[] palette = new int[size];
int plen = palette.length;
for(int iter = 0 ; iter < plen ; iter++) {
palette[iter] = input.readInt();
}
int width = input.readShort();
int height = input.readShort();
byte[] data = new byte[width * height];
input.readFully(data, 0, data.length);
return Image.createIndexed(width, height, palette, data);
}
/**
* Gets the system resource which can be located /CN1Images.res.
*
* @return a Resources object which contains the system resources
*/
public static Resources getSystemResource(){
try {
return open(systemResourceLocation);
} catch (IOException ex) {
Log.e(ex);
}
return null;
}
/**
* Global resources are used by new GUI builder apps to keep track of the applications resources
*
* @param res the resource object used by default in the GUI builder forms
*/
public static void setGlobalResources(Resources res) {
globalResources = res;
}
/**
* Global resources are used by new GUI builder apps to keep track of the applications resources
*
* @return the resource object used by default in the GUI builder forms
*/
public static Resources getGlobalResources() {
return globalResources;
}
}