blob: 8b37002218ec681f3d964fc5c86b17861c02d3b3 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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.
*/
/*
ONOS GUI -- Topology Toolbar Module.
Functions for creating and interacting with the toolbar.
*/
(function () {
'use strict';
// injected references
var $log, fs, tbs, ps, tov, tds, api;
// API:
// getActionEntry
// setUpKeys
// function to be replaced by the localization bundle function
var topoLion = function (x) {
return '#ttbar#' + x + '#';
};
// internal state
var toolbar, keyData, cachedState, thirdRow, ovRset, ovIndex;
// constants
var name = 'topo-tbar',
cooktag = 'topo_prefs',
soa = 'switchOverlayActions: ',
selOver = '************',
defaultOverlay = 'traffic';
// key to button mapping data
var k2b = {
O: { id: 'summary-tog', gid: 'm_summary', isel: true },
I: { id: 'instance-tog', gid: 'm_uiAttached', isel: true },
D: { id: 'details-tog', gid: 'm_details', isel: true },
H: { id: 'hosts-tog', gid: 'm_endstation', isel: false },
M: { id: 'offline-tog', gid: 'm_switch', isel: true },
P: { id: 'ports-tog', gid: 'm_ports', isel: true },
B: { id: 'bkgrnd-tog', gid: 'm_map', isel: false },
G: { id: 'bkgrnd-sel', gid: 'm_selectMap' },
S: { id: 'sprite-tog', gid: 'm_cloud', isel: false },
Z: { id: 'oblique-tog', gid: 'm_oblique', isel: false },
N: { id: 'filters-btn', gid: 'm_filters' },
L: { id: 'cycleLabels-btn', gid: 'm_cycleLabels' },
R: { id: 'resetZoom-btn', gid: 'm_resetZoom' },
E: { id: 'eqMaster-btn', gid: 'm_eqMaster' },
};
var prohibited = [
'T', 'backSlash', 'slash',
'X', // needed until we re-instate X above.
];
prohibited = prohibited.concat(d3.map(k2b).keys());
// initial toggle state: default settings and tag to key mapping
var defaultPrefsState = {
insts: 1,
summary: 1,
detail: 1,
hosts: 0,
offdev: 1,
dlbls: 0,
hlbls: 0,
porthl: 1,
bg: 0,
spr: 0,
ovid: 'traffic', // default to traffic overlay
toolbar: 0,
},
prefsMap = {
summary: 'O',
insts: 'I',
detail: 'D',
hosts: 'H',
offdev: 'M',
porthl: 'P',
bg: 'B',
spr: 'S',
// NOTE: toolbar state is handled separately
};
function init(_api_) {
api = _api_;
// retrieve initial toggle button settings from user prefs
setInitToggleState();
}
function topoDefPrefs() {
return angular.extend({}, defaultPrefsState);
}
function setInitToggleState() {
cachedState = ps.asNumbers(
ps.getPrefs(cooktag, defaultPrefsState), ['ovid'], true
);
$log.debug('TOOLBAR---- read prefs state:', cachedState);
if (!cachedState) {
cachedState = topoDefPrefs();
ps.setPrefs(cooktag, cachedState);
$log.debug('TOOLBAR---- Set default prefs state:', cachedState);
}
angular.forEach(prefsMap, function (v, k) {
var cfg = k2b[v];
cfg && (cfg.isel = !!cachedState[k]);
});
}
function initKeyData() {
// TODO: use angular forEach instead of d3.map
keyData = d3.map(k2b);
keyData.forEach(function (key, value) {
var data = api.getActionEntry(key),
ttfn = data[1]; // tooltip-possibly-a-function
value.key = key;
value.cb = data[0]; // on-click callback
// tooltip function invoked at the time the tooltip is displayed
value.tt = function () {
return fs.isF(ttfn) ? ttfn() : '' + ttfn;
};
});
}
// returns a no-args function that returns the tooltip text
function deferredText(v) {
// this function will get invoked at the time the tooltip is displayed:
return function () {
return (fs.isF(v.tt) ? v.tt() : v.tt) + ' (' + v.key + ')';
};
}
function addButton(key) {
var v = keyData.get(key);
v.btn = toolbar.addButton(v.id, v.gid, v.cb, deferredText(v));
}
function addToggle(key, suppressIfMobile) {
var v = keyData.get(key);
if (suppressIfMobile && fs.isMobile()) { return; }
v.tog = toolbar.addToggle(v.id, v.gid, v.isel, v.cb, deferredText(v));
}
function addFirstRow() {
addToggle('I');
addToggle('O');
addToggle('D');
toolbar.addSeparator();
addToggle('H');
addToggle('M');
addToggle('P', true);
addToggle('B');
addButton('G');
addToggle('S', true);
}
function addSecondRow() {
// addToggle('X');
addToggle('Z');
addButton('N');
addButton('L');
addButton('R');
toolbar.addSeparator();
addButton('E');
}
function addOverlays() {
toolbar.addSeparator();
// generate radio button set for overlays; start with 'none'
var rset = [{
gid: 'm_unknown',
tooltip: topoLion('ov_tt_none'),
cb: function () {
tov.tbSelection(null, switchOverlayActions);
},
}];
ovIndex = tov.augmentRbset(rset, switchOverlayActions);
ovRset = toolbar.addRadioSet('topo-overlays', rset);
}
// invoked by overlay service to switch out old buttons and switch in new
function switchOverlayActions(oid, keyBindings) {
var prohibits = [],
kb = fs.isO(keyBindings) || {},
order = fs.isA(kb._keyOrder) || [];
if (keyBindings && !keyBindings._keyOrder) {
$log.warn(soa + 'no _keyOrder property defined');
} else {
// sanity removal of reserved property names
['esc', '_keyListener', '_helpFormat'].forEach(function (k) {
fs.removeFromArray(k, order);
});
}
// ensure dialog has closed (if opened by outgoing overlay)
tds.closeDialog();
thirdRow.clear();
// persist our choice of overlay...
persistTopoPrefs('ovid', oid);
if (!order.length) {
thirdRow.setText(selOver);
thirdRow.classed('right', true);
api.setUpKeys(); // clear previous overlay key bindings
} else {
thirdRow.classed('right', false);
angular.forEach(order, function (key) {
var value, bid, gid, tt;
if (prohibited.indexOf(key) > -1) {
prohibits.push(key);
} else {
value = keyBindings[key];
bid = oid + '-' + key;
gid = tov.mkGlyphId(oid, value.gid);
tt = function () {
var ttfn = value.tt,
txt = fs.isF(ttfn) ? ttfn() : ttfn;
return txt + ' (' + key + ')';
};
thirdRow.addButton(bid, gid, value.cb, tt);
}
});
api.setUpKeys(keyBindings); // add overlay key bindings
}
if (prohibits.length) {
$log.warn(soa + 'Prohibited key bindings ignored:', prohibits);
}
}
function createToolbar() {
initKeyData();
toolbar = tbs.createToolbar(name);
addFirstRow();
toolbar.addRow();
addSecondRow();
addOverlays();
thirdRow = toolbar.addRow();
thirdRow.setText(selOver);
thirdRow.classed('right', true);
if (cachedState.toolbar) {
toolbar.show();
} else {
toolbar.hide();
}
}
function destroyToolbar() {
tbs.destroyToolbar(name);
tov.resetOnToolbarDestroy();
}
// allows us to ensure the button states track key strokes
function keyListener(key) {
var v = keyData.get(key);
if (v) {
// we have a valid button mapping
if (v.tog) {
// it's a toggle button
v.tog.toggleNoCb();
}
}
}
function persistTopoPrefs(key, val) {
var prefs = ps.getPrefs(cooktag, defaultPrefsState);
prefs[key] = val === undefined ? !prefs[key] : val;
ps.setPrefs('topo_prefs', prefs);
}
function toggleToolbar() {
toolbar.toggle();
persistTopoPrefs('toolbar');
}
function selectOverlay(ovid) {
var idx = ovIndex[defaultOverlay] || 0,
pidx = (ovid === null) ? 0 : ovIndex[ovid] || -1;
if (pidx >= 0 && pidx < ovRset.size()) {
idx = pidx;
}
ovRset.selectedIndex(idx);
}
// an overlay was selected via Function-Key press
function fnkey(idx) {
if (idx < ovRset.size() && idx !== ovRset.selectedIndex()) {
ovRset.selectedIndex(idx);
}
}
angular.module('ovTopo')
.factory('TopoToolbarService',
['$log', 'FnService', 'ToolbarService', 'PrefsService',
'TopoOverlayService', 'TopoDialogService',
function (_$log_, _fs_, _tbs_, _ps_, _tov_, _tds_) {
$log = _$log_;
fs = _fs_;
tbs = _tbs_;
ps = _ps_;
tov = _tov_;
tds = _tds_;
return {
init: init,
createToolbar: createToolbar,
destroyToolbar: destroyToolbar,
keyListener: keyListener,
toggleToolbar: toggleToolbar,
selectOverlay: selectOverlay,
defaultPrefs: defaultPrefsState,
fnkey: fnkey,
setLionBundle: function (bundle) { topoLion = bundle; },
};
}]);
}());