package org.itsnat.droid.impl.xmlinflater.layout; import android.content.Context; import android.view.View; import android.view.ViewGroup; import org.itsnat.droid.AttrResourceInflaterListener; import org.itsnat.droid.ItsNatDroidException; import org.itsnat.droid.impl.ItsNatDroidImpl; import org.itsnat.droid.impl.browser.PageImpl; import org.itsnat.droid.impl.browser.serveritsnat.PageItsNatImpl; import org.itsnat.droid.impl.dom.DOMAttr; import org.itsnat.droid.impl.dom.DOMElement; import org.itsnat.droid.impl.dom.XMLDOM; import org.itsnat.droid.impl.dom.layout.DOMElemLayout; import org.itsnat.droid.impl.dom.layout.DOMElemMerge; import org.itsnat.droid.impl.dom.layout.DOMElemView; import org.itsnat.droid.impl.dom.layout.XMLDOMLayout; import org.itsnat.droid.impl.dom.layout.XMLDOMLayoutPage; import org.itsnat.droid.impl.dom.layout.XMLDOMLayoutPageItsNat; import org.itsnat.droid.impl.dom.layout.XMLDOMLayoutPageNotItsNat; import org.itsnat.droid.impl.dom.layout.XMLDOMLayoutStandalone; import org.itsnat.droid.impl.util.MiscUtil; import org.itsnat.droid.impl.xmlinflated.layout.InflatedXMLLayoutImpl; import org.itsnat.droid.impl.xmlinflated.layout.InflatedXMLLayoutPageImpl; import org.itsnat.droid.impl.xmlinflated.layout.InflatedXMLLayoutPageItsNatImpl; import org.itsnat.droid.impl.xmlinflated.layout.InflatedXMLLayoutPageNotItsNatImpl; import org.itsnat.droid.impl.xmlinflated.layout.InflatedXMLLayoutStandaloneImpl; import org.itsnat.droid.impl.xmlinflater.XMLInflater; import org.itsnat.droid.impl.xmlinflater.XMLInflaterRegistry; import org.itsnat.droid.impl.xmlinflater.layout.classtree.ClassDescViewBased; import org.itsnat.droid.impl.xmlinflater.layout.page.XMLInflaterLayoutPageItsNat; import org.itsnat.droid.impl.xmlinflater.layout.page.XMLInflaterLayoutPageNotItsNat; import org.itsnat.droid.impl.xmlinflater.layout.stdalone.XMLInflaterLayoutStandalone; import java.util.ArrayList; import java.util.List; /** * Created by jmarranz on 4/11/14. */ public abstract class XMLInflaterLayout extends XMLInflater { public XMLInflaterLayout(InflatedXMLLayoutImpl inflatedXML, int bitmapDensityReference, AttrResourceInflaterListener attrResourceInflaterListener) { super(inflatedXML, bitmapDensityReference,attrResourceInflaterListener); } public static XMLInflaterLayout createXMLInflaterLayout(ItsNatDroidImpl itsNatDroid, XMLDOMLayout xmlDOMLayout, int bitmapDensityReference, AttrResourceInflaterListener attrResourceInflaterListener, Context ctx, PageImpl page) { InflatedXMLLayoutImpl inflatedLayout; if (xmlDOMLayout instanceof XMLDOMLayoutPage) { if (page == null) throw MiscUtil.internalError(); if (xmlDOMLayout instanceof XMLDOMLayoutPageItsNat) inflatedLayout = new InflatedXMLLayoutPageItsNatImpl((PageItsNatImpl)page,itsNatDroid,(XMLDOMLayoutPageItsNat) xmlDOMLayout,ctx); else if (xmlDOMLayout instanceof XMLDOMLayoutPageNotItsNat) inflatedLayout = new InflatedXMLLayoutPageNotItsNatImpl(page,itsNatDroid,(XMLDOMLayoutPageNotItsNat) xmlDOMLayout,ctx); else return null; // Internal Error } else if (xmlDOMLayout instanceof XMLDOMLayoutStandalone) inflatedLayout = new InflatedXMLLayoutStandaloneImpl(itsNatDroid,(XMLDOMLayoutStandalone)xmlDOMLayout, ctx); else return null; // Internal Error XMLInflaterLayout xmlInflaterLayout = createXMLInflaterLayout(inflatedLayout, bitmapDensityReference, attrResourceInflaterListener); //View rootViewOrViewParent = xmlInflaterLayout.inflateLayout(viewParent, indexChild); return xmlInflaterLayout; } private static XMLInflaterLayout createXMLInflaterLayout(InflatedXMLLayoutImpl inflatedLayout, int bitmapDensityReference, AttrResourceInflaterListener attrResourceInflaterListener) { if (inflatedLayout instanceof InflatedXMLLayoutPageImpl) { if (inflatedLayout instanceof InflatedXMLLayoutPageItsNatImpl) return new XMLInflaterLayoutPageItsNat((InflatedXMLLayoutPageItsNatImpl)inflatedLayout,bitmapDensityReference,attrResourceInflaterListener); else if (inflatedLayout instanceof InflatedXMLLayoutPageNotItsNatImpl) return new XMLInflaterLayoutPageNotItsNat((InflatedXMLLayoutPageNotItsNatImpl)inflatedLayout,bitmapDensityReference,attrResourceInflaterListener); } else if (inflatedLayout instanceof InflatedXMLLayoutStandaloneImpl) { return new XMLInflaterLayoutStandalone((InflatedXMLLayoutStandaloneImpl)inflatedLayout,bitmapDensityReference,attrResourceInflaterListener); } return null; // Internal error } public InflatedXMLLayoutImpl getInflatedXMLLayoutImpl() { return (InflatedXMLLayoutImpl)inflatedXML; } public View inflateLayout(ViewGroup viewParent,int indexChild) { InflatedXMLLayoutImpl inflatedLayout = getInflatedXMLLayoutImpl(); XMLDOMLayout domLayout = inflatedLayout.getXMLDOMLayout(); View rootViewOrViewParent = inflateRootView(domLayout, viewParent, indexChild); return rootViewOrViewParent; } private ClassDescViewBased getClassDescViewBased(DOMElemView domElemView) { ClassDescViewMgr classDescViewMgr = getInflatedXMLLayoutImpl().getXMLInflaterRegistry().getClassDescViewMgr(); return classDescViewMgr.get(domElemView); } private View inflateRootView(XMLDOMLayout xmlDOMLayout,ViewGroup viewParent,int indexChild) { DOMElemLayout rootDOMView = (DOMElemLayout)xmlDOMLayout.getRootDOMElement(); DOMElemView newRootDOMElemView; if (rootDOMView instanceof DOMElemMerge) { if (viewParent == null) throw new ItsNatDroidException("Only can be used <merge> on external included layouts in a parent layout (needed a parent view)"); newRootDOMElemView = new DOMElemView((DOMElemMerge)rootDOMView); // Reemplazamos el <merge> por el ViewGroup parent como elemento, conservando los hijos y atributos del <merge> original (el namespace de Android por ejemplo) newRootDOMElemView.setTagName(viewParent.getClass().getName()); } else { if (viewParent != null) { newRootDOMElemView = new DOMElemView(viewParent.getClass().getName(), null); // Reemplazamos el <View> root (normalmente un ViewGroup pero el root del layout cargado puede ser por ej un Button) por el ViewGroup del layout padre y lo añadimos como hijo (lo que finalmente se hará más tarde), para que se definan bien los Layout Params newRootDOMElemView.addChildDOMElement(rootDOMView); } else newRootDOMElemView = (DOMElemView)rootDOMView; } PendingPostInsertChildrenTasks pendingPostInsertChildrenTasks = new PendingPostInsertChildrenTasks(); // El View rootView creado por createRootViewObjectAndFillAttributes es el root del layout a cargar // Tres casos de newRootDOMElemView: // El newRootDOMElemView puede ser el DOM de <merge> pero reemplazado por un clon básico del ViewGroup (viewParent) pero en el layout a cargar // => rootView será el ViewGroup clone (el merge es substituido) // El newRootDOMElemView puede ser el DOM del root del layout a cargar pero reemplazado por un clon básico del ViewGroup (viewParent) pero en el layout a cargar, el root del layout a cargar se añadirá como hijo único como se hará finalmente con el ViewGroup verdad (caso viewPaarent!=null) // => rootView será el ViewGroup clone (el original root es ahora el hijo del ViewGroup clone y no es rootView) // El newRootDOMElemView puede ser el DOM del root del layout a cargar pero no hay viewParent. // => rootView será el normal root del layout cargado View rootView = createRootViewObjectAndFillAttributes(newRootDOMElemView, pendingPostInsertChildrenTasks); processChildViews(newRootDOMElemView, rootView, xmlDOMLayout); pendingPostInsertChildrenTasks.executeTasks(); if (viewParent != null) { // El root del layout cargado es reemplazado temporalmente por un clon básico del ViewGroup (viewParent), tenemos que deshacer esto ViewGroup falseRootViewGroupCloned = (ViewGroup)rootView; while (falseRootViewGroupCloned.getChildCount() > 0) { View child = falseRootViewGroupCloned.getChildAt(0); falseRootViewGroupCloned.removeViewAt(0); viewParent.addView(child,indexChild); indexChild++; } // A la hora de devolver algo devolvemos viewParent QUE ES NO NULO por una parte porque el <merge> desaparece y puede tener varios hijos y en el otro caso cuando hay un viewParent // no nulo ya están insertados los elementos del layout insertado y podemos obtener el root via viewParent.getChild(indexChild). En ressumen cuando viewParent es no nulo sabemos // que devuelve viewParent getInflatedXMLLayoutImpl().setRootView(viewParent); return viewParent; } else { // rootView es el normal root del layout cargado que todavía NO está insertado getInflatedXMLLayoutImpl().setRootView(rootView); return rootView; } // Como se puede ver inflateRootView(...) devuelve viewParent o si no hay viewParent el root view del layout cargado, esto se arrastra en tod_o el stack de llamadas } private View createRootViewObjectAndFillAttributes(DOMElemView rootDOMElemView,PendingPostInsertChildrenTasks pendingPostInsertChildrenTasks) { ClassDescViewBased classDesc = getClassDescViewBased(rootDOMElemView); return classDesc.createRootViewObjectAndFillAttributes(rootDOMElemView, this, pendingPostInsertChildrenTasks); } private View createViewObjectAndFillAttributesAndAdd(ViewGroup viewParent, DOMElemView domElemView, PendingPostInsertChildrenTasks pendingPostInsertChildrenTasks) { ClassDescViewBased classDesc = getClassDescViewBased(domElemView); return classDesc.createViewObjectAndFillAttributesAndAdd(viewParent,domElemView.getDOMAttributeMap(), -1, this,pendingPostInsertChildrenTasks); } protected void processChildViews(DOMElemView domElemViewParent, View viewParent, XMLDOM xmlDOMParent) { List<DOMElement> childElemList = domElemViewParent.getChildDOMElementList(); if (childElemList != null) { ViewGroup viewParentGroup = (ViewGroup)viewParent; for (DOMElement childDOMElem : childElemList) { View childView = inflateNextView((DOMElemLayout)childDOMElem,viewParentGroup,xmlDOMParent); } } } public View insertFragment(DOMElemView rootDOMElemViewFragment, XMLDOM xmlDOMParent) { return inflateNextView(rootDOMElemViewFragment,null,xmlDOMParent); } private View inflateNextView(DOMElemLayout domElem, ViewGroup viewParent, XMLDOM xmlDOMParent) { // Es llamado también para insertar fragmentos PendingPostInsertChildrenTasks pendingPostInsertChildrenTasks = new PendingPostInsertChildrenTasks(); View view = createViewObjectAndFillAttributesAndAdd(viewParent, (DOMElemView) domElem, pendingPostInsertChildrenTasks); processChildViews((DOMElemView)domElem,view,xmlDOMParent); pendingPostInsertChildrenTasks.executeTasks(); return view; } public void fillIncludeAttributesFromGetLayout(View rootViewChild,ViewGroup viewParent,ArrayList<DOMAttr> includeAttribs) { String className = rootViewChild.getClass().getName(); XMLInflaterRegistry xmlInflaterRegistry = getInflatedXMLLayoutImpl().getItsNatDroidImpl().getXMLInflaterRegistry(); ClassDescViewBased classDesc = xmlInflaterRegistry.getClassDescViewMgr().get(className); if (classDesc == null) throw new ItsNatDroidException("Not found processor for " + className); classDesc.fillIncludeAttributesFromGetLayout(rootViewChild,viewParent,this,includeAttribs); } public abstract boolean setAttributeInlineEventHandler(View view, DOMAttr attr); public abstract boolean removeAttributeInlineEventHandler(View view, String namespaceURI, String name); }