/*
* Copyright (c) 2004-2009 XMLVM --- An XML-based Programming Language
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 675 Mass
* Ave, Cambridge, MA 02139, USA.
*
* For more information, visit the XMLVM Home Page at http://www.xmlvm.org
*/
package android.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xmlvm.iphone.NSBundle;
import org.xmlvm.iphone.NSData;
import org.xmlvm.iphone.NSXMLParser;
import org.xmlvm.iphone.NSXMLParserDelegate;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
import android.view.InflateException;
class DrawableParser extends NSXMLParserDelegate {
private static final int UNKNOWN_DRAWABLE = 0;
private static final int STATELIST_DRAWABLE = 1;
private static final int GRADIENT_DRAWABLE = 2;
private Context context;
private String prefix;
private Drawable drawable;
private int drawableType = UNKNOWN_DRAWABLE;
public DrawableParser(Context context) {
this.context = context;
}
@Override
public void didStartMappingPrefix(NSXMLParser parser, String prefix, String namespaceURI) {
if (namespaceURI.equals("http://schemas.android.com/apk/res/android")) {
this.prefix = prefix + ":";
}
}
@Override
public void didStartElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName, Map<String, String> attributes) {
AttributeSet attrs = new ResourceAttributes(context, prefix, attributes);
if (qualifiedName.equals("selector")) {
drawable = StateListDrawable.xmlvmCreateStateListDrawable(attrs);
drawableType = STATELIST_DRAWABLE;
} else if (qualifiedName.equals("shape")) {
drawable = GradientDrawable.xmlvmCreateGradientDrawable(attrs);
drawableType = GRADIENT_DRAWABLE;
} else {
switch (drawableType) {
case STATELIST_DRAWABLE:
didStartStateListDrawableElement(qualifiedName, attrs);
break;
case GRADIENT_DRAWABLE:
didStartGradientDrawableElement(qualifiedName, attrs);
}
}
}
@Override
public void didEndElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName) {
}
private void didStartStateListDrawableElement(String elementName, AttributeSet attrs) {
if (elementName.equals("item")) {
processStateListItem(attrs);
} else {
throw new InflateException("Element not valid for StateListDrawable: " + elementName);
}
}
private void didStartGradientDrawableElement(String elementName, AttributeSet attrs) {
// TODO: Implement parsing the various gradient elements
if (elementName.equals("solid")) {
int color = attrs.getAttributeIntValue(null, "color", 0);
((GradientDrawable) drawable).setColor(color);
} else if (elementName.equals("padding")) {
int left = Dimension.resolveDimension(attrs.getAttributeValue(null, "left"));
left = left < 0 ? 0 : left;
int top = Dimension.resolveDimension(attrs.getAttributeValue(null, "top"));
top = top < 0 ? 0 : top;
int right = Dimension.resolveDimension(attrs.getAttributeValue(null, "right"));
right = right < 0 ? 0 : right;
int bottom = Dimension.resolveDimension(attrs.getAttributeValue(null, "bottom"));
bottom = bottom < 0 ? 0 : bottom;
((GradientDrawable) drawable).xmlvmSetPadding(left, top, right, bottom);
}
}
private void processStateListItem(AttributeSet attrs) {
List<Integer> states = new ArrayList<Integer>();
boolean b = attrs.getAttributeBooleanValue(null, State.STATE_PRESSED_NAME, false);
if (b) {
states.add(new Integer(State.STATE_PRESSED_ID));
}
b = attrs.getAttributeBooleanValue(null, State.STATE_CHECKED_NAME, false);
if (b) {
states.add(new Integer(State.STATE_CHECKED_ID));
}
int drawableId = attrs.getAttributeResourceValue(null, "drawable", -1);
Drawable d = context.getResources().getDrawable(drawableId);
int stateArray[] = new int[states.size()];
for (int i = 0; i < states.size(); i++) {
stateArray[i] = states.get(i).intValue();
}
((StateListDrawable) drawable).xmlvmAddState(stateArray, d);
}
Drawable getDrawable() {
return drawable;
}
}
class StringsParser extends NSXMLParserDelegate {
private Context context;
private String prefix;
private Map<String, Integer> nameToIdMap;
private Map<Integer, String> stringMap;
private Integer currentId;
private StringBuffer currentValue;
public StringsParser(Context context, Map<String, Integer> nameToIdMap) {
this.context = context;
this.nameToIdMap = nameToIdMap;
stringMap = new HashMap<Integer, String>();
}
@Override
public void didStartMappingPrefix(NSXMLParser parser, String prefix, String namespaceURI) {
if (namespaceURI.equals("http://schemas.android.com/apk/res/android")) {
this.prefix = prefix + ":";
}
}
@Override
public void didStartElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName, Map<String, String> attributes) {
AttributeSet attrs = new ResourceAttributes(context, prefix, attributes);
if (qualifiedName.equals("string")) {
currentValue = new StringBuffer();
String name = attrs.getAttributeValue("", "name");
currentId = nameToIdMap.get("string/" + name);
}
}
@Override
public void didEndElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName) {
if (qualifiedName.equals("string")) {
stringMap.put(currentId, currentValue.toString());
currentId = null;
}
}
@Override
public void foundCharacters(NSXMLParser parser, String characters) {
if (currentId != null) {
currentValue.append(characters);
}
}
Map<Integer, String> getStringMap() {
return stringMap;
}
}
class StringArraysParser extends NSXMLParserDelegate {
private Context context;
private String prefix;
private Map<String, Integer> nameToIdMap;
private Map<Integer, String[]> stringMap;
private Integer currentId;
private StringBuffer[] currentValue;
private int currentIdx;
private boolean inItem;
public StringArraysParser(Context context, Map<String, Integer> nameToIdMap) {
this.context = context;
this.nameToIdMap = nameToIdMap;
stringMap = new HashMap<Integer, String[]>();
inItem = false;
}
@Override
public void didStartMappingPrefix(NSXMLParser parser, String prefix, String namespaceURI) {
if (namespaceURI.equals("http://schemas.android.com/apk/res/android")) {
this.prefix = prefix + ":";
}
}
@Override
public void didStartElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName, Map<String, String> attributes) {
AttributeSet attrs = new ResourceAttributes(context, prefix, attributes);
// System.out.println("StartEl="+qualifiedName);
if (qualifiedName.equals("string-array")) {
String name = attrs.getAttributeValue("", "name");
currentId = nameToIdMap.get("array/" + name);
// if (currentId==null) { System.out.println("cId=null"); } else {
// System.out.println("cId="+currentId); }
currentIdx = -1;
currentValue = new StringBuffer[100]; // TODO: at most 100 values
// for array
} else if (qualifiedName.equals("item")) {
currentIdx++;
inItem = true;
currentValue[currentIdx] = new StringBuffer();
}
}
@Override
public void didEndElement(NSXMLParser parser, String elementName, String namespaceURI,
String qualifiedName) {
// System.out.println("EndEl="+qualifiedName);
if (currentId != null && qualifiedName.equals("string-array")) {
// System.out.println("Storing "+currentId);
String[] cV = new String[currentIdx + 1];
for (int i = 0; i <= currentIdx; i++) {
cV[i] = currentValue[i].toString();
}
stringMap.put(currentId, cV);
currentId = null;
} else if (currentId != null && currentIdx >= 0 && qualifiedName.equals("item")) {
// System.out.println("currentIdx="+currentIdx);
inItem = false;
}
}
@Override
public void foundCharacters(NSXMLParser parser, String characters) {
// System.out.println("chars");
if (currentId != null && currentIdx >= 0 && inItem) {
// System.out.println("Adding "+characters+" to "+currentId+"/#"+currentIdx);
currentValue[currentIdx].append(characters);
}
}
Map<Integer, String[]> getStringMap() {
return stringMap;
}
}
public class ResourceParser {
public static Drawable parseDrawable(Context context, String fileName) {
String resourceName = getResourceName(fileName);
String resourceDir = getResourceDirectory(fileName);
String filePath = NSBundle.mainBundle().pathForResource(resourceName, "xml", resourceDir);
NSData content = NSData.dataWithContentsOfFile(filePath);
DrawableParser delegate = new DrawableParser(context);
NSXMLParser xmlParser = createParser(context, content, delegate);
boolean success = xmlParser.parse();
if (!success) {
throw new InflateException("Unable to inflate drawable resource: " + fileName + ".xml");
}
return delegate.getDrawable();
}
public static Map<Integer, String> parseStrings(Context context, String fileName,
Map<String, Integer> nameToIdMap) {
String resourceName = getResourceName(fileName);
String resourceDir = getResourceDirectory(fileName);
String filePath = NSBundle.mainBundle().pathForResource(resourceName, "xml", resourceDir);
NSData content = NSData.dataWithContentsOfFile(filePath);
StringsParser delegate = new StringsParser(context, nameToIdMap);
NSXMLParser xmlParser = createParser(context, content, delegate);
boolean success = xmlParser.parse();
if (!success) {
throw new InflateException("Unable to inflate string resources: " + fileName + ".xml");
}
return delegate.getStringMap();
}
public static Map<Integer, String[]> parseStringArrays(Context context, String fileName,
Map<String, Integer> nameToIdMap) {
String resourceName = getResourceName(fileName);
String resourceDir = getResourceDirectory(fileName);
String filePath = NSBundle.mainBundle().pathForResource(resourceName, "xml", resourceDir);
NSData content = NSData.dataWithContentsOfFile(filePath);
StringArraysParser delegate = new StringArraysParser(context, nameToIdMap);
NSXMLParser xmlParser = createParser(context, content, delegate);
boolean success = xmlParser.parse();
if (!success) {
throw new InflateException("Unable to inflate string resources: " + fileName + ".xml");
}
return delegate.getStringMap();
}
private static NSXMLParser createParser(Context context, NSData content,
NSXMLParserDelegate delegate) {
NSXMLParser xmlParser = new NSXMLParser(content);
xmlParser.setShouldProcessNamespaces(true);
xmlParser.setShouldReportNamespacePrefixes(true);
xmlParser.setDelegate(delegate);
return xmlParser;
}
private static String getResourceName(String resourcePath) {
int i = resourcePath.lastIndexOf('/');
return i >= 0 ? resourcePath.substring(i + 1) : resourcePath;
}
private static String getResourceDirectory(String resourcePath) {
int i = resourcePath.lastIndexOf('/');
return i >= 0 ? resourcePath.substring(0, i) : null;
}
}