Simon Hunt
Committed by Gerrit Code Review

ONOS-1479 - GUI Topology Overlay Work - (WIP)

- UiExtension now uses Builder Pattern; added topology overlay factory.
- Refactored UiExtensionTest (and other classes) to use builder.
- Created UiTopoOverlayFactory, UiTopoOverlay, and TopoOverlayCache.
- Started implementation of TrafficOverlay.
- Inject TopoOverlayCache into TopologyViewMessageHandler; added TopoSelectOverlay request handler.
- Modified UiExtensionManager to create traffic overlay.
- Augmented UiWebSocket to create overlays on demand, and inject overlay cache into topo view message handler.
- added client side wiring to switch overlays.

Change-Id: I6f99596aefb3b87382517ce929d268a2447545ee
......@@ -62,7 +62,9 @@ public class IntentPerfUi {
);
private UiExtension uiExtension =
new UiExtension(views, this::newHandlers, getClass().getClassLoader());
new UiExtension.Builder(getClass().getClassLoader(), views)
.messageHandlerFactory(this::newHandlers)
.build();
private IntentPerfCollector collector;
......
......@@ -15,61 +15,47 @@
*/
package org.onosproject.ui;
import com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* User interface extension.
*/
public class UiExtension {
public final class UiExtension {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String VIEW_PREFIX = "app/view/";
private static final String EMPTY = "";
private static final String SLASH = "/";
private static final String CSS_HTML = "css.html";
private static final String JS_HTML = "js.html";
private final String prefix;
private final ClassLoader classLoader;
private final String resourcePath;
private final List<UiView> views;
private final UiMessageHandlerFactory messageHandlerFactory;
/**
* Creates a user interface extension for loading CSS and JS injections
* from {@code css.html} and {@code js.html} resources, respectively.
*
* @param views list of contributed views
* @param messageHandlerFactory optional message handler factory
* @param classLoader class-loader for user interface resources
*/
public UiExtension(List<UiView> views,
UiMessageHandlerFactory messageHandlerFactory,
ClassLoader classLoader) {
this(views, messageHandlerFactory, null, classLoader);
private final UiTopoOverlayFactory topoOverlayFactory;
// private constructor - only the builder calls this
private UiExtension(ClassLoader cl, String path, List<UiView> views,
UiMessageHandlerFactory mhFactory,
UiTopoOverlayFactory toFactory) {
this.classLoader = cl;
this.resourcePath = path;
this.views = views;
this.messageHandlerFactory = mhFactory;
this.topoOverlayFactory = toFactory;
}
/**
* Creates a user interface extension using custom resource prefix. It
* loads CSS and JS injections from {@code path/css.html} and
* {@code prefix/js.html} resources, respectively.
*
* @param views list of user interface views
* @param messageHandlerFactory optional message handler factory
* @param path resource path prefix
* @param classLoader class-loader for user interface resources
*/
public UiExtension(List<UiView> views,
UiMessageHandlerFactory messageHandlerFactory,
String path, ClassLoader classLoader) {
this.views = checkNotNull(ImmutableList.copyOf(views), "Views cannot be null");
this.messageHandlerFactory = messageHandlerFactory;
this.prefix = path != null ? (path + "/") : "";
this.classLoader = checkNotNull(classLoader, "Class loader must be specified");
}
/**
* Returns input stream containing CSS inclusion statements.
......@@ -77,7 +63,7 @@ public class UiExtension {
* @return CSS inclusion statements
*/
public InputStream css() {
return getStream(prefix + "css.html");
return getStream(resourcePath + CSS_HTML);
}
/**
......@@ -86,7 +72,7 @@ public class UiExtension {
* @return JavaScript inclusion statements
*/
public InputStream js() {
return getStream(prefix + "js.html");
return getStream(resourcePath + JS_HTML);
}
/**
......@@ -106,18 +92,28 @@ public class UiExtension {
* @return resource input stream
*/
public InputStream resource(String viewId, String path) {
return getStream(VIEW_PREFIX + viewId + "/" + path);
return getStream(VIEW_PREFIX + viewId + SLASH + path);
}
/**
* Returns message handler factory.
* Returns message handler factory, if one was defined.
*
* @return message handlers
* @return message handler factory
*/
public UiMessageHandlerFactory messageHandlerFactory() {
return messageHandlerFactory;
}
/**
* Returns the topology overlay factory, if one was defined.
*
* @return topology overlay factory
*/
public UiTopoOverlayFactory topoOverlayFactory() {
return topoOverlayFactory;
}
// Returns the resource input stream from the specified class-loader.
private InputStream getStream(String path) {
InputStream stream = classLoader.getResourceAsStream(path);
......@@ -128,4 +124,76 @@ public class UiExtension {
}
/**
* UI Extension Builder.
*/
public static class Builder {
private ClassLoader classLoader;
private String resourcePath = EMPTY;
private List<UiView> views = new ArrayList<>();
private UiMessageHandlerFactory messageHandlerFactory = null;
private UiTopoOverlayFactory topoOverlayFactory = null;
/**
* Create a builder with the given class loader.
* Resource path defaults to "".
* Views defaults to an empty list.
* Both Message and TopoOverlay factories default to null.
*
* @param cl the classloader
*/
public Builder(ClassLoader cl, List<UiView> views) {
checkNotNull(cl, "Must provide a class loader");
checkArgument(views.size() > 0, "Must provide at least one view");
this.classLoader = cl;
this.views = views;
}
/**
* Set the resource path. That is, path to where the CSS and JS
* files are located. This value should
*
* @param path resource path
* @return self, for chaining
*/
public Builder resourcePath(String path) {
this.resourcePath = path == null ? EMPTY : path + SLASH;
return this;
}
/**
* Sets the message handler factory for this extension.
*
* @param mhFactory message handler factory
* @return self, for chaining
*/
public Builder messageHandlerFactory(UiMessageHandlerFactory mhFactory) {
this.messageHandlerFactory = mhFactory;
return this;
}
/**
* Sets the topology overlay factory for this extension.
*
* @param toFactory topology overlay factory
* @return self, for chaining
*/
public Builder topoOverlayFactory(UiTopoOverlayFactory toFactory) {
this.topoOverlayFactory = toFactory;
return this;
}
/**
* Builds the UI extension.
*
* @return UI extension instance
*/
public UiExtension build() {
return new UiExtension(classLoader, resourcePath, views,
messageHandlerFactory, topoOverlayFactory);
}
}
}
......
......@@ -107,8 +107,9 @@ public abstract class UiMessageHandler {
void exec(String eventType, long sid, ObjectNode payload) {
RequestHandler requestHandler = handlerMap.get(eventType);
if (requestHandler != null) {
log.debug("process {} event...", eventType);
requestHandler.process(sid, payload);
} else {
log.warn("no request handler for event type {}", eventType);
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.onosproject.ui;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents user interface topology view overlay.
*/
public class UiTopoOverlay {
private final Logger log = LoggerFactory.getLogger(getClass());
private final String id;
/**
* Creates a new user interface topology view overlay descriptor.
*
* @param id overlay identifier
*/
public UiTopoOverlay(String id) {
this.id = id;
}
/**
* Returns the identifier for this overlay.
*
* @return the identifier
*/
public String id() {
return id;
}
/**
* Callback invoked to initialize this overlay, soon after creation.
* This default implementation does nothing.
*/
public void init() {
}
/**
* Callback invoked when this overlay is activated.
*/
public void activate() {
log.debug("Overlay '{}' Activated", id);
}
/**
* Callback invoked when this overlay is deactivated.
*/
public void deactivate() {
log.debug("Overlay '{}' Deactivated", id);
}
/**
* Callback invoked to destroy this instance by cleaning up any
* internal state ready for garbage collection.
* This default implementation does nothing.
*/
public void destroy() {
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.onosproject.ui;
import java.util.Collection;
/**
* Abstraction of an entity capable of producing one or more topology
* overlay handlers specific to a given user interface connection.
*/
public interface UiTopoOverlayFactory {
/**
* Produces a collection of new overlay handlers.
*
* @return collection of new overlay handlers
*/
Collection<UiTopoOverlay> newOverlays();
}
......@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static com.google.common.io.ByteStreams.toByteArray;
import static org.junit.Assert.*;
......@@ -29,29 +30,111 @@ import static org.onosproject.ui.UiView.Category.OTHER;
*/
public class UiExtensionTest {
private static final String FOO_ID = "foo";
private static final String FOO_LABEL = "Foo View";
private static final String BAR_ID = "bar";
private static final String BAR_LABEL = "Bar View";
private static final String CUSTOM = "custom";
private static final UiView FOO_VIEW = new UiView(OTHER, FOO_ID, FOO_LABEL);
private static final UiView BAR_VIEW = new UiView(OTHER, BAR_ID, BAR_LABEL);
private static final UiView HIDDEN_VIEW = new UiViewHidden(FOO_ID);
private static final UiMessageHandlerFactory MH_FACTORY = () -> null;
private static final UiTopoOverlayFactory TO_FACTORY = () -> null;
private final ClassLoader cl = getClass().getClassLoader();
private List<UiView> viewList;
private UiExtension ext;
private String css;
private String js;
private UiView view;
@Test
public void basics() throws IOException {
UiExtension ext = new UiExtension(ImmutableList.of(new UiView(OTHER, "foo", "Foo View")),
null,
getClass().getClassLoader());
String css = new String(toByteArray(ext.css()));
viewList = ImmutableList.of(FOO_VIEW);
ext = new UiExtension.Builder(cl, viewList).build();
css = new String(toByteArray(ext.css()));
assertTrue("incorrect css stream", css.contains("foo-css"));
String js = new String(toByteArray(ext.js()));
js = new String(toByteArray(ext.js()));
assertTrue("incorrect js stream", js.contains("foo-js"));
assertEquals("incorrect view id", "foo", ext.views().get(0).id());
assertEquals("incorrect view category", OTHER, ext.views().get(0).category());
assertNull("incorrect handler factory", ext.messageHandlerFactory());
assertEquals("expected 1 view", 1, ext.views().size());
view = ext.views().get(0);
assertEquals("wrong view category", OTHER, view.category());
assertEquals("wrong view id", FOO_ID, view.id());
assertEquals("wrong view label", FOO_LABEL, view.label());
assertNull("unexpected message handler factory", ext.messageHandlerFactory());
assertNull("unexpected topo overlay factory", ext.topoOverlayFactory());
}
@Test
public void withPath() throws IOException {
UiExtension ext = new UiExtension(ImmutableList.of(new UiView(OTHER, "foo", "Foo View")),
null, "custom", getClass().getClassLoader());
String css = new String(toByteArray(ext.css()));
viewList = ImmutableList.of(FOO_VIEW);
ext = new UiExtension.Builder(cl, viewList)
.resourcePath(CUSTOM)
.build();
css = new String(toByteArray(ext.css()));
assertTrue("incorrect css stream", css.contains("custom-css"));
String js = new String(toByteArray(ext.js()));
js = new String(toByteArray(ext.js()));
assertTrue("incorrect js stream", js.contains("custom-js"));
assertEquals("incorrect view id", "foo", ext.views().get(0).id());
assertNull("incorrect handler factory", ext.messageHandlerFactory());
assertEquals("expected 1 view", 1, ext.views().size());
view = ext.views().get(0);
assertEquals("wrong view category", OTHER, view.category());
assertEquals("wrong view id", FOO_ID, view.id());
assertEquals("wrong view label", FOO_LABEL, view.label());
assertNull("unexpected message handler factory", ext.messageHandlerFactory());
assertNull("unexpected topo overlay factory", ext.topoOverlayFactory());
}
@Test
public void messageHandlerFactory() {
viewList = ImmutableList.of(FOO_VIEW);
ext = new UiExtension.Builder(cl, viewList)
.messageHandlerFactory(MH_FACTORY)
.build();
assertEquals("wrong message handler factory", MH_FACTORY,
ext.messageHandlerFactory());
assertNull("unexpected topo overlay factory", ext.topoOverlayFactory());
}
@Test
public void topoOverlayFactory() {
viewList = ImmutableList.of(HIDDEN_VIEW);
ext = new UiExtension.Builder(cl, viewList)
.topoOverlayFactory(TO_FACTORY)
.build();
assertNull("unexpected message handler factory", ext.messageHandlerFactory());
assertEquals("wrong topo overlay factory", TO_FACTORY,
ext.topoOverlayFactory());
}
@Test
public void twoViews() {
viewList = ImmutableList.of(FOO_VIEW, BAR_VIEW);
ext = new UiExtension.Builder(cl, viewList).build();
assertEquals("expected 2 views", 2, ext.views().size());
view = ext.views().get(0);
assertEquals("wrong view category", OTHER, view.category());
assertEquals("wrong view id", FOO_ID, view.id());
assertEquals("wrong view label", FOO_LABEL, view.label());
view = ext.views().get(1);
assertEquals("wrong view category", OTHER, view.category());
assertEquals("wrong view id", BAR_ID, view.id());
assertEquals("wrong view label", BAR_LABEL, view.label());
}
}
\ No newline at end of file
......
......@@ -57,8 +57,9 @@ public class AppUiComponent {
// Application UI extension
protected UiExtension extension =
new UiExtension(uiViews, messageHandlerFactory,
getClass().getClassLoader());
new UiExtension.Builder(getClass().getClassLoader(), uiViews)
.messageHandlerFactory(messageHandlerFactory)
.build();
@Activate
protected void activate() {
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.onosproject.ui.impl;
import org.onosproject.ui.UiTopoOverlay;
import java.util.HashMap;
import java.util.Map;
/**
* A cache of {@link org.onosproject.ui.UiTopoOverlay}'s that were registered
* at the time the UI connection was established.
*/
public class TopoOverlayCache {
private final Map<String, UiTopoOverlay> overlays = new HashMap<>();
/**
* Adds a topology overlay to the cache.
*
* @param overlay a topology overlay
*/
public void add(UiTopoOverlay overlay) {
overlays.put(overlay.id(), overlay);
}
/**
* Invoked when the cache is no longer needed.
*/
public void destroy() {
overlays.clear();
}
/**
* Switching currently selected overlay.
*
* @param deact identity of overlay to deactivate
* @param act identity of overlay to activate
*/
public void switchOverlay(String deact, String act) {
UiTopoOverlay toDeactivate = getOverlay(deact);
UiTopoOverlay toActivate = getOverlay(act);
if (toDeactivate != null) {
toDeactivate.deactivate();
}
if (toActivate != null) {
toActivate.activate();
}
}
private UiTopoOverlay getOverlay(String id) {
return id == null ? null : overlays.get(id);
}
/**
* Returns the number of overlays in the cache.
*
* @return number of overlays
*/
public int size() {
return overlays.size();
}
}
......@@ -103,6 +103,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
private static final String SPRITE_DATA_REQ = "spriteDataRequest";
private static final String TOPO_START = "topoStart";
private static final String TOPO_HEARTBEAT = "topoHeartbeat";
private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
private static final String TOPO_STOP = "topoStop";
......@@ -135,6 +136,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
private final ExecutorService msgSender =
newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender"));
private TopoOverlayCache overlayCache;
private TimerTask trafficTask = null;
private TrafficEvent trafficEvent = null;
......@@ -172,6 +175,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
return ImmutableSet.of(
new TopoStart(),
new TopoHeartbeat(),
new TopoSelectOverlay(),
new TopoStop(),
new ReqSummary(),
new CancelSummary(),
......@@ -195,6 +199,15 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
);
}
/**
* Injects the topology overlay cache.
*
* @param overlayCache injected cache
*/
void setOverlayCache(TopoOverlayCache overlayCache) {
this.overlayCache = overlayCache;
}
// ==================================================================
/**
......@@ -231,6 +244,19 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
}
}
private final class TopoSelectOverlay extends RequestHandler {
private TopoSelectOverlay() {
super(TOPO_SELECT_OVERLAY);
}
@Override
public void process(long sid, ObjectNode payload) {
String deact = string(payload, "deactivate");
String act = string(payload, "activate");
overlayCache.switchOverlay(deact, act);
}
}
/**
* @deprecated in Cardinal Release
*/
......@@ -311,7 +337,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
@Override
public void process(long sid, ObjectNode payload) {
String type = string(payload, "class", "unknown");
String id = JsonUtils.string(payload, "id");
String id = string(payload, "id");
if (type.equals("device")) {
sendMessage(deviceDetails(deviceId(id), sid));
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.onosproject.ui.impl;
import org.onosproject.ui.UiTopoOverlay;
/**
* Topology Overlay for network traffic.
*/
public class TrafficOverlay extends UiTopoOverlay {
private static final String TRAFFIC_ID = "traffic";
/**
* Constructs the traffic overlay.
*/
public TrafficOverlay() {
super(TRAFFIC_ID);
}
// TODO : override init(), activate(), deactivate(), destroy()
}
......@@ -30,6 +30,7 @@ import org.onosproject.mastership.MastershipService;
import org.onosproject.ui.UiExtension;
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.UiView;
import org.onosproject.ui.UiViewHidden;
import org.onosproject.ui.impl.topo.OverlayService;
......@@ -54,6 +55,10 @@ import static org.onosproject.ui.UiView.Category.PLATFORM;
public class UiExtensionManager
implements UiExtensionService, SpriteService, OverlayService {
private static final ClassLoader CL =
UiExtensionManager.class.getClassLoader();
private static final String CORE = "core";
private final Logger log = LoggerFactory.getLogger(getClass());
// List of all extensions
......@@ -104,8 +109,16 @@ public class UiExtensionManager
new ClusterViewMessageHandler()
);
return new UiExtension(coreViews, messageHandlerFactory, "core",
UiExtensionManager.class.getClassLoader());
UiTopoOverlayFactory topoOverlayFactory =
() -> ImmutableList.of(
new TrafficOverlay()
);
return new UiExtension.Builder(CL, coreViews)
.messageHandlerFactory(messageHandlerFactory)
.topoOverlayFactory(topoOverlayFactory)
.resourcePath(CORE)
.build();
}
@Activate
......
......@@ -27,6 +27,7 @@ import org.onosproject.ui.UiConnection;
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -58,6 +59,7 @@ public class UiWebSocket
private long lastActive = System.currentTimeMillis();
private Map<String, UiMessageHandler> handlers;
private TopoOverlayCache overlayCache;
/**
* Creates a new web-socket for serving data to GUI.
......@@ -72,7 +74,7 @@ public class UiWebSocket
* Issues a close on the connection.
*/
synchronized void close() {
destroyHandlers();
destroyHandlersAndOverlays();
if (connection.isOpen()) {
connection.close();
}
......@@ -104,7 +106,7 @@ public class UiWebSocket
this.connection = connection;
this.control = (FrameConnection) connection;
try {
createHandlers();
createHandlersAndOverlays();
sendInstanceData();
log.info("GUI client connected");
......@@ -118,7 +120,7 @@ public class UiWebSocket
@Override
public synchronized void onClose(int closeCode, String message) {
destroyHandlers();
destroyHandlersAndOverlays();
log.info("GUI client disconnected [close-code={}, message={}]",
closeCode, message);
}
......@@ -131,6 +133,7 @@ public class UiWebSocket
@Override
public void onMessage(String data) {
log.debug("onMessage: {}", data);
lastActive = System.currentTimeMillis();
try {
ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
......@@ -172,8 +175,11 @@ public class UiWebSocket
}
// Creates new message handlers.
private synchronized void createHandlers() {
private synchronized void createHandlersAndOverlays() {
log.debug("creating handlers and overlays...");
handlers = new HashMap<>();
overlayCache = new TopoOverlayCache();
UiExtensionService service = directory.get(UiExtensionService.class);
service.getExtensions().forEach(ext -> {
UiMessageHandlerFactory factory = ext.messageHandlerFactory();
......@@ -181,15 +187,33 @@ public class UiWebSocket
factory.newHandlers().forEach(handler -> {
handler.init(this, directory);
handler.messageTypes().forEach(type -> handlers.put(type, handler));
// need to inject the overlay cache into topology message handler
if (handler instanceof TopologyViewMessageHandler) {
((TopologyViewMessageHandler) handler).setOverlayCache(overlayCache);
}
});
}
UiTopoOverlayFactory overlayFactory = ext.topoOverlayFactory();
if (overlayFactory != null) {
overlayFactory.newOverlays().forEach(overlayCache::add);
}
});
log.debug("#handlers = {}, #overlays = {}", handlers.size(),
overlayCache.size());
}
// Destroys message handlers.
private synchronized void destroyHandlers() {
private synchronized void destroyHandlersAndOverlays() {
log.debug("destroying handlers and overlays...");
handlers.forEach((type, handler) -> handler.destroy());
handlers.clear();
if (overlayCache != null) {
overlayCache.destroy();
overlayCache = null;
}
}
// Sends cluster node/instance information to allow GUI to fail-over.
......
......@@ -30,10 +30,11 @@
var tos = 'TopoOverlayService: ';
// injected refs
var $log, fs, gs;
var $log, fs, gs, wss;
// internal state
var overlays = {};
var overlays = {},
current = null;
function error(fn, msg) {
$log.error(tos + fn + '(): ' + msg);
......@@ -108,20 +109,42 @@
return overlays[id];
}
// an overlay was selected via toolbar radio button press from user
function tbSelection(id) {
var same = current && current.overlayId === id,
payload = {};
function doop(op) {
var oid = current.overlayId;
$log.debug('Overlay:', op, oid);
current[op]();
payload[op] = oid;
}
if (!same) {
current && doop('deactivate');
current = overlay(id);
current && doop('activate');
wss.sendEvent('topoSelectOverlay', payload);
}
}
angular.module('ovTopo')
.factory('TopoOverlayService',
['$log', 'FnService', 'GlyphService',
['$log', 'FnService', 'GlyphService', 'WebSocketService',
function (_$log_, _fs_, _gs_) {
function (_$log_, _fs_, _gs_, _wss_) {
$log = _$log_;
fs = _fs_;
gs = _gs_;
wss = _wss_;
return {
register: register,
unregister: unregister,
list: list,
overlay: overlay
overlay: overlay,
tbSelection: tbSelection
}
}]);
......
......@@ -50,14 +50,14 @@
L: { id: 'cycleLabels-btn', gid: 'cycleLabels' },
R: { id: 'resetZoom-btn', gid: 'resetZoom' },
E: { id: 'eqMaster-btn', gid: 'eqMaster' },
V: { id: 'relatedIntents-btn', gid: 'relatedIntents' },
leftArrow: { id: 'prevIntent-btn', gid: 'prevIntent' },
rightArrow: { id: 'nextIntent-btn', gid: 'nextIntent' },
W: { id: 'intentTraffic-btn', gid: 'intentTraffic' },
A: { id: 'allTraffic-btn', gid: 'allTraffic' },
F: { id: 'flows-btn', gid: 'flows' },
E: { id: 'eqMaster-btn', gid: 'eqMaster' }
F: { id: 'flows-btn', gid: 'flows' }
};
// initial toggle state: default settings and tag to key mapping
......@@ -153,14 +153,6 @@
addButton('E');
}
function setOverlay(overlayId) {
if (!overlayId) {
$log.debug('CLEAR overlay');
} else {
$log.debug('SET overlay', overlayId);
}
}
function addOverlays() {
toolbar.addSeparator();
......@@ -168,7 +160,9 @@
var rset = [{
gid: 'unknown',
tooltip: 'No Overlay',
cb: function () { setOverlay(); }
cb: function () {
tov.tbSelection(null);
}
}];
tov.list().forEach(function (key) {
......@@ -177,7 +171,7 @@
gid: ov._glyphId,
tooltip: (ov.tooltip || '(no tooltip)'),
cb: function () {
setOverlay(ov.overlayId);
tov.tbSelection(ov.overlayId);
}
});
});
......@@ -186,6 +180,7 @@
}
// TODO: 3rd row needs to be swapped in/out based on selected overlay
// NOTE: This particular row of buttons is for the traffic overlay
function addThirdRow() {
addButton('V');
addButton('leftArrow');
......