/*
* Copyright 2011 cruxframework.org.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cruxframework.crux.core.client.screen.views;
import org.cruxframework.crux.core.client.collection.FastList;
import org.cruxframework.crux.core.client.executor.BeginEndExecutor;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Device;
import org.cruxframework.crux.core.client.screen.Screen;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.RootPanel;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public class ViewHandlers
{
private static boolean initialized = false;
private static FastList<ViewContainer> boundContainers = null;
private static boolean hasWindowResizeHandler = false;
private static boolean hasOrientationChangeHandler = false;
private static boolean hasWindowCloseHandler = false;
private static boolean hasWindowClosingHandler = false;
private static boolean hasHistoryHandler = false;
private static boolean historyFrameInitialized = false;
private static HandlerRegistration resizeHandler;
private static HandlerRegistration orientationChangeHandler;
private static HandlerRegistration closeHandler;
private static HandlerRegistration closingHandler;
private static HandlerRegistration historyHandler;
protected static void initializeWindowContainers()
{
if (!initialized)
{
boundContainers = new FastList<ViewContainer>();
initialized = true;
}
}
/**
* This method must be called when the container is attached to DOM
*/
protected static void bindToDOM(ViewContainer container)
{
boundContainers.add(container);
ensureViewContainerHandlers();
}
/**
* This method must be called when the container is detached from DOM
*/
protected static void unbindToDOM(ViewContainer container)
{
boundContainers.remove(boundContainers.indexOf(container));
}
/**
*
* @param viewContainer
*/
protected static void ensureViewContainerHandlers()
{
ensureViewContainerResizeHandler();
ensureViewContainerOrientationChangeHandler();
ensureViewContainerCloseHandler();
ensureViewContainerClosingHandler();
ensureViewContainerHistoryHandler();
}
/**
*
* @param viewContainer
*/
protected static void ensureViewContainerResizeHandler()
{
if (!hasWindowResizeHandler)
{
hasWindowResizeHandler = true;
resizeHandler = addWindowResizeHandler(new ResizeHandler()
{
@Override
public void onResize(ResizeEvent event)
{
for (int i=0; i< boundContainers.size(); i++)
{
boundContainers.get(i).notifyViewsAboutWindowResize(event);
}
}
}, false);
}
}
/**
*
* @param viewContainer
*/
protected static void ensureViewContainerHistoryHandler()
{
if (!hasHistoryHandler)
{
prepareHistoryFrame();
hasHistoryHandler = true;
historyHandler = History.addValueChangeHandler(new ValueChangeHandler<String>()
{
@Override
public void onValueChange(ValueChangeEvent<String> event)
{
for (int i=0; i< boundContainers.size(); i++)
{
boundContainers.get(i).notifyViewsAboutHistoryChange(event);
}
}
});
}
}
/**
*
* @param viewContainer
* @return
*/
protected static void ensureViewContainerOrientationChangeHandler()
{
if (!hasOrientationChangeHandler)
{
hasOrientationChangeHandler = true;
orientationChangeHandler = addWindowOrientationChangeHandler(new OrientationChangeCallback()
{
@Override
public void onOrientationChange(String orientation)
{
for (int i=0; i< boundContainers.size(); i++)
{
boundContainers.get(i).notifyViewsAboutOrientationChange(orientation);
}
}
});
}
}
/**
*
* @param viewContainer
*/
protected static void ensureViewContainerCloseHandler()
{
if (!hasWindowCloseHandler)
{
hasWindowCloseHandler = true;
closeHandler = Window.addCloseHandler(new CloseHandler<Window>()
{
@Override
public void onClose(CloseEvent<Window> event)
{
for (int i=0; i< boundContainers.size(); i++)
{
boundContainers.get(i).notifyViewsAboutWindowClose(event);
}
}
});
}
}
/**
*
* @param viewContainer
*/
protected static void ensureViewContainerClosingHandler()
{
if (!hasWindowClosingHandler)
{
hasWindowClosingHandler = true;
closingHandler = Window.addWindowClosingHandler(new ClosingHandler()
{
@Override
public void onWindowClosing(ClosingEvent event)
{
for (int i=0; i< boundContainers.size(); i++)
{
boundContainers.get(i).notifyViewsAboutWindowClosing(event);
}
}
});
}
}
/**
* @param callbak
* @return
*/
private static HandlerRegistration addWindowOrientationChangeHandler(final OrientationChangeCallback callbak)
{
final JavaScriptObject orientationHandler = attachOrientationChangeHandler(callbak);
if(orientationHandler == null)
{
return null;
}
return new HandlerRegistration()
{
public void removeHandler()
{
if(orientationHandler != null)
{
removeOrientationChangeHandler(orientationHandler);
}
}
};
}
private abstract static class ResizeBeginEndExecutor extends BeginEndExecutor
{
private ResizeEvent resizeEvent;
public ResizeBeginEndExecutor(int maxIntervalBetweenStartAndEnd, ResizeEvent resizeEvent) {
super(maxIntervalBetweenStartAndEnd);
this.resizeEvent = resizeEvent;
}
public ResizeEvent getResizeEvent()
{
return resizeEvent;
}
};
/**
* @param handler
* @return
*/
private static HandlerRegistration addWindowResizeHandler(final ResizeHandler handler, final boolean lazyCheck)
{
ResizeHandler resizeHandler = new ResizeHandler()
{
public void onResize(ResizeEvent event)
{
if(!lazyCheck)
{
handler.onResize(event);
return;
}
final ResizeBeginEndExecutor executor = new ResizeBeginEndExecutor(100, event)
{
private int clientHeight = Window.getClientHeight();
private int clientWidth = Window.getClientWidth();
@Override
protected void doEndAction()
{
if (!Screen.getCurrentDevice().equals(Device.largeDisplayMouse))
{
int newClientHeight = Window.getClientHeight();
int newClientWidth = Window.getClientWidth();
if (this.clientHeight != newClientHeight || clientWidth != newClientWidth || Screen.isIos())
{
handler.onResize(getResizeEvent());
}
clientHeight = newClientHeight;
clientWidth = newClientWidth;
}
else
{
handler.onResize(getResizeEvent());
}
}
@Override
protected void doBeginAction()
{
// nothing
}
};
executor.execute();
}
};
final HandlerRegistration resizeHandlerRegistration = Window.addResizeHandler(resizeHandler);
return new HandlerRegistration()
{
public void removeHandler()
{
if(resizeHandlerRegistration != null)
{
resizeHandlerRegistration.removeHandler();
}
}
};
}
/**
* @param orientationHandler
*/
private static native void removeOrientationChangeHandler(JavaScriptObject orientationHandler) /*-{
var orientationEvent =
"onorientationchange" in $wnd ? "onorientationchange" :
"orientationchange" in $wnd ? "orientationchange" :
"ondeviceorientation" in $wnd ? "ondeviceorientation" :
"deviceorientation" in $wnd ? "deviceorientation" : null;
if (orientationEvent != null)
{
$wnd.removeEventListener(orientationEvent, orientationHandler);
}
}-*/;
/**
* @param executor
* @return
*/
private static native JavaScriptObject attachOrientationChangeHandler(OrientationChangeCallback handler)/*-{
if (! @org.cruxframework.crux.core.client.screen.views.View::isOrientationChangeSupported()())
{
return null;
}
var attachEvent,
eventListener,
orientationHandler;
if("onorientationchange" in $wnd || "orientationchange" in $wnd)
{
attachEvent = "onorientationchange";
eventListener = "orientationchange";
orientationHandler = function() { handler.@org.cruxframework.crux.core.client.screen.views.ViewHandlers.OrientationChangeCallback::onOrientationChange(Ljava/lang/String;)('unknow'); };
} else if("ondeviceorientation" in $wnd || "deviceorientation" in $wnd)
{
var delta = 15;
attachEvent = "ondeviceorientation";
eventListener = "deviceorientation";
orientationHandler = function(event)
{
var position = Math.abs(event.gamma);
if( (position >= -delta) && (position <= delta) )
{
$wnd.orientation = 'horizontal';
if($wnd.orientation !== $wnd.previousOrientation)
{
$wnd.previousOrientation = $wnd.orientation;
handler.@org.cruxframework.crux.core.client.screen.views.ViewHandlers.OrientationChangeCallback::onOrientationChange(Ljava/lang/String;)($wnd.orientation);
}
} else if( (position >= (90 - delta) ) && (position <= (90 + delta) ) )
{
$wnd.orientation = 'vertical';
if($wnd.orientation !== $wnd.previousOrientation)
{
$wnd.previousOrientation = $wnd.orientation;
handler.@org.cruxframework.crux.core.client.screen.views.ViewHandlers.OrientationChangeCallback::onOrientationChange(Ljava/lang/String;)($wnd.orientation);
}
}
};
}
if($wnd.attachEvent)
{
$wnd.attachEvent(attachEvent, orientationHandler);
} else if($wnd.addEventListener)
{
$wnd.addEventListener(eventListener, orientationHandler, false);
}
}-*/;
private static interface OrientationChangeCallback
{
void onOrientationChange(String orientation);
}
/**
*
*/
private static void prepareHistoryFrame()
{
if (!historyFrameInitialized)
{
Element body = RootPanel.getBodyElement();
IFrameElement historyFrame = DOM.createIFrame().cast();
historyFrame.setSrc("javascript:''");
historyFrame.setId("__gwt_historyFrame");
historyFrame.getStyle().setProperty("position", "absolute");
historyFrame.getStyle().setProperty("width", "0");
historyFrame.getStyle().setProperty("height", "0");
historyFrame.getStyle().setProperty("border", "0");
body.appendChild(historyFrame);
History.fireCurrentHistoryState();
historyFrameInitialized = true;
}
}
}