package org.robobinding.binder;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.robobinding.PendingAttributesForView;
import org.robobinding.PendingAttributesForViewImpl;
import org.robobinding.util.Lists;
import org.robobinding.widget.menuitemgroup.MenuItemGroup;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
/**
*
* @since 1.0
* @version $Revision: 1.0 $
* @author Cheng Wei
*/
public class BindingMenuInflater {
private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
private static final int NO_ID = 0;
private static final String XML_GROUP = "group";
private static final String XML_ITEM = "item";
private static final String XML_MENU = "menu";
private final Context context;
private final Menu menu;
private final MenuInflater inflater;
private final BindingAttributeParser bindingAttributeParser;
private final BindingAttributeResolver bindingAttributeResolver;
public BindingMenuInflater(Context context, Menu menu, MenuInflater inflater, BindingAttributeParser bindingAttributeParser,
BindingAttributeResolver bindingAttributeResolver) {
this.context = context;
this.menu = menu;
this.inflater = inflater;
this.bindingAttributeParser = bindingAttributeParser;
this.bindingAttributeResolver = bindingAttributeResolver;
}
public InflatedView inflate(int menuRes) {
inflater.inflate(menuRes, menu);
try {
return new BindingInflater(menuRes).inflate();
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private class BindingInflater {
private final XmlResourceParser parser;
private final AttributeSet attrs;
private final ViewHierarchyInflationErrorsException errors;
private final List<ResolvedBindingAttributesForView> resolvedBindingAttributesForChildViews;
public BindingInflater(int menuRes) {
parser = context.getResources().getLayout(menuRes);
attrs = Xml.asAttributeSet(parser);
errors = new ViewHierarchyInflationErrorsException();
resolvedBindingAttributesForChildViews = Lists.newArrayList();
}
public InflatedView inflate() throws XmlPullParserException, IOException {
int eventType = parser.next();
boolean reachedEndOfMenu = false;
String tagName;
while (!reachedEndOfMenu) {
switch (eventType) {
case XmlPullParser.START_TAG:
tagName = parser.getName();
if (tagName.equals(XML_GROUP)) {
resolveAndAddGroup(attrs);
} else if (tagName.equals(XML_ITEM)) {
resolveAndAddItem(attrs);
}
break;
case XmlPullParser.END_TAG:
tagName = parser.getName();
if (tagName.equals(XML_MENU)) {
reachedEndOfMenu = true;
}
break;
default:
break;
}
eventType = parser.next();
}
return new InflatedView(resolvedBindingAttributesForChildViews, errors);
}
private void resolveAndAddGroup(AttributeSet attrs) {
Map<String, String> bindingAttributes = bindingAttributeParser.parse(attrs);
if (!bindingAttributes.isEmpty()) {
int groupId = readId();
MenuItemGroup group = new MenuItemGroup(menu, groupId);
resolveAndAdd(new PendingAttributesForViewImpl(group, bindingAttributes));
}
}
private int readId() {
int id = parser.getAttributeResourceValue(ANDROID_NAMESPACE, "id", NO_ID);
if (NO_ID == id) {
String tagName = parser.getName();
throw new RuntimeException("android:id is required for menu '" + tagName + "' when apply binding");
}
return id;
}
private void resolveAndAdd(PendingAttributesForView pendingAttributesForView) {
ViewResolutionResult viewResolutionResult = bindingAttributeResolver.resolve(pendingAttributesForView);
viewResolutionResult.addPotentialErrorTo(errors);
resolvedBindingAttributesForChildViews.add(viewResolutionResult.getResolvedBindingAttributes());
}
private void resolveAndAddItem(AttributeSet attrs) {
Map<String, String> bindingAttributes = bindingAttributeParser.parse(attrs);
if (!bindingAttributes.isEmpty()) {
int itemId = readId();
MenuItem menuItem = menu.findItem(itemId);
resolveAndAdd(new PendingAttributesForViewImpl(menuItem, bindingAttributes));
}
}
}
}