blob: f431d9e9ded0ddb19c18f1888a25f0c6708de419 [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
Simon Hunt6036b192015-02-11 11:20:26 -080026 var $log, fs, flash, tps;
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] )
34 sendEvent( type, {payload} )
35 */
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
41 haveDetails = false, // do we have details of one or more nodes?
42 useDetails = true; // should we show details if we have 'em?
43
44 // ==========================
45
46 function nSel() {
47 return selectOrder.length;
48 }
49 function getSel(idx) {
50 return selections[selectOrder[idx]];
51 }
52 function allSelectionsClass(cls) {
53 for (var i=0, n=nSel(); i<n; i++) {
54 if (getSel(i).obj.class !== cls) {
55 return false;
56 }
57 }
58 return true;
59 }
60
61 // ==========================
62
63 function nodeMouseOver(m) {
64 if (!m.dragStarted) {
65 $log.debug("MouseOver()...", m);
66 if (hovered != m) {
67 hovered = m;
68 requestTrafficForMode();
69 }
70 }
71 }
72
73 function nodeMouseOut(m) {
74 if (!m.dragStarted) {
75 if (hovered) {
76 hovered = null;
77 requestTrafficForMode();
78 }
79 $log.debug("MouseOut()...", m);
80 }
81 }
82
83 // ==========================
84
85 function selectObject(obj) {
86 var el = this,
87 ev = d3.event.sourceEvent,
88 n;
89
90 if (api.zoomingOrPanning(ev)) {
91 return;
92 }
93
94 if (el) {
95 n = d3.select(el);
96 } else {
97 api.node().each(function (d) {
98 if (d == obj) {
99 n = d3.select(el = this);
100 }
101 });
102 }
103 if (!n) return;
104
105 if (ev.shiftKey && n.classed('selected')) {
106 deselectObject(obj.id);
107 updateDetail();
108 return;
109 }
110
111 if (!ev.shiftKey) {
112 deselectAll();
113 }
114
115 selections[obj.id] = { obj: obj, el: el };
116 selectOrder.push(obj.id);
117
118 n.classed('selected', true);
119 api.updateDeviceColors(obj);
120 updateDetail();
121
122 debugSel();
123 }
124
125 function deselectObject(id) {
126 var obj = selections[id];
127 if (obj) {
128 d3.select(obj.el).classed('selected', false);
129 delete selections[id];
130 fs.removeFromArray(id, selectOrder);
131 api.updateDeviceColors(obj.obj);
132 }
133
134 debugSel();
135 }
136
137 function deselectAll() {
138 // deselect all nodes in the network...
139 api.node().classed('selected', false);
140 selections = {};
141 selectOrder = [];
142 api.updateDeviceColors();
143 updateDetail();
144
145 debugSel();
146 }
147
148 function debugSel() {
149 $log.debug(' ..... Selected now >> ', selectOrder);
150 }
151
152 // === -----------------------------------------------------
153
154 function requestDetails() {
155 var data = getSel(0).obj;
156 api.sendEvent('requestDetails', {
157 id: data.id,
158 class: data.class
159 });
160 }
161
162 // === -----------------------------------------------------
163
164 function updateDetail() {
165 var nSel = selectOrder.length;
166 if (!nSel) {
167 emptySelect();
168 } else if (nSel === 1) {
169 singleSelect();
170 } else {
171 multiSelect();
172 }
173 }
174
175 function emptySelect() {
176 haveDetails = false;
177 tps.hideDetailPanel();
178 cancelTraffic();
179 }
180
181 function singleSelect() {
182 // NOTE: detail is shown from 'showDetails' event callback
183 requestDetails();
184 cancelTraffic();
185 requestTrafficForMode();
186 }
187
188 function multiSelect() {
189 haveDetails = true;
190
191 // display the selected nodes in the detail panel
192 tps.displayMulti(selectOrder);
193
194 // always add the 'show traffic' action
195 tps.addAction('Show Related Traffic', showRelatedIntentsAction);
196
197 // add other actions, based on what is selected...
198 if (nSel() === 2 && allSelectionsClass('host')) {
199 tps.addAction('Create Host-to-Host Flow', addHostIntentAction);
200 } else if (nSel() >= 2 && allSelectionsClass('host')) {
201 tps.addAction('Create Multi-Source Flow', addMultiSourceIntentAction);
202 }
203
204 cancelTraffic();
205 requestTrafficForMode();
206 }
207
208
209 // === -----------------------------------------------------
210 // Event Handlers
211
212 function showDetails(data) {
213 haveDetails = true;
214
215 // display the data for the single selected node
216 tps.displaySingle(data);
217
218 // always add the 'show traffic' action
219 tps.addAction('Show Related Traffic', showRelatedIntentsAction);
220
221 // add other actions, based on what is selected...
222 if (data.type === 'switch') {
223 tps.addAction('Show Device Flows', showDeviceLinkFlowsAction);
224 }
225
226 // only show the details panel if the user hasn't "hidden" it
227 if (useDetails) {
228 tps.showDetailPanel();
229 }
230 }
231
Simon Hunt6036b192015-02-11 11:20:26 -0800232 function toggleDetails() {
233 useDetails = !useDetails;
234 if (useDetails) {
235 flash.flash('Enable details panel');
236 if (haveDetails) {
237 tps.showDetailPanel();
238 }
239 } else {
240 flash.flash('Disable details panel');
241 tps.hideDetailPanel();
242 }
243 }
244
Simon Hunt08f841d02015-02-10 14:39:20 -0800245 // === -----------------------------------------------------
246 // TODO: migrate these to topoTraffic.js
247
248 function cancelTraffic() {
249 $log.debug('TODO: cancelTraffic');
250
251 }
252 function requestTrafficForMode() {
253 $log.debug('TODO: requestTrafficForMode');
254
255 }
256 function showRelatedIntentsAction () {
257 $log.debug('TODO: showRelatedIntentsAction');
258
259 }
260 function addHostIntentAction () {
261 $log.debug('TODO: addHostIntentAction');
262
263 }
264 function addMultiSourceIntentAction () {
265 $log.debug('TODO: addMultiSourceIntentAction');
266
267 }
268 function showDeviceLinkFlowsAction () {
269 $log.debug('TODO: showDeviceLinkFlowsAction');
270
271 }
272
273
274 // === -----------------------------------------------------
275 // === MODULE DEFINITION ===
276
277 angular.module('ovTopo')
278 .factory('TopoSelectService',
Simon Hunt6036b192015-02-11 11:20:26 -0800279 ['$log', 'FnService', 'FlashService', 'TopoPanelService',
Simon Hunt08f841d02015-02-10 14:39:20 -0800280
Simon Hunt6036b192015-02-11 11:20:26 -0800281 function (_$log_, _fs_, _flash_, _tps_) {
282 $log = _$log_;
283 fs = _fs_;
284 flash = _flash_;
285 tps = _tps_;
Simon Hunt08f841d02015-02-10 14:39:20 -0800286
Simon Hunt6036b192015-02-11 11:20:26 -0800287 function initSelect(_api_) {
288 api = _api_;
289 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800290
Simon Hunt6036b192015-02-11 11:20:26 -0800291 function destroySelect() { }
Simon Hunt08f841d02015-02-10 14:39:20 -0800292
Simon Hunt6036b192015-02-11 11:20:26 -0800293 return {
294 initSelect: initSelect,
295 destroySelect: destroySelect,
Simon Hunt08f841d02015-02-10 14:39:20 -0800296
Simon Hunt6036b192015-02-11 11:20:26 -0800297 showDetails: showDetails,
298 toggleDetails: toggleDetails,
Simon Hunt08f841d02015-02-10 14:39:20 -0800299
Simon Hunt6036b192015-02-11 11:20:26 -0800300 nodeMouseOver: nodeMouseOver,
301 nodeMouseOut: nodeMouseOut,
302 selectObject: selectObject,
303 deselectObject: deselectObject,
304 deselectAll: deselectAll,
Simon Hunta0eb0a82015-02-11 12:30:06 -0800305 hovered: function () { return hovered; },
306 haveDetails: function () { return haveDetails; }
Simon Hunt6036b192015-02-11 11:20:26 -0800307 };
308 }]);
Simon Hunt08f841d02015-02-10 14:39:20 -0800309}());