package com.github.florent37.carpaccio; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.github.florent37.carpaccio.mapping.MappingManager; import com.github.florent37.carpaccio.model.CarpaccioAction; import com.github.florent37.carpaccio.model.ObjectAndMethod; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by florentchampigny on 24/07/15. */ public class CarpaccioManager implements MappingManager.MappingManagerCallback { public static class CarpaccioException extends NullPointerException { public CarpaccioException(String detailMessage) { super(detailMessage); } public CarpaccioException() { } } protected boolean displayErrors = false; private static final String TAG = "CarpaccioManager"; protected List<View> carpaccioViews = new ArrayList<>(); protected Map<String, Object> registerAdapters = new HashMap<>(); protected List<Object> registerControllers = new ArrayList<>(); protected MappingManager mappingManager; protected Map<String, ObjectAndMethod> savedControllers = new HashMap<>(); public CarpaccioManager(MappingManager mappingManager) { this.mappingManager = mappingManager; this.mappingManager.setMappingManagerCallback(this); } public void addView(View view) { carpaccioViews.add(view); } public boolean isCarpaccioControlledView(View view) { if (view.getTag() != null) { String tag = view.getTag().toString(); return !tag.isEmpty() && tag.contains("(") && tag.contains(")"); //TODO use matcher } else if (view instanceof TextView && ((TextView) view).getText() != null) { String text = ((TextView) view).getText().toString(); return !text.isEmpty() && text.trim().startsWith("$"); } else return false; } public void registerController(Object controller) { if (controller != null) registerControllers.add(controller); } public void registerControllers(Context context, String registerString) { String[] registers = registerString.split(";"); for (String s : registers) { String reg = s.trim().replace(";", ""); if (!reg.isEmpty()) { Object controller = CarpaccioHelper.construct(reg); if (controller == null) controller = CarpaccioHelper.construct("com.github.florent37.carpaccio.controllers." + reg); if (controller == null && context != null) controller = CarpaccioHelper.construct(context.getPackageName() +"." + reg); if (controller != null) registerController(controller); else { CarpaccioLogger.d(TAG, "cannot find controller " + reg); if(displayErrors) throw new CarpaccioException("cannot find controller " + reg); } } } CarpaccioLogger.d(TAG, "registered controllers = " + savedControllers.toString()); } public void executeActionsOnViews() { executeActionsOnViews(carpaccioViews, null); } public void executeActionsOnViews(List<View> views, Object mappedObject) { for (View view : views) { executeActionsOnView(view, mappedObject); } } public void executeActionsOnView(View view) { executeActionsOnView(view, null); } public void executeActionsOnView(View view, Object mappedObject) { if (view.getTag() != null) { List<CarpaccioAction> actions; if (view.getTag() instanceof List) { //if already splitted actions = (List<CarpaccioAction>) view.getTag(); } else { //only do this work the first time actions = new ArrayList<>(); String tag = view.getTag().toString().trim(); String[] tagCalls = CarpaccioHelper.trim(tag.split(";")); for (String call : tagCalls) { if (!call.startsWith("//")) { //skip the "//function(args)" CarpaccioAction carpaccioAction = new CarpaccioAction(call); actions.add(carpaccioAction); } } view.setTag(actions); //save into view tags, replace the string with the list } CarpaccioLogger.d(TAG, view.getClass().getName() + " has actions " + actions); if (actions != null) for (CarpaccioAction action : actions) { //if it's a mapped function ex: setText($user) if (mappingManager != null && action.isCallMapping()) { mappingManager.callMappingOnView(action, view, mappedObject); if (Carpaccio.IN_EDIT_MODE) { try { callActionOnView(action, view); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } } } else //an usual function setText(florent) callActionOnView(action, view); } } if (view instanceof TextView && ((TextView) view).getText() != null) { String text = ((TextView) view).getText().toString().trim(); if (text.startsWith("$")) { if (mappingManager != null) { String textAction = "setText(" + text + ")"; CarpaccioAction carpaccioAction = new CarpaccioAction(textAction); if (view.getTag() != null) { if (view.getTag() instanceof String) view.setTag(view.getTag() + ";" + textAction); else if (view.getTag() instanceof List) { ((List) view.getTag()).add(carpaccioAction); } } else { List<CarpaccioAction> actions = new ArrayList<>(); actions.add(carpaccioAction); view.setTag(actions); } mappingManager.callMappingOnView(carpaccioAction, view, null); } } } } public void callActionOnView(CarpaccioAction action, View view) { //find the controller for this call ObjectAndMethod objectAndMethod = action.getObjectAndMethod(); if (objectAndMethod == null) { //check if cached it String key = action.getFunction() + (action.getArgs().length + 1); objectAndMethod = savedControllers.get(key); if (objectAndMethod == null) { //if not cached, objectAndMethod = CarpaccioHelper.findObjectWithThisMethod(this.registerControllers, action.getFunction(), action.getArgs().length + 1); //+1 for the view if (objectAndMethod != null) { CarpaccioLogger.d(TAG, objectAndMethod.getObject() + " used for " + action.getCompleteCall()); } else { CarpaccioLogger.e(TAG, "cannot find any controller for " + action.getCompleteCall()); if(displayErrors) throw new CarpaccioException("cannot find any controller for " + action.getCompleteCall()); } savedControllers.put(key, objectAndMethod); } action.setObjectAndMethod(objectAndMethod); } if (objectAndMethod != null) { //call ! CarpaccioHelper.callMethod(action.getObjectAndMethod().getObject(), action.getObjectAndMethod().getMethod(), action.getFunction(), view, action.getValues()); } } public void mapObject(String name, Object object) { if (mappingManager != null) mappingManager.mapObject(name, object); } public Object getMappedObject(String name) { if (mappingManager != null) return mappingManager.getMappedObject(name); else return null; } //region mapList protected Map<View, List<View>> carpaccioSubViews = new HashMap<>(); public void mapList(String mappedName, List list) { if (mappingManager != null) { mappingManager.mapList(mappedName, list); notifyAdapterDataSetChanded(registerAdapters.get(mappedName)); } } public void appendList(String mappedName, List list) { if (mappingManager != null) { mappingManager.appendList(mappedName, list); notifyAdapterDataSetChanded(registerAdapters.get(mappedName)); } } public List getMappedList(String name) { if (mappingManager != null) return mappingManager.getMappedList(name); return null; } public Object registerAdapter(String mapName, Object adapter) { if (adapter instanceof RecyclerView.Adapter || adapter instanceof BaseAdapter) { if (!registerAdapters.containsKey(mapName)) { this.registerAdapters.put(mapName, adapter); return adapter; } else { return this.registerAdapters.get(mapName); } } return null; } public <T> T getAdapter(String mappedName) { return (T) this.registerAdapters.get(mappedName); } public void addChildViews(View view) { if (mappingManager != null) { List<View> subViews = carpaccioSubViews.get(view); if (subViews == null) { subViews = new ArrayList<>(); carpaccioSubViews.put(view, subViews); } findCarpaccioControlledViews(view, subViews); } } public Object bindView(View view, String mapName, int position) { if (mappingManager != null) { List<View> subViews = carpaccioSubViews.get(view); if (subViews != null) { Object mappedObject = mappingManager.getMappedListsObject(mapName, position); CarpaccioLogger.d(TAG, "bindView " + mapName + " position=" + position + " object=" + mappedObject); executeActionsOnViews(subViews, mappedObject); return mappedObject; } } return null; } public Object bindView(View view, String mapName) { if (mappingManager != null) { List<View> subViews = carpaccioSubViews.get(view); if (subViews != null) { Object mappedObject = mappingManager.getMappedObject(mapName); CarpaccioLogger.d(TAG, "bindView " + mapName + " object=" + mappedObject); executeActionsOnViews(subViews, mappedObject); return mappedObject; } } return null; } public void notifyAdapterDataSetChanded(Object adapter) { if (adapter != null) { if (adapter instanceof RecyclerView.Adapter) { try { ((RecyclerView.Adapter) adapter).notifyDataSetChanged(); } catch (Exception e) { CarpaccioLogger.e(TAG, e.getMessage(), e); } } else if (adapter instanceof BaseAdapter) { try { ((BaseAdapter) adapter).notifyDataSetChanged(); } catch (Exception e) { CarpaccioLogger.e(TAG, e.getMessage(), e); } } } } public void findCarpaccioControlledViews(View view) { findCarpaccioControlledViews(view, this.carpaccioViews); } public void findCarpaccioControlledViews(View view, List<View> listAddTo) { if (isCarpaccioControlledView(view)) listAddTo.add(view); if (view instanceof ViewGroup) { ViewGroup viewGroup = ViewGroup.class.cast(view); for (int i = 0; i < viewGroup.getChildCount(); ++i) findCarpaccioControlledViews(viewGroup.getChildAt(i), listAddTo); } } //endregion }