/** * */ package org.commcare.android.adapters; import java.util.Hashtable; import java.util.Vector; import org.commcare.android.javarosa.AndroidLogger; import org.commcare.android.models.AndroidSessionWrapper; import org.commcare.android.util.CommCareInstanceInitializer; import org.commcare.android.view.TextImageAudioView; import org.commcare.dalvik.application.CommCareApplication; import org.commcare.suite.model.Entry; import org.commcare.suite.model.Menu; import org.commcare.suite.model.Suite; import org.commcare.util.CommCarePlatform; import org.javarosa.core.model.condition.EvaluationContext; import org.javarosa.core.services.Logger; import org.javarosa.core.services.locale.Localization; import org.javarosa.core.services.locale.Localizer; import org.javarosa.xpath.XPathException; import org.javarosa.xpath.XPathTypeMismatchException; import org.javarosa.xpath.expr.XPathExpression; import org.javarosa.xpath.expr.XPathFuncExpr; import org.javarosa.xpath.parser.XPathSyntaxException; import android.content.Context; import android.database.DataSetObserver; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; /** * Adapter class to handle both Menu and Entry items * @author wspride * */ public class GenericMenuListAdapter implements ListAdapter { private AndroidSessionWrapper asw; private CommCarePlatform platform; private Context context; private Object[] objectData; private String menuTitle = null; public GenericMenuListAdapter(Context context, CommCarePlatform platform, String menuID){ this.platform = platform; this.context = context; Vector<Object> items = new Vector<Object>(); Hashtable<String, Entry> map = platform.getMenuMap(); asw = CommCareApplication._().getCurrentSessionWrapper(); for(Suite s : platform.getInstalledSuites()) { for(Menu m : s.getMenus()) { if(m.getId().equals(menuID)) { if(menuTitle == null) { //TODO: Do I need args, here? try { menuTitle = m.getName().evaluate(); }catch(Exception e) { e.printStackTrace(); } } for(String command : m.getCommandIds()) { try { XPathExpression mRelevantCondition = m.getRelevantCondition(m.indexOfCommand(command)); if(mRelevantCondition != null) { EvaluationContext mEC = asw.getEvaluationContext(); Object ret = mRelevantCondition.eval(mEC); try { if(!XPathFuncExpr.toBoolean(ret)) { continue; } } catch(XPathTypeMismatchException e) { Logger.log(AndroidLogger.TYPE_ERROR_CONFIG_STRUCTURE, "relevancy condition for menu item returned non-boolean value : " + ret); throw new RuntimeException("relevancy condition for menu item returned non-boolean value : " + ret); } if(!XPathFuncExpr.toBoolean(ret)) { continue;} } Entry e = map.get(command); if(e.getXFormNamespace() == null) { //If this is a "view", not an "entry" //we only want to display it if all of its //datums are not already present if(asw.getSession().getNeededDatum(e) == null) { continue; } } items.add(e); } catch(XPathSyntaxException xpse) { String xpathExpression = m.getRelevantConditionRaw(m.indexOfCommand(command)); CommCareApplication._().triggerHandledAppExit(context, Localization.get("app.menu.display.cond.bad.xpath", new String[] {xpathExpression, xpse.getMessage()})); objectData = new Object[0]; return; } catch(XPathException xpe) { String xpathExpression = m.getRelevantConditionRaw(m.indexOfCommand(command)); CommCareApplication._().triggerHandledAppExit(context, Localization.get("app.menu.display.cond.xpath.err", new String[] {xpathExpression, xpe.getMessage()})); objectData = new Object[0]; return; } } continue; } if(menuID.equals(m.getRoot())){ //make sure we didn't already add this ID boolean idExists = false; for(Object o : items) { if(o instanceof Menu) { if(((Menu)o).getId().equals(m.getId())){ idExists = true; break; } } } if(!idExists) { items.add(m); } } } } objectData = new Object[items.size()]; items.copyInto(objectData); } public String getMenuTitle() { return menuTitle; } /* (non-Javadoc) * @see android.widget.ListAdapter#areAllItemsEnabled() */ public boolean areAllItemsEnabled() { return true; } /* (non-Javadoc) * @see android.widget.ListAdapter#isEnabled(int) */ public boolean isEnabled(int arg0) { return true; } /* (non-Javadoc) * @see android.widget.Adapter#getCount() */ public int getCount() { return (objectData.length); } /* (non-Javadoc) * @see android.widget.Adapter#getItem(int) */ public Object getItem(int i) { return objectData[i]; } /* (non-Javadoc) * @see android.widget.Adapter#getItemId(int) */ public long getItemId(int i) { Object tempItem = objectData[i]; if(tempItem instanceof Menu){ return ((Menu)tempItem).getId().hashCode(); } else{ return ((Entry)tempItem).getCommandId().hashCode(); } } /* * (non-Javadoc) * @see android.widget.Adapter#getItemViewType(int) */ public int getItemViewType(int i) { return 0; } /* (non-Javadoc) * @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup) */ public View getView(int i, View v, ViewGroup vg) { Object mObject = objectData[i]; TextImageAudioView emv = (TextImageAudioView)v; String mQuestionText = textViewHelper(mObject); if(emv == null) { emv = new TextImageAudioView(context); } //Final change, remove any numeric context requests. J2ME uses these to //help with numeric navigation. if(mQuestionText != null) { mQuestionText = Localizer.processArguments(mQuestionText, new String[] {""}).trim(); } emv.setAVT(mQuestionText, getAudioURI(mObject), getImageURI(mObject)); return emv; } /* * Helpers to make the getView call Entry/Menu agnostic */ public String getAudioURI(Object e){ if(e instanceof Menu){ return ((Menu)e).getAudioURI(); } return ((Entry)e).getAudioURI(); } public String getImageURI(Object e){ if(e instanceof Menu){ return ((Menu)e).getImageURI(); } return ((Entry)e).getImageURI(); } /* * Helper to build the TextView for the TextImageAudioView constructor */ public String textViewHelper(Object e){ String displayText; if(e instanceof Menu){ displayText = ((Menu)e).getName().evaluate(); } else{ displayText = ((Entry)e).getText().evaluate(); } //mQuestionText.setTypeface(null, Typeface.NORMAL); //mQuestionText.setPadding(0, 0, 0, 7); //mQuestionText.setId((int)Math.random()*100000000); // assign random id //mQuestionText.setHorizontallyScrolling(false); return displayText; } /* (non-Javadoc) * @see android.widget.Adapter#getViewTypeCount() */ public int getViewTypeCount() { return 1; } /* (non-Javadoc) * @see android.widget.Adapter#hasStableIds() */ public boolean hasStableIds() { return true; } /* (non-Javadoc) * @see android.widget.Adapter#isEmpty() */ public boolean isEmpty() { return false; } /* (non-Javadoc) * @see android.widget.Adapter#registerDataSetObserver(android.database.DataSetObserver) */ public void registerDataSetObserver(DataSetObserver arg0) { } /* (non-Javadoc) * @see android.widget.Adapter#unregisterDataSetObserver(android.database.DataSetObserver) */ public void unregisterDataSetObserver(DataSetObserver arg0) { } }