package org.itsnat.droid.impl.browser.serveritsnat;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import org.itsnat.droid.ClientErrorMode;
import org.itsnat.droid.EventMonitor;
import org.itsnat.droid.HttpRequestResult;
import org.itsnat.droid.ItsNatDroidException;
import org.itsnat.droid.ItsNatDroidServerResponseException;
import org.itsnat.droid.ItsNatView;
import org.itsnat.droid.OnEventErrorListener;
import org.itsnat.droid.OnServerStateLostListener;
import org.itsnat.droid.event.Event;
import org.itsnat.droid.event.EventStateless;
import org.itsnat.droid.event.UserEvent;
import org.itsnat.droid.impl.browser.ItsNatDocImpl;
import org.itsnat.droid.impl.browser.ItsNatDroidBrowserImpl;
import org.itsnat.droid.impl.browser.ItsNatViewImpl;
import org.itsnat.droid.impl.browser.ItsNatViewNotNullImpl;
import org.itsnat.droid.impl.browser.ItsNatViewNullImpl;
import org.itsnat.droid.impl.browser.PageImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.AttachedClientCometTaskRefreshEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.AttachedClientTimerRefreshEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.AttachedClientUnloadEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DOMExtEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DroidFocusEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DroidKeyEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DroidMotionEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DroidOtherEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.DroidTextChangeEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.EventGenericImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.EventStatelessImpl;
import org.itsnat.droid.impl.browser.serveritsnat.event.UserEventImpl;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.AsyncTaskEventListener;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.CometTaskEventListener;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.ContinueEventListener;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.DroidEventListener;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.TimerEventListener;
import org.itsnat.droid.impl.browser.serveritsnat.evtlistener.UserEventListener;
import org.itsnat.droid.impl.dom.DOMAttr;
import org.itsnat.droid.impl.dom.DOMAttrRemote;
import org.itsnat.droid.impl.dom.ResourceDesc;
import org.itsnat.droid.impl.dom.ResourceDescRemote;
import org.itsnat.droid.impl.dom.layout.XMLDOMLayoutPage;
import org.itsnat.droid.impl.util.MapList;
import org.itsnat.droid.impl.util.MapListLight;
import org.itsnat.droid.impl.util.MapListReal;
import org.itsnat.droid.impl.util.MiscUtil;
import org.itsnat.droid.impl.util.NameValue;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Created by jmarranz on 23/12/2015.
*/
public class ItsNatDocItsNatImpl extends ItsNatDocImpl implements ItsNatDocItsNatPublic
{
private static final String key_itsNatUserListenersByName = "itsNatUserListenersByName";
protected String itsNatServletPath; // Definido en el servidor
protected final Map<String,Node> nodeCacheById = new HashMap<String,Node>();
protected final DOMPathResolver pathResolver = new DOMPathResolverImpl(this);
protected Map<String,DroidEventListener> droidEventListeners;
protected Map<String,TimerEventListener> timerEventListeners;
protected Map<String,UserEventListener> userListenersById;
protected MapList<String,UserEventListener> userListenersByName;
protected Runnable attachTimerRefreshCallback;
protected Runnable attachUnloadCallback;
protected List<GlobalEventListener> globalEventListeners;
protected String attachType;
protected int errorMode;
protected boolean eventsEnabled;
protected boolean disabledEvents = false; // En Droid tiene poco sentido y no se usa, candidato a eliminarse
protected boolean enableEvtMonitors = true;
protected List<EventMonitor> evtMonitorList;
protected final EventManager evtManager = new EventManager(this);
protected LinkedList<DOMAttrRemote> attrRemoteListBSParsed;
public ItsNatDocItsNatImpl(PageItsNatImpl page,int errorMode)
{
super(page);
this.errorMode = errorMode; // errorMode el valor inicial, será cambiado por el método init() (si hay scripting)
}
public PageItsNatImpl getPageItsNatImpl()
{
return (PageItsNatImpl)page;
}
@Override
public void init(String stdSessionId,String sessionToken,String sessionId,String clientId,String servletPath,int errorMode,String attachType,boolean eventsEnabled)
{
getPageItsNatImpl().setSessionIdAndClientId(stdSessionId, sessionToken, sessionId, clientId);
this.itsNatServletPath = servletPath;
this.errorMode = errorMode; // Modifica el valor inicial
this.attachType = attachType;
this.eventsEnabled = eventsEnabled;
}
public void evalEventResultScript(String code, EventGenericImpl evt, LinkedList<DOMAttrRemote> attrRemoteListBSParsed)
{
if (attrRemoteListBSParsed != null) // Puede ser null
{
this.attrRemoteListBSParsed = attrRemoteListBSParsed;
}
try
{
super.eval(code, evt);
}
finally
{
if (attrRemoteListBSParsed != null)
{
this.attrRemoteListBSParsed = null;
}
}
}
public void evalLoadInitScript(String code, LinkedList<DOMAttrRemote> attrRemoteListBSParsed)
{
if (attrRemoteListBSParsed != null) // Puede ser null
{
this.attrRemoteListBSParsed = attrRemoteListBSParsed;
}
try
{
super.eval(code);
}
finally
{
if (attrRemoteListBSParsed != null)
{
this.attrRemoteListBSParsed = null;
}
}
}
public String getItsNatServletPath()
{
return itsNatServletPath;
}
public EventManager getEventManager()
{
return evtManager;
}
public Runnable getAttachTimerRefreshCallback()
{
return attachTimerRefreshCallback;
}
public String getAttachType()
{
return attachType;
}
public boolean isEventsEnabled()
{
return eventsEnabled;
}
public boolean isDisabledEvents()
{
return disabledEvents;
}
@Override
public void setDisabledEvents()
{
this.disabledEvents = true;
}
@Override
public void onServerStateLost()
{
OnServerStateLostListener listener = page.getOnServerStateLostListener();
if (listener != null) listener.onServerStateLost(page);
}
@Override
public void setEnableEventMonitors(boolean value) { this.enableEvtMonitors = value; }
@Override
public void addEventMonitor(EventMonitor monitor)
{
if (evtMonitorList == null) this.evtMonitorList = new ArrayList<EventMonitor>();
evtMonitorList.add(monitor);
}
@Override
public boolean removeEventMonitor(EventMonitor monitor)
{
if (evtMonitorList == null) return false;
return evtMonitorList.remove(monitor);
}
public void fireEventMonitors(boolean before,boolean timeout,Event evt)
{
if (!this.enableEvtMonitors) return;
if (evtMonitorList == null) return;
for(EventMonitor curr : evtMonitorList)
{
if (before) curr.before(evt);
else curr.after(evt,timeout);
}
}
public List<NameValue> genParamURL()
{
PageItsNatImpl pageItsNat = getPageItsNatImpl();
List<NameValue> paramList = new ArrayList<NameValue>();
paramList.add(new NameValue("itsnat_client_id", pageItsNat.getId()));
paramList.add(new NameValue("itsnat_session_token", pageItsNat.getItsNatSessionImpl().getToken()));
paramList.add(new NameValue("itsnat_session_id", pageItsNat.getItsNatSessionImpl().getId()));
return paramList;
}
private DOMAttr toDOMAttrSyncResource(String namespaceURI, String name, String value)
{
XMLDOMLayoutPage xmlDOMLayoutPage = getPageImpl().getInflatedXMLLayoutPageImpl().getXMLDOMLayoutPage();
DOMAttr attr = xmlDOMLayoutPage.createDOMAttrNotSyncResource(namespaceURI, name, value);
ResourceDesc resourceDesc = attr.getResourceDesc();
if (this.attrRemoteListBSParsed != null && resourceDesc instanceof ResourceDescRemote) // Si attrRemoteListBSParsed es null es que no hay atributos remotos extraidos del script para sincronizar
{
ResourceDescRemote resourceDescRemote = (ResourceDescRemote)resourceDesc;
DOMAttrRemote attrWithRes = attrRemoteListBSParsed.removeFirst();
attr.checkEquals(attrWithRes.getNamespaceURI(), attrWithRes.getName(), attrWithRes.getValue()); // Para estar tranquilos de que to_do va bien (es el mismo atributo, podemos copiar el objeto ParsedResource)
resourceDescRemote.setParsedResource(attrWithRes.getResourceDescRemote().getParsedResource());
}
return attr;
}
private DOMAttr[] toDOMAttrSyncResource(String namespaceURI, String[] attrNames, String[] attrValues)
{
DOMAttr[] attrArray = new DOMAttr[attrNames.length];
if (attrNames.length > 0)
{
for (int i = 0; i < attrNames.length; i++)
attrArray[i] = toDOMAttrSyncResource(namespaceURI, attrNames[i], attrValues[i]);
}
return attrArray;
}
private void setAttributeNSInternalSingle(Node node, String namespaceURI, String name, String value)
{
View view = node.getView();
Configuration configuration = getContext().getResources().getConfiguration();
DOMAttr attr = toDOMAttrSyncResource(namespaceURI, name, value);
if (view != null)
{
PageItsNatImpl page = getPageItsNatImpl();
page.getXMLInflaterLayoutPageItsNat().setAttributeSingleFromRemote(view, attr);
}
else // Es un nodo que no se ha insertado todavía
{
if (!(node instanceof NodeToInsertImpl)) throw MiscUtil.internalError();
NodeToInsertImpl nodeToIn = (NodeToInsertImpl) node;
nodeToIn.setDOMAttribute(attr);
}
}
@Override
public void setAttribute(Node node,String name,String value)
{
setAttributeNS(node, null, name, value);
}
@Override
public void setAttribute2(Object[] idObj,String name,String value)
{
setAttributeNS2(idObj, null, name, value);
}
@Override
public void setAttributeNS(Node node,String namespaceURI,String name,String value)
{
setAttributeNSInternalSingle(node, namespaceURI, name, value);
}
@Override
public void setAttributeNS2(Object[] idObj,String namespaceURI,String name,String value)
{
Node elem = getNode(idObj);
setAttributeNS(elem, namespaceURI, name, value);
}
@Override
public void setAttrBatch(Node node,String namespaceURI,String[] attrNames,String[] attrValues)
{
View view = node.getView();
if (view != null) // El node ya se ha insertado. Este caso no se da nunca todavía pero el nombre es suficientemente ambiguo para dejarlo ya programado por si somos capaces de usar setAttrBatch con un nodo ya insertado
{
PageItsNatImpl page = getPageItsNatImpl();
DOMAttr[] attrArray = toDOMAttrSyncResource(namespaceURI, attrNames, attrValues);
page.getXMLInflaterLayoutPageItsNat().setAttrBatchFromRemote(view, attrArray);
}
else // Es un nodo no insertado todavía
{
if (!(node instanceof NodeToInsertImpl)) throw MiscUtil.internalError();
NodeToInsertImpl nodeToIn = (NodeToInsertImpl)node;
int len = attrNames.length;
if (len > 0)
{
for (int i = 0; i < len; i++)
{
String name = attrNames[i];
String value = attrValues[i];
DOMAttr attr = toDOMAttrSyncResource(namespaceURI, name, value);
nodeToIn.setDOMAttribute(attr);
}
}
}
}
@Override
public void removeAttribute(Node node, String name)
{
removeAttributeNS(node, null, name);
}
@Override
public void removeAttribute2(Object[] idObj, String name)
{
removeAttributeNS2(idObj, null, name);
}
@Override
public void removeAttributeNS(Node node, String namespaceURI, String name)
{
removeAttributeNSInternal(node, namespaceURI, name);
}
@Override
public void removeAttributeNS2(Object[] idObj, String namespaceURI, String name)
{
Node node = getNode(idObj);
removeAttributeNS(node, namespaceURI, name);
}
private void removeAttributeNSInternal(Node node, String namespaceURI, String name)
{
// Si node es un NodeToInsertImpl debe estar ya insertado
if (node instanceof NodeToInsertImpl && !((NodeToInsertImpl)node).isInserted())
throw MiscUtil.internalError(); // Este caso no se da nunca porque ItsNat al insertar un nodo con atributos definidos antes de que el usuario lo inserte en el DOM, los atributos eliminados antes de insertar no generan código script porque el nodo no ha sido insertado y no lo gestiona ItsNat todavía
XMLDOMLayoutPage xmlDOMLayoutPage = getPageImpl().getInflatedXMLLayoutPageImpl().getXMLDOMLayoutPage();
String namespaceURIFinal = xmlDOMLayoutPage.extractAttrNamespaceURI(namespaceURI, name); // NECESARIO
String localName = xmlDOMLayoutPage.extractAttrLocalName(namespaceURI, name); // NECESARIO
PageItsNatImpl page = getPageItsNatImpl();
View view = node.getView();
page.getXMLInflaterLayoutPageItsNat().removeAttributeFromRemote(view, namespaceURIFinal, localName);
}
@Override
public View getView(Object[] idObj)
{
// Este método es llamado por ScriptUtil.getNodeReference(), el usuario espera que devuelva un View no nuestro Node wrapper
Node node = getNode(idObj);
if (node == null) return null;
return node.getView();
}
@Override
public Node getNode(Object[] idObj)
{
if (idObj == null) return null;
String id = null;
String cachedParentId = null;
String path = null;
Object[] newCachedParentIds = null;
int len = idObj.length;
if (len == 1)
{
id = (String)idObj[0];
}
else if (len == 2)
{
id = (String)idObj[0];
newCachedParentIds = (Object[])idObj[1];
}
else if (len >= 3)
{
cachedParentId = (String)idObj[0];
id = (String)idObj[1];
path = (String)idObj[2];
if (len == 4) newCachedParentIds = (Object[])idObj[3];
}
return getNode(id,path,cachedParentId,newCachedParentIds);
}
private Node getNode(String id,String path,String cachedParentId,Object[] newCachedParentIds)
{
Node cachedParent = null;
if (cachedParentId != null)
{
cachedParent = getNodeCached(cachedParentId);
if (cachedParent == null) throw new ItsNatDroidException("Unexpected error");
}
Node node = getNode2(cachedParent, new Object[]{id, path});
if (newCachedParentIds != null)
{
Node parentNode = getParentNode(node);
for (Object newCachedParentId : newCachedParentIds)
{
addNodeCache2((String) newCachedParentId, parentNode);
parentNode = getParentNode(parentNode);
}
}
return node;
}
/*
private Node getNode2(Node parentNode,String id)
{
return getNode2(parentNode,new Object[]{id});
}
*/
private Node getNode2(Node parentNode,Object[] idObj) // No es público
{
if (idObj == null) return null;
String id;
String path = null;
id = (String)idObj[0];
if (idObj.length == 2) path = (String)idObj[1];
if ((id == null) && (path == null)) return null; // raro
if (path == null) return getNodeCached(id); // Debe estar en la httpFileCache
else
{
// si parentNode es null caso de path absoluto, si no, path relativo
Node node = pathResolver.getNodeFromPath(path,parentNode);
if (id != null) addNodeCache2(id,node);
return node;
}
}
private String getNodeCacheId(Node node)
{
View view = node.getView();
ItsNatViewImpl itsNatView = getItsNatViewImpl(view);
return itsNatView.getNodeCacheId();
}
private Node getNodeCached(String id) // No es público
{
if (id == null) return null;
return nodeCacheById.get(id);
}
private void addNodeCache2(String id,Node node)
{
if (id == null) return; // si id es null httpFileCache desactivado
nodeCacheById.put(id,node);
View view = node.getView();
ItsNatViewImpl itsNatView = getItsNatViewImpl(view);
itsNatView.setNodeCacheId(id);
}
public Map<String,DroidEventListener> getDroidEventListeners()
{
if (droidEventListeners == null) this.droidEventListeners = new HashMap<String,DroidEventListener>();
return droidEventListeners;
}
public Map<String,TimerEventListener> getTimerEventListeners()
{
if (timerEventListeners == null) this.timerEventListeners = new HashMap<String,TimerEventListener>();
return timerEventListeners;
}
public Map<String,UserEventListener> getUserEventListenersById()
{
if (userListenersById == null) this.userListenersById = new HashMap<String,UserEventListener>();
return userListenersById;
}
public MapList<String,UserEventListener> getUserEventListenersByName()
{
if (userListenersByName == null) this.userListenersByName = new MapListReal<String,UserEventListener>();
return userListenersByName;
}
public Node getParentNode(Node node)
{
return NodeImpl.create((View) node.getView().getParent());
}
@Override
public Node createElement(String name)
{
return createElementNS(null, name);
}
@Override
public Node createElementNS(String namespaceURI,String name)
{
// El namespaceURI es irrelevante
return new NodeToInsertImpl(name);
}
public String getStringPathFromView(View view)
{
return getStringPathFromNode(NodeImpl.create(view));
}
public String getStringPathFromNode(Node node)
{
if (node == null) return null;
String nodeId = getNodeCacheId(node);
if (nodeId != null) return "id:" + nodeId; // es undefined si no esta cacheado (o null si se quito)
else
{
String parentId;
Node parentNode = node;
do
{
parentNode = getParentNode(parentNode);
parentId = getNodeCacheId(parentNode); // si parentNode es null devuelve null
}
while((parentId == null)&&(parentNode != null));
String path = pathResolver.getStringPathFromNode(node,parentNode); // Si parentNode es null (parentId es null) devuelve un path absoluto
if (parentNode != null) return "pid:" + parentId + ":" + path;
return path; // absoluto
}
}
private static int getChildIndex(Node parentNode,Node node)
{
// Esto es una chapuza pero no hay opción
ViewGroup parentView = (ViewGroup)parentNode.getView();
View view = node.getView();
int index = parentView.indexOfChild(view);
return index;
}
@Override
public void insertBefore(Node parentNode,Node newChild,Node childRef)
{
NodeToInsertImpl newChildToIn = (NodeToInsertImpl)newChild;
PageItsNatImpl page = getPageItsNatImpl();
XMLInflaterLayoutPageItsNat xmlInflaterLayout = page.getXMLInflaterLayoutPageItsNat();
ItsNatDroidBrowserImpl browser = page.getItsNatDroidBrowserImpl();
XMLInflaterRegistry xmlInflaterRegistry = browser.getItsNatDroidImpl().getXMLInflaterRegistry();
ClassDescViewBased classDesc = xmlInflaterRegistry.getClassDescViewMgr().get(newChildToIn);
int index = childRef == null ? -1 : getChildIndex(parentNode,childRef);
View view = classDesc.createViewObjectAndFillAttributesAndAddFromRemote((ViewGroup) parentNode.getView(), newChildToIn, index, xmlInflaterLayout, null);
newChildToIn.setInserted();
}
@Override
public void insertBefore2(Node parentNode,Node newChild,Node childRef,String newId)
{
insertBefore(parentNode, newChild, childRef);
if (newId != null) addNodeCache2(newId,newChild);
}
@Override
public void insertBefore3(Object[] parentIdObj,Node newChild,Object[] childRefIdObj,String newId)
{
Node parentNode = getNode(parentIdObj);
Node childRef = getNode2(parentNode, childRefIdObj);
insertBefore2(parentNode, newChild, childRef, newId);
}
@Override
public void appendChild(Node parentNode,Node newChild)
{
insertBefore(parentNode, newChild, null);
}
@Override
public void appendChild2(Node parentNode,Node newChild,String newId)
{
appendChild(parentNode, newChild);
if (newId != null) addNodeCache2(newId,newChild);
}
@Override
public void appendChild3(Object[] idObj,Node newChild,String newId)
{
Node parentNode = getNode(idObj);
appendChild2(parentNode, newChild, newId);
}
@Override
public void removeChild(Node child)
{
if (child == null) return; // Raro
removeChild(child.getView());
}
private void removeChild(View child)
{
if (child == null) return; // Raro
ViewGroup parentView = (ViewGroup)child.getParent();
parentView.removeView(child);
}
@Override
public void removeChild2(String id,boolean isText)
{
// isText es siempre false
if (isText) throw MiscUtil.internalError();
Node child = getNode(new Object[]{id});
removeChild(child);
}
@Override
public void removeChild3(Object[] parentIdObj,String childRelPath,boolean isText)
{
if (isText) throw MiscUtil.internalError();
Node parentNode = getNode(parentIdObj);
Node child = getNode2(parentNode, new Object[]{null, childRelPath});
removeChild(child);
}
@Override
public void removeNodeCache(String[] idList)
{
for (String id : idList)
{
Node node = nodeCacheById.remove(id);
if (node == null) continue; // por si acaso, no debería ocurrir
View view = node.getView();
ItsNatViewImpl viewData = getItsNatViewImpl(view);
viewData.setNodeCacheId(null);
}
}
@Override
public void clearNodeCache()
{
nodeCacheById.clear();
}
private View getChildNode(int i,Node parentNode)
{
View parentView = parentNode.getView();
if (parentView instanceof ViewGroup)
return ((ViewGroup)parentView).getChildAt(i);
return null;
}
private int getLenChildNodes(Node node)
{
View view = node.getView();
if (view instanceof ViewGroup)
return ((ViewGroup)view).getChildCount();
return 0;
}
private void removeAllChild(Node parentNode) // No es público
{
while(getLenChildNodes(parentNode) > 0)
{
View child = getChildNode(0,parentNode);
removeChild(child);
}
}
@Override
public void removeAllChild2(Object[] parentIdObj)
{
Node parentNode = getNode(parentIdObj);
removeAllChild(parentNode);
}
@Override
public Node addNodeCache(Object[] idObj)
{
return getNode(idObj);
}
@Override
public void setInnerXML(Node parentNode,String markup)
{
setInnerXML(parentNode, null, markup);
}
@Override
public void setInnerXML2(Object[] idObj,String markup)
{
setInnerXML2(idObj, null, markup);
}
@Override
public void setInnerXML(Node parentNode,String className,String markup)
{
fragmentLayoutInserter.setInnerXML((ViewGroup) parentNode.getView(), className, markup, null, getXMLDOMParserContext());
}
@Override
public void setInnerXML2(Object[] idObj,String className,String markup)
{
Node parentNode = getNode(idObj);
setInnerXML(parentNode, className, markup);
}
@Override
public UserEvent createUserEvent(String name)
{
return new UserEventImpl(name);
}
@Override
public void dispatchUserEvent(View currTargetView,UserEvent evt)
{
MapList<String,UserEventListener> listenersByName = getUserEventListenersByName(currTargetView);
if (listenersByName == null) return;
List<UserEventListener> listeners = listenersByName.get(evt.getName());
if (listeners == null) return;
for(UserEventListener listener : listeners)
{
UserEventImpl evt2 = (UserEventImpl)listener.createNormalEvent(evt);
listener.dispatchEvent(evt2);
}
}
@Override
public void fireUserEvent(View currTargetView,String name)
{
UserEvent evt = createUserEvent(name);
dispatchUserEvent(currTargetView, evt);
}
@Override
public EventStateless createEventStateless()
{
return new EventStatelessImpl();
}
@Override
public void dispatchEventStateless(EventStateless evt,int commMode,long timeout)
{
EventStatelessImpl evt2 = new EventStatelessImpl(this,(EventStatelessImpl)evt,commMode,timeout);
evt2.sendEvent();
}
@Override
public void addDroidEL(Object[] idObj,String type,String listenerId,CustomFunction customFunction,boolean useCapture,int commMode,long timeout,int eventGroupCode)
{
View currentTarget = getView(idObj);
if (currentTarget == null /*&& (!type.equals("unload") && !type.equals("load")) */) // En el caso "unload" y "load" se permite que sea nulo el target
throw MiscUtil.internalError();
ItsNatViewImpl viewData = getItsNatViewImpl(currentTarget);
DroidEventListener listenerWrapper = new DroidEventListener(this,currentTarget,type,customFunction,listenerId,useCapture,commMode,timeout,eventGroupCode);
getDroidEventListeners().put(listenerId, listenerWrapper);
viewData.getEventListeners().add(type,listenerWrapper);
if (viewData instanceof ItsNatViewNullImpl)
return; // Nada más que hacer
((ItsNatViewNotNullImpl)viewData).registerEventListenerViewAdapter(type);
}
@Override
public void removeDroidEL(String listenerId)
{
DroidEventListener listenerWrapper = getDroidEventListeners().remove(listenerId);
View currentTarget = listenerWrapper.getCurrentTarget(); // En el caso "unload" y "load" puede ser nulo => ¡¡YA NO!!
ItsNatViewImpl viewData = getItsNatViewImpl(currentTarget);
viewData.getEventListeners().remove(listenerWrapper.getType(), listenerWrapper);
}
@Override
public void addGlobalEL(GlobalEventListener listener)
{
// Por ahora no se usa pero por imitación del Web...
if (globalEventListeners == null) this.globalEventListeners = new LinkedList<GlobalEventListener>();
globalEventListeners.add(listener);
}
@Override
public void removeGlobalEL(GlobalEventListener listener) { globalEventListeners.remove(listener); }
@Override
public void sendContinueEvent(Object[] idObj,String listenerId,CustomFunction customFunc,int commMode,long timeout)
{
Node currTarget = getNode(idObj); // idObj puede ser nulo
View currTargetView = currTarget != null ? currTarget.getView() : null;
ContinueEventListener listenerWrapper = new ContinueEventListener(this,currTargetView,customFunc,listenerId,commMode,timeout);
DOMExtEventImpl evtWrapper = (DOMExtEventImpl)listenerWrapper.createNormalEvent(null);
listenerWrapper.dispatchEvent(evtWrapper);
}
@SuppressWarnings("unchecked")
private MapList<String,UserEventListener> getUserEventListenersByName(View currTargetView)
{
MapList<String, UserEventListener> listenersByName;
if (currTargetView == null) listenersByName = getUserEventListenersByName();
else
{
ItsNatView itsNatView = getItsNatView(currTargetView);
listenersByName = (MapList<String, UserEventListener>) itsNatView.getUserData().get(key_itsNatUserListenersByName);
}
return listenersByName;
}
@SuppressWarnings("unchecked")
@Override
public void addUserEL(Object[] idObj,String name,String listenerId,CustomFunction customFunc,int commMode,long timeout)
{
View currTarget = getView(idObj);
UserEventListener listenerWrapper = new UserEventListener(this,currTarget,name,customFunc,listenerId,commMode,timeout);
getUserEventListenersById().put(listenerId, listenerWrapper);
MapList<String,UserEventListener> listenersByName;
if (currTarget == null) listenersByName = getUserEventListenersByName();
else
{
ItsNatView itsNatView = getItsNatView(currTarget);
listenersByName = (MapList<String,UserEventListener>)itsNatView.getUserData().get(key_itsNatUserListenersByName);
if (listenersByName == null)
{
listenersByName = new MapListLight<String,UserEventListener>();
itsNatView.getUserData().set(key_itsNatUserListenersByName,listenersByName);
}
}
listenersByName.add(name, listenerWrapper);
}
@Override
public void removeUserEL(String listenerId)
{
UserEventListener listenerWrapper = getUserEventListenersById().remove(listenerId);
if (listenerWrapper == null) return;
View currTargetView = listenerWrapper.getCurrentTarget();
MapList<String,UserEventListener> listenersByName = getUserEventListenersByName(currTargetView);
listenersByName.remove(listenerWrapper.getName(), listenerWrapper);
}
@Override
public void sendAsyncTaskEvent(Object[] idObj,String listenerId,CustomFunction customFunc,int commMode,long timeout)
{
View currTarget = getView(idObj);
AsyncTaskEventListener listenerWrapper = new AsyncTaskEventListener(this,currTarget,customFunc,listenerId,commMode,timeout);
DOMExtEventImpl evtWrapper = (DOMExtEventImpl)listenerWrapper.createNormalEvent(null);
listenerWrapper.dispatchEvent(evtWrapper);
}
@Override
public void addTimerEL(Object[] idObj,String listenerId,CustomFunction customFunc,int commMode,long timeout,long delay)
{
View currTarget = getView(idObj);
final TimerEventListener listenerWrapper = new TimerEventListener(this,currTarget,customFunc,listenerId,commMode,timeout);
Runnable callback = new Runnable()
{
@Override
public void run()
{
// Se ejecutará en el hilo UI
DOMExtEventImpl evtWrapper = (DOMExtEventImpl) listenerWrapper.createNormalEvent(null);
try
{
listenerWrapper.dispatchEvent(evtWrapper);
}
catch(Exception ex)
{
HttpRequestResult result = (ex instanceof ItsNatDroidServerResponseException) ? ((ItsNatDroidServerResponseException)ex).getHttpRequestResult() : null;
ItsNatDroidException exFinal = (ex instanceof ItsNatDroidException) ? (ItsNatDroidException)ex : new ItsNatDroidException(ex);
PageImpl page = getPageImpl();
OnEventErrorListener errorListener = page.getOnEventErrorListener();
if (errorListener != null)
{
errorListener.onError(page, evtWrapper, exFinal, result);
}
else
{
if (errorMode != ClientErrorMode.NOT_CATCH_ERRORS)
{
// Error del servidor, lo normal es que haya lanzado una excepción
showErrorMessage(true, result,exFinal, errorMode);
}
else throw exFinal;
}
}
}
};
listenerWrapper.setCallback(callback);
getHandler().postDelayed(callback, delay);
getTimerEventListeners().put(listenerId, listenerWrapper);
}
@Override
public void removeTimerEL(String listenerId)
{
TimerEventListener listenerWrapper = getTimerEventListeners().remove(listenerId);
if (listenerWrapper == null) return;
Runnable callback = listenerWrapper.getCallback();
getHandler().removeCallbacks(callback);
}
@Override
public void updateTimerEL(String listenerId,long delay)
{
TimerEventListener listenerWrapper = getTimerEventListeners().get(listenerId);
if (listenerWrapper == null) return;
Runnable callback = listenerWrapper.getCallback();
getHandler().postDelayed(callback, delay);
}
@Override
public void sendCometTaskEvent(String listenerId,CustomFunction customFunc,int commMode,long timeout)
{
CometTaskEventListener listenerWrapper = new CometTaskEventListener(this,listenerId,customFunc,commMode,timeout);
DOMExtEventImpl evtWrapper = (DOMExtEventImpl)listenerWrapper.createNormalEvent(null);
listenerWrapper.dispatchEvent(evtWrapper);
}
@Override
public MotionEvent createMotionEvent(String type,float x, float y)
{
return DroidMotionEventImpl.createMotionEventNative(type, x, y);
}
@Override
public KeyEvent createKeyEvent(String type,int keyCode)
{
return DroidKeyEventImpl.createKeyEventNative(type, keyCode);
}
@Override
public Boolean createFocusEvent(boolean hasFocus)
{
return DroidFocusEventImpl.createFocusEventNative(hasFocus);
}
@Override
public CharSequence createTextChangeEvent(CharSequence newText)
{
return DroidTextChangeEventImpl.createTextChangeEventNative(newText);
}
@Override
public Object createOtherEvent()
{
return DroidOtherEventImpl.createOtherEventNative();
}
@Override
public boolean dispatchEvent(Node node, String type, Object nativeEvt)
{
View currTarget = NodeImpl.getView(node);
return dispatchDroidEvent(currTarget, type, nativeEvt);
}
@Override
public boolean dispatchEvent2(Object[] idObj, String type, Object nativeEvt)
{
Node currTarget = getNode(idObj);
return dispatchEvent(currTarget, type, nativeEvt);
}
private boolean dispatchDroidEvent(View target, String type, Object nativeEvt)
{
ItsNatViewImpl targetViewData = getItsNatViewImpl(target);
eventDispatcher.dispatch(targetViewData, type, nativeEvt);
return false; // No sabemos qué poner
}
public void sendUnloadEvent()
{
Object nativeEvt = createOtherEvent();
dispatchDroidEvent(getRootView(), "unload", nativeEvt);
if (attachUnloadCallback != null)
{
attachUnloadCallback.run();
}
}
public void sendLoadEvent()
{
Object nativeEvt = createOtherEvent();
dispatchDroidEvent(getRootView(), "load", nativeEvt);
}
@Override
public boolean dispatchUserEvent2(Object[] idObj,UserEvent evt)
{
View currTarget = getView(idObj);
dispatchUserEvent(currTarget, evt);
return false; // No sabemos qué poner;
}
@Override
public void initAttachTimerRefresh(final int interval,final int commMode,final long timeout)
{
final ItsNatDocItsNatImpl itsNatDoc = this;
this.attachTimerRefreshCallback = new Runnable()
{
@Override
public void run()
{
AttachedClientTimerRefreshEventImpl evtWrapper = new AttachedClientTimerRefreshEventImpl(itsNatDoc,interval,commMode,timeout);
try
{
evtWrapper.sendEvent();
}
catch(Exception ex)
{
PageImpl page = getPageImpl();
OnEventErrorListener errorListener = page.getOnEventErrorListener();
if (errorListener != null)
{
HttpRequestResult resultError = (ex instanceof ItsNatDroidServerResponseException) ? ((ItsNatDroidServerResponseException)ex).getHttpRequestResult() : null;
errorListener.onError(page, evtWrapper, ex, resultError);
}
else
{
if (ex instanceof ItsNatDroidException) throw (ItsNatDroidException) ex;
else throw new ItsNatDroidException(ex);
}
}
}
};
getHandler().postDelayed(attachTimerRefreshCallback, interval);
}
@Override
public void stopAttachTimerRefresh()
{
getHandler().removeCallbacks(attachTimerRefreshCallback);
this.attachTimerRefreshCallback = null;
}
@Override
public void sendAttachCometTaskRefresh(String listenerId,int commMode,long timeout)
{
AttachedClientCometTaskRefreshEventImpl evt = new AttachedClientCometTaskRefreshEventImpl(this,listenerId,commMode,timeout);
evt.sendEvent();
}
@Override
public void addAttachUnloadListener(final int commMode)
{
this.attachUnloadCallback = new Runnable()
{
@Override
public void run()
{
AttachedClientUnloadEventImpl evt = new AttachedClientUnloadEventImpl(ItsNatDocItsNatImpl.this,commMode,-1);
evt.sendEvent();
}
};
}
}