package ch.unifr.pai.twice.multipointer.client;
/*
* Copyright 2013 Oliver Schmid
* 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.
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ch.unifr.pai.twice.multipointer.client.MouseCursorTimeoutEvent.Handler;
import ch.unifr.pai.twice.utils.device.client.UUID;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Use {@link ExtendedWebsocketControl} instead
*
* @author Oliver Schmid
*
*/
@Deprecated
public class WebsocketControl extends MultiCursorController implements ResizeHandler {
private boolean opened = false;
private JavaScriptObject websocket;
private final List<MouseCursor> cursors = new ArrayList<MouseCursor>();
private final Map<String, MouseCursor> assignedMouseCursors = new HashMap<String, MouseCursor>();
private final Map<String, MouseCursor> preferredMouseCursors = new HashMap<String, MouseCursor>();
private final Set<MouseCursor> activeCursorsCounter = new HashSet<MouseCursor>();
private final Storage storage = Storage.getLocalStorageIfSupported();
private final int maxCursorsOnScreen = 5;
private void initializeCursorList() {
cursors.clear();
assignedMouseCursors.clear();
cursors.add(defineMouseCursor("black", "#1a1a1a"));
cursors.add(defineMouseCursor("blue", "#336aa6"));
cursors.add(defineMouseCursor("green", "#42a75b"));
cursors.add(defineMouseCursor("grey", "#646663"));
cursors.add(defineMouseCursor("red", "#d65555"));
cursors.add(defineMouseCursor("yellow", "#f7d64c"));
cursors.add(defineMouseCursor("purple", "#cb2c7a"));
}
private MouseCursor getCursorByColor(String color) {
for (MouseCursor c : activeCursorsCounter) {
if (c.getColor().equals(color))
return c;
}
return null;
}
private MouseCursor defineMouseCursor(String cursor, String color) {
final MouseCursor c = new MouseCursor(cursor, color);
c.addMouseCursorEventHandler(new Handler() {
@Override
public void onMouseCursorTimeout(MouseCursorTimeoutEvent event) {
if (event.isDetached()) {
GWT.log("Detaching cursor " + c.getFileName());
String uuid = null;
for (String assignedCursor : assignedMouseCursors.keySet()) {
if (assignedMouseCursors.get(assignedCursor) == c) {
uuid = assignedCursor;
break;
}
}
if (uuid != null) {
assignedMouseCursors.remove(uuid);
if (storage != null)
storage.removeItem("ch.unifr.pai.mice.multicursor.assignedCursor." + c.getFileName());
}
if (!cursors.contains(c))
cursors.add(c);
}
activeCursorsCounter.remove(c);
if (storage != null)
storage.removeItem("ch.unifr.pai.mice.multicursor.activeCursor." + c.getFileName());
}
});
if (storage != null) {
String assigneduuid = storage.getItem("ch.unifr.pai.mice.multicursor.assignedCursor." + cursor);
if (assigneduuid != null)
assignedMouseCursors.put(assigneduuid, c);
String preferreduuid = storage.getItem("ch.unifr.pai.mice.multicursor.preferredCursor." + cursor);
if (preferreduuid != null)
preferredMouseCursors.put(preferreduuid, c);
String activeCursor = storage.getItem("ch.unifr.pai.mice.multicursor.activeCursor." + cursor);
if (activeCursor != null)
activeCursorsCounter.add(c);
}
if (!activeCursorsCounter.contains(c))
c.getElement().getStyle().setDisplay(Display.NONE);
else
c.show();
RootPanel.get().add(c);
return c;
}
HandlerRegistration r;
public native boolean isInIFrame() /*-{
return $wnd.top.location != $wnd.location;
}-*/;
@Override
public void start() {
if (!isInIFrame()) {
initializeCursorList();
if (r != null)
r.removeHandler();
r = Window.addResizeHandler(this);
UrlBuilder b = Window.Location.createUrlBuilder();
b.setProtocol("ws");
b.setPath("mouseControlXBrowser");
b.setHash(null);
String p = Window.Location.getPort();
Integer port;
try {
port = p != null ? Integer.parseInt(p) : 8080;
}
catch (NumberFormatException e) {
port = 8080;
}
b.setPort(port + 1);
for (String param : Window.Location.getParameterMap().keySet()) {
b.removeParameter(param);
}
websocket = createWebsocket(this, b.buildString());
if (websocket != null)
createOnBeforeUnloadHandler(websocket);
}
}
@Override
public void stop() {
super.stop();
stopWebsocket(websocket);
for (MouseCursor c : activeCursorsCounter) {
c.hide();
}
}
private native void send(JavaScriptObject websocket, String message)/*-{
if (websocket != null)
websocket.send(message);
}-*/;
private native JavaScriptObject createOnBeforeUnloadHandler(JavaScriptObject websocket)/*-{
$wnd.onbeforeunload = function() {
//$wnd.alert("CLOSE WEBSOCKET: "+websocket);
websocket.close();
}
}-*/;
private native JavaScriptObject stopWebsocket(JavaScriptObject websocket)/*-{
websocket.close();
}-*/;
private native JavaScriptObject createWebsocket(WebsocketControl w, String url)/*-{
if ("WebSocket" in $wnd) {
// Let us open a web socket
var ws = new WebSocket(url);
ws.onmessage = function(evt) {
w.@ch.unifr.pai.twice.multipointer.client.WebsocketControl::onMessage(Ljava/lang/String;)(evt.data);
}
ws.onopen = function() {
w.@ch.unifr.pai.twice.multipointer.client.WebsocketControl::onOpen()();
}
ws.onclose = function() {
w.@ch.unifr.pai.twice.multipointer.client.WebsocketControl::onClose()();
}
//Add onbeforeunload to handle closing correctly in chrome
$wnd.onbeforeunload = function() {
ws.onclose = function() {
};
ws.close();
}
return ws;
} else {
$wnd
.alert("This browser does not support multipointer functionalities (needs websockets)!");
}
return null;
}-*/;
private void onMessage(String data) {
if (data != null) {
String[] values = data.split("@");
if (values.length > 0) {
String uuid = values[0];
MouseCursor m = getOrCreateCursor(uuid);
if (m != null) {
boolean isActive = activeCursorsCounter.contains(m);
if (activeCursorsCounter.size() < maxCursorsOnScreen || isActive) {
if (!isActive) {
activeCursorsCounter.add(m);
if (storage != null) {
storage.setItem("ch.unifr.pai.mice.multicursor.activeCursor." + m.getFileName(), "true");
}
}
if (values.length > 1) {
String action = null;
Map<String, String> params = new HashMap<String, String>();
for (int i = 1; i < values.length; i++) {
String[] param = values[i].split("=");
if (param[0].equals("a"))
action = param[1];
else
params.put(param[0], param[1]);
}
m.interpretMessage(action, params);
}
}
}
}
}
}
private MouseCursor getOrCreateCursor(String uuid) {
MouseCursor m = assignedMouseCursors.get(uuid);
// If a cursor is already assigned to the uuid, return this one
if (m != null)
return m;
if (cursors.size() > 0) {
// otherwise Get the preferred mouse cursor for this uuid and check
// if it's still available
m = preferredMouseCursors.get(uuid);
// If there is no preferred cursor or if the preferred cursor is
// already in use, take another one
if (m == null || !cursors.contains(m)) {
m = cursors.get(0);
preferredMouseCursors.put(uuid, m);
if (storage != null)
storage.setItem("ch.unifr.pai.mice.multicursor.preferredCursor." + m.getFileName(), uuid);
}
m.setUuid(uuid);
cursors.remove(m);
assignedMouseCursors.put(uuid, m);
if (storage != null)
storage.setItem("ch.unifr.pai.mice.multicursor.assignedCursor." + m.getFileName(), uuid);
if (opened && websocket != null) {
send(websocket, UUID.get() + "@c@" + uuid + "@" + m.getColor());
}
return m;
}
return null;
}
private void onOpen() {
this.opened = true;
send(websocket, UUID.get() + "@s@" + Window.getClientWidth() + "@" + Window.getClientHeight());
// Window.alert("Multi cursor control started!");
}
private void onClose() {
if (!opened) {
Window.alert("The websocket server is not reachable!");
}
else {
opened = false;
// Window.alert("Stopping multi cursor control!");
}
}
@Override
public void onResize(ResizeEvent event) {
if (opened && websocket != null) {
send(websocket, UUID.get() + "@r@" + Window.getClientWidth() + "@" + Window.getClientHeight());
}
}
@Override
public void notifyCursor(String uuid, String action) {
send(websocket, UUID.get() + "@" + action + "@" + uuid);
}
}