blob: 880ab9023442962b4ce27fb51b47dddc22c40ba1 [file] [log] [blame]
Simon Hunt08f841d02015-02-10 14:39:20 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- Topology Selection Module.
19 Defines behavior when selecting nodes.
20 */
21
22(function () {
23 'use strict';
24
25 // injected refs
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -070026 var $log, fs, wss, tps, tts, ns;
Simon Hunt08f841d02015-02-10 14:39:20 -080027
28 // api to topoForce
29 var api;
30 /*
31 node() // get ref to D3 selection of nodes
32 zoomingOrPanning( ev )
33 updateDeviceColors( [dev] )
Simon Hunt0c6b2d32015-03-26 17:46:29 -070034 deselectLink()
Simon Hunt08f841d02015-02-10 14:39:20 -080035 */
36
37 // internal state
38 var hovered, // the node over which the mouse is hovering
39 selections = {}, // currently selected nodes (by id)
40 selectOrder = [], // the order in which we made selections
Simon Hunt0c6b2d32015-03-26 17:46:29 -070041 consumeClick = false; // used to coordinate with SVG click handler
Simon Hunt08f841d02015-02-10 14:39:20 -080042
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -070043 // constants
Bri Prebilic Coleac829e42015-05-05 13:42:06 -070044 var flowPath = 'flow',
Bri Prebilic Cole5c60d6e2015-05-12 09:11:03 -070045 portPath ='port',
46 groupPath = 'group';
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -070047
Simon Hunt08f841d02015-02-10 14:39:20 -080048 // ==========================
49
50 function nSel() {
51 return selectOrder.length;
52 }
53 function getSel(idx) {
54 return selections[selectOrder[idx]];
55 }
56 function allSelectionsClass(cls) {
57 for (var i=0, n=nSel(); i<n; i++) {
58 if (getSel(i).obj.class !== cls) {
59 return false;
60 }
61 }
62 return true;
63 }
64
65 // ==========================
66
67 function nodeMouseOver(m) {
68 if (!m.dragStarted) {
Simon Hunt36a58c62015-04-08 11:00:07 -070069 //$log.debug("MouseOver()...", m);
Simon Hunt08f841d02015-02-10 14:39:20 -080070 if (hovered != m) {
71 hovered = m;
Simon Huntf542d842015-02-11 16:20:33 -080072 tts.requestTrafficForMode();
Simon Hunt08f841d02015-02-10 14:39:20 -080073 }
74 }
75 }
76
77 function nodeMouseOut(m) {
78 if (!m.dragStarted) {
79 if (hovered) {
80 hovered = null;
Simon Huntf542d842015-02-11 16:20:33 -080081 tts.requestTrafficForMode();
Simon Hunt08f841d02015-02-10 14:39:20 -080082 }
Simon Hunt36a58c62015-04-08 11:00:07 -070083 //$log.debug("MouseOut()...", m);
Simon Hunt08f841d02015-02-10 14:39:20 -080084 }
85 }
86
87 // ==========================
88
89 function selectObject(obj) {
90 var el = this,
Simon Hunt5aac2fc2015-06-09 12:34:07 -070091 nodeEv = el && el.tagName === 'g',
92 ev = d3.event.sourceEvent || {},
Simon Hunt08f841d02015-02-10 14:39:20 -080093 n;
94
95 if (api.zoomingOrPanning(ev)) {
96 return;
97 }
98
Simon Hunt5aac2fc2015-06-09 12:34:07 -070099 if (nodeEv) {
Simon Hunt08f841d02015-02-10 14:39:20 -0800100 n = d3.select(el);
101 } else {
102 api.node().each(function (d) {
103 if (d == obj) {
104 n = d3.select(el = this);
105 }
106 });
107 }
108 if (!n) return;
109
Simon Hunt5aac2fc2015-06-09 12:34:07 -0700110 if (nodeEv) {
111 consumeClick = true;
112 }
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700113 api.deselectLink();
114
Simon Hunt08f841d02015-02-10 14:39:20 -0800115 if (ev.shiftKey && n.classed('selected')) {
116 deselectObject(obj.id);
117 updateDetail();
118 return;
119 }
120
121 if (!ev.shiftKey) {
122 deselectAll();
123 }
124
125 selections[obj.id] = { obj: obj, el: el };
126 selectOrder.push(obj.id);
127
128 n.classed('selected', true);
129 api.updateDeviceColors(obj);
130 updateDetail();
Simon Hunt08f841d02015-02-10 14:39:20 -0800131 }
132
133 function deselectObject(id) {
134 var obj = selections[id];
135 if (obj) {
136 d3.select(obj.el).classed('selected', false);
137 delete selections[id];
138 fs.removeFromArray(id, selectOrder);
139 api.updateDeviceColors(obj.obj);
140 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800141 }
142
143 function deselectAll() {
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700144 var something = (selectOrder.length > 0);
145
Simon Hunt08f841d02015-02-10 14:39:20 -0800146 // deselect all nodes in the network...
147 api.node().classed('selected', false);
148 selections = {};
149 selectOrder = [];
150 api.updateDeviceColors();
151 updateDetail();
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700152
153 // return true if something was selected
154 return something;
Simon Hunt08f841d02015-02-10 14:39:20 -0800155 }
156
157 // === -----------------------------------------------------
158
159 function requestDetails() {
160 var data = getSel(0).obj;
Simon Hunt237676b52015-03-10 19:04:26 -0700161 wss.sendEvent('requestDetails', {
Simon Hunt08f841d02015-02-10 14:39:20 -0800162 id: data.id,
163 class: data.class
164 });
165 }
166
167 // === -----------------------------------------------------
168
169 function updateDetail() {
170 var nSel = selectOrder.length;
171 if (!nSel) {
172 emptySelect();
173 } else if (nSel === 1) {
174 singleSelect();
175 } else {
176 multiSelect();
177 }
178 }
179
180 function emptySelect() {
Simon Huntf542d842015-02-11 16:20:33 -0800181 tts.cancelTraffic();
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700182 tps.displayNothing();
Simon Hunt08f841d02015-02-10 14:39:20 -0800183 }
184
185 function singleSelect() {
186 // NOTE: detail is shown from 'showDetails' event callback
187 requestDetails();
Simon Huntf542d842015-02-11 16:20:33 -0800188 tts.cancelTraffic();
189 tts.requestTrafficForMode();
Simon Hunt08f841d02015-02-10 14:39:20 -0800190 }
191
192 function multiSelect() {
Simon Hunt08f841d02015-02-10 14:39:20 -0800193 // display the selected nodes in the detail panel
194 tps.displayMulti(selectOrder);
195
196 // always add the 'show traffic' action
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700197 tps.addAction({
198 id: '-mult-rel-traf-btn',
199 gid: 'allTraffic',
200 cb: tts.showRelatedIntentsAction,
201 tt: 'Show Related Traffic'
202 });
Simon Hunt08f841d02015-02-10 14:39:20 -0800203
204 // add other actions, based on what is selected...
205 if (nSel() === 2 && allSelectionsClass('host')) {
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700206 tps.addAction({
207 id: 'host-flow-btn',
208 gid: 'endstation',
209 cb: tts.addHostIntentAction,
210 tt: 'Create Host-to-Host Flow'
211 });
Simon Hunt08f841d02015-02-10 14:39:20 -0800212 } else if (nSel() >= 2 && allSelectionsClass('host')) {
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700213 tps.addAction({
214 id: 'mult-src-flow-btn',
215 gid: 'flows',
216 cb: tts.addMultiSourceIntentAction,
217 tt: 'Create Multi-Source Flow'
218 });
Simon Hunt08f841d02015-02-10 14:39:20 -0800219 }
220
Simon Huntf542d842015-02-11 16:20:33 -0800221 tts.cancelTraffic();
222 tts.requestTrafficForMode();
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700223 tps.displaySomething();
Simon Hunt08f841d02015-02-10 14:39:20 -0800224 }
225
226
227 // === -----------------------------------------------------
228 // Event Handlers
229
230 function showDetails(data) {
Simon Hunt08f841d02015-02-10 14:39:20 -0800231 // display the data for the single selected node
232 tps.displaySingle(data);
233
234 // always add the 'show traffic' action
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700235 tps.addAction({
236 id: '-sin-rel-traf-btn',
237 gid: 'intentTraffic',
238 cb: tts.showRelatedIntentsAction,
239 tt: 'Show Related Traffic'
240 });
Simon Hunt08f841d02015-02-10 14:39:20 -0800241
242 // add other actions, based on what is selected...
243 if (data.type === 'switch') {
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700244 tps.addAction({
245 id: 'sin-dev-flows-btn',
246 gid: 'flows',
247 cb: tts.showDeviceLinkFlowsAction,
248 tt: 'Show Device Flows'
249 });
Simon Hunt08f841d02015-02-10 14:39:20 -0800250 }
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700251 // TODO: have the server return explicit class and ID of each node
252 // for now, we assume the node is a device if it has a URI
253 if ((data.props).hasOwnProperty('URI')) {
254 tps.addAction({
255 id: 'flows-table-btn',
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700256 gid: 'flowTable',
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700257 cb: function () {
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700258 ns.navTo(flowPath, { devId: data.props['URI'] });
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700259 },
Bri Prebilic Coleac829e42015-05-05 13:42:06 -0700260 tt: 'Show flow view for this device'
261 });
262 tps.addAction({
263 id: 'ports-table-btn',
Bri Prebilic Cole9467a232015-05-06 16:59:05 -0700264 gid: 'portTable',
Bri Prebilic Coleac829e42015-05-05 13:42:06 -0700265 cb: function () {
266 ns.navTo(portPath, { devId: data.props['URI'] });
267 },
268 tt: 'Show port view for this device'
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700269 });
Bri Prebilic Cole5c60d6e2015-05-12 09:11:03 -0700270 tps.addAction({
271 id: 'groups-table-btn',
272 gid: 'groupTable',
273 cb: function () {
274 ns.navTo(groupPath, { devId: data.props['URI'] });
275 },
276 tt: 'Show group view for this device'
277 });
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700278 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800279
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700280 tps.displaySomething();
Simon Hunt6036b192015-02-11 11:20:26 -0800281 }
282
Simon Huntf542d842015-02-11 16:20:33 -0800283 function validateSelectionContext() {
284 if (!hovered && !nSel()) {
285 tts.cancelTraffic();
286 return false;
287 }
288 return true;
Simon Hunt08f841d02015-02-10 14:39:20 -0800289 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800290
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700291 function clickConsumed(x) {
292 var cc = consumeClick;
293 consumeClick = !!x;
294 return cc;
295 }
296
Simon Hunt08f841d02015-02-10 14:39:20 -0800297 // === -----------------------------------------------------
298 // === MODULE DEFINITION ===
299
300 angular.module('ovTopo')
Simon Hunt75ec9692015-02-11 16:40:36 -0800301 .factory('TopoSelectService',
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700302 ['$log', 'FnService', 'WebSocketService',
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700303 'TopoPanelService', 'TopoTrafficService', 'NavService',
Simon Hunt08f841d02015-02-10 14:39:20 -0800304
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700305 function (_$log_, _fs_, _wss_, _tps_, _tts_, _ns_) {
Simon Hunt6036b192015-02-11 11:20:26 -0800306 $log = _$log_;
307 fs = _fs_;
Simon Hunt237676b52015-03-10 19:04:26 -0700308 wss = _wss_;
Simon Hunt6036b192015-02-11 11:20:26 -0800309 tps = _tps_;
Simon Huntf542d842015-02-11 16:20:33 -0800310 tts = _tts_;
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700311 ns = _ns_;
Simon Hunt08f841d02015-02-10 14:39:20 -0800312
Simon Hunt6036b192015-02-11 11:20:26 -0800313 function initSelect(_api_) {
314 api = _api_;
315 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800316
Simon Hunt6036b192015-02-11 11:20:26 -0800317 function destroySelect() { }
Simon Hunt08f841d02015-02-10 14:39:20 -0800318
Simon Hunt6036b192015-02-11 11:20:26 -0800319 return {
320 initSelect: initSelect,
321 destroySelect: destroySelect,
Simon Hunt08f841d02015-02-10 14:39:20 -0800322
Simon Hunt6036b192015-02-11 11:20:26 -0800323 showDetails: showDetails,
Simon Hunt08f841d02015-02-10 14:39:20 -0800324
Simon Hunt6036b192015-02-11 11:20:26 -0800325 nodeMouseOver: nodeMouseOver,
326 nodeMouseOut: nodeMouseOut,
327 selectObject: selectObject,
328 deselectObject: deselectObject,
329 deselectAll: deselectAll,
Simon Huntf542d842015-02-11 16:20:33 -0800330
Simon Hunta0eb0a82015-02-11 12:30:06 -0800331 hovered: function () { return hovered; },
Simon Huntf542d842015-02-11 16:20:33 -0800332 selectOrder: function () { return selectOrder; },
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700333 validateSelectionContext: validateSelectionContext,
334
335 clickConsumed: clickConsumed
Simon Hunt6036b192015-02-11 11:20:26 -0800336 };
337 }]);
Simon Hunt08f841d02015-02-10 14:39:20 -0800338}());