webgme
Version:
Web-based Generic Modeling Environment
424 lines (346 loc) • 16 kB
JavaScript
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
/**
* @author rkereskenyi / https://github.com/rkereskenyi
*/
define(['js/logger',
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames',
'js/RegistryKeys',
'js/Utils/PreferencesHelper'
], function (Logger,
CONSTANTS,
GMEConcepts,
nodePropertyNames,
REGISTRY_KEYS,
PreferencesHelper) {
'use strict';
var PartBrowserControl,
ALL_NSP = 'ALL',
NO_LIBS = 'Exclude Libraries',
WIDGET_NAME = 'PartBrowser',
DEFAULT_DECORATOR = 'ModelDecorator';
PartBrowserControl = function (myClient, myPartBrowserView) {
var self = this;
this._client = myClient;
this._partBrowserView = myPartBrowserView;
this._partBrowserView.onSelectorChanged = function (/*newValue*/) {
self._updateDescriptor(self._getPartDescriptorCollection());
};
//the ID of the node whose valid children types should be displayed
this._containerNodeId = WebGMEGlobal.State.getActiveObject() || null;
//decorators can use it to ask for notifications about their registered sub IDs
this._componentIDPartIDMap = {};
//stores the last known active aspect so that we can decide if it is reall
this._aspect = null;
//stores the GUID of the UI piece which is the identification of the client communications
this._guid = '_part_browser_';
//collects information for all the part descriptors
this._descriptorCollection = {};
//the decorator instances of the parts
this._partInstances = {};
//the meta descriptor that looks for the changes in meta
this._shortMetaDescriptor = {};
//the territory rules
this._territoryRules = {'': {children: 0}};
//
this._stateChangeTimeoutId = null;
//the current visualizer
this._visualizer = null;
//library filtering
this._libraryFilter = {};
this._initDragDropFeatures();
this._logger = Logger.create('gme:Panels:PartBrowser:PartBrowserPanelControl',
WebGMEGlobal.gmeConfig.client.log);
this._logger.debug('Created');
function stateChangeUpdate(stateChangeType) {
clearTimeout(self._stateChangeTimeoutId);
self._logger.debug('stateChangeUpdate from state update:', stateChangeType);
self._partBrowserView.showProgressbar();
self._stateChangeTimeoutId = setTimeout(function delayedStateChangeUpdate() {
self._updateDescriptor(self._getPartDescriptorCollection());
self._partBrowserView.hideProgressbar();
});
}
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, function (model, activeObject) {
self._containerNodeId = activeObject;
//we have to reset the aspect, if that is not available in the new container
var container = self._client.getNode(activeObject);
if (!container ||
container.getValidAspectNames().indexOf(self._aspect) === -1) {
self._aspect = null;
}
if (container && self._client && !self._client.isProjectReadOnly() &&
!self._client.isCommitReadOnly() && self._partBrowserView) {
self._partBrowserView.setReadOnly(container.isLibraryElement() || container.isLibraryRoot());
self.setReadOnly(container.isLibraryElement() || container.isLibraryRoot());
}
stateChangeUpdate(CONSTANTS.STATE_ACTIVE_OBJECT);
});
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_TAB, function (/*model, activeTabId*/) {
var activeAspect = WebGMEGlobal.State.getActiveAspect();
activeAspect = activeAspect === CONSTANTS.ASPECT_ALL ? null : activeAspect;
if (self._aspect !== activeAspect) {
self._aspect = activeAspect;
stateChangeUpdate(CONSTANTS.STATE_ACTIVE_TAB);
}
});
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_VISUALIZER, function (model, activeVisualizer) {
if (self._visualizer !== activeVisualizer) {
self._visualizer = activeVisualizer;
stateChangeUpdate(CONSTANTS.STATE_ACTIVE_VISUALIZER);
}
});
this._nodeEventHandling = function (events) {
var containerChanged = false,
i,
newShortMetaDescriptor = self._getShortMetaDescriptor();
for (i = 0; i < events.length; i += 1) {
if (events[i].eid === self._containerNodeId && events[i].etype !== 'load') {
containerChanged = true;
break;
}
}
if ((JSON.stringify(self._shortMetaDescriptor) !== JSON.stringify(newShortMetaDescriptor)) ||
containerChanged) {
self._shortMetaDescriptor = newShortMetaDescriptor;
self._updateLibrarySelector();
self._updateDescriptor(self._getPartDescriptorCollection(), true);
} else {
self._updateDecorators();
}
};
this._client.addUI(self, self._nodeEventHandling, this._guid);
this._client.updateTerritory(this._guid, this._territoryRules);
};
PartBrowserControl.prototype._defaultCompare = function (a, b) {
var result = a.name.localeCompare(b.name);
// sort alphabetically based on name first
if (result) {
return result;
} else {
return a.id.localeCompare(b.id);
}
};
PartBrowserControl.prototype._getShortMetaDescriptor = function () {
var result = {},
allMetaNodes = this._client.getAllMetaNodes(),
i,
guidLookupTable = {},
guids;
for (i = 0; i < allMetaNodes.length; i += 1) {
guidLookupTable[allMetaNodes[i].getGuid()] = i;
}
guids = Object.keys(guidLookupTable).sort();
for (i = 0; i < guids.length; i += 1) {
result[guids[i]] = {
path: allMetaNodes[guidLookupTable[guids[i]]].getId(),
name: allMetaNodes[guidLookupTable[guids[i]]].getAttribute('name'),
meta: this._client.getChildrenMeta(guidLookupTable[guids[i]])
};
}
result.libraryNames = this._client.getLibraryNames().sort();
return result;
};
PartBrowserControl.prototype._updateDescriptor = function (newDescriptor, delay) {
var descriptor = newDescriptor || {},
keys,
i,
self = this,
newTerritoryRules;
// TODO: later we should apply project specific sorting if it is defined.
keys = Object.keys(newDescriptor || {}) // get the descriptor keys or empty object
.map(function (key) {
return descriptor[key];
}) // turn the object into an array
.sort(self._defaultCompare) // sort the objects, using the default compare
.map(function (value/*, index*/) {
return value.id;
}); // get only the ids
//add and update
for (i = 0; i < keys.length; i += 1) {
if (!this._descriptorCollection[keys[i]]) {
//new item
this._partInstances[keys[i]] = this._partBrowserView.addPart(keys[i], newDescriptor[keys[i]]);
} else if (this._descriptorCollection[keys[i]].decorator !== newDescriptor[keys[i]].decorator ||
this._descriptorCollection[keys[i]].name !== newDescriptor[keys[i]].name) {
this._partInstances[keys[i]] = this._partBrowserView.updatePart(keys[i], newDescriptor[keys[i]]);
}
if (!this._descriptorCollection[keys[i]] ||
(this._descriptorCollection[keys[i]].visibility !== newDescriptor[keys[i]].visibility)) {
if (newDescriptor[keys[i]].visibility === 'hidden') {
this._partBrowserView.hidePart(keys[i]);
} else if (newDescriptor[keys[i]].visibility === 'visible') {
this._partBrowserView.showPart(keys[i]);
this._partBrowserView.setEnabled(keys[i], true);
} else if (newDescriptor[keys[i]].visibility === 'filtered') {
this._partBrowserView.hidePart(keys[i]);
} else {
this._partBrowserView.showPart(keys[i]);
this._partBrowserView.setEnabled(keys[i], false);
}
}
}
//remove
keys = Object.keys(this._descriptorCollection);
for (i = 0; i < keys.length; i += 1) {
if (!newDescriptor[keys[i]]) {
this._partBrowserView.removePart(keys[i]);
delete this._partInstances[keys[i]];
}
}
this._descriptorCollection = newDescriptor;
newTerritoryRules = this._getTerritoryPatterns();
if (JSON.stringify(this._territoryRules) !== JSON.stringify(newTerritoryRules)) {
this._territoryRules = newTerritoryRules;
if (delay) {
setTimeout(function delayedUpdateDescriptor() {
self._client.updateTerritory(self._guid, self._territoryRules);
});
} else {
self._client.updateTerritory(self._guid, self._territoryRules);
}
} else {
this._updateDecorators();
}
};
PartBrowserControl.prototype._getPartDescriptorCollection = function () {
var containerNode = this._client.getNode(this._containerNodeId),
metaNodes = this._client.getAllMetaNodes(),
descriptorCollection = {},
activePanel,
descriptor,
validInfo,
keys,
librarySelector = this._partBrowserView.getCurrentSelectorValue(),
shouldFilterOutItem = function (key) {
var namespace = librarySelector;
if (librarySelector === ALL_NSP) {
return false;
}
if (librarySelector === NO_LIBS) {
namespace = '';
}
return descriptorCollection[key].namespace !== namespace;
},
i;
for (i = 0; i < metaNodes.length; i += 1) {
descriptor = this._getPartDescriptor(metaNodes[i].getId());
if (descriptor) {
descriptorCollection[metaNodes[i].getId()] = descriptor;
descriptorCollection[metaNodes[i].getId()].visibility = 'hidden';
}
}
if (containerNode) {
activePanel = WebGMEGlobal.PanelManager.getActivePanel();
if (activePanel && typeof activePanel.getValidTypesInfo === 'function') {
validInfo = activePanel.getValidTypesInfo(containerNode.getId(), this._aspect);
} else {
// default is the containment based elements.
validInfo = containerNode.getValidChildrenTypesDetailed(this._aspect);
}
keys = Object.keys(validInfo);
for (i = 0; i < keys.length; i += 1) {
if (validInfo[keys[i]]) {
descriptorCollection[keys[i]].visibility = 'visible';
} else {
descriptorCollection[keys[i]].visibility = 'grayed';
}
if (shouldFilterOutItem(keys[i])) {
descriptorCollection[keys[i]].visibility = 'filtered';
}
}
}
return descriptorCollection;
};
PartBrowserControl.prototype._getTerritoryPatterns = function () {
var patterns = {'': {children: 0}};
if (this._containerNodeId) {
patterns[this._containerNodeId] = {children: 0};
}
return patterns;
};
PartBrowserControl.prototype._getObjectDescriptor = function (nodeId) {
var nodeObj = this._client.getNode(nodeId),
objDescriptor;
if (nodeObj) {
objDescriptor = {};
objDescriptor.id = nodeObj.getId();
objDescriptor.decorator = nodeObj.getRegistry(REGISTRY_KEYS.DECORATOR) || DEFAULT_DECORATOR;
//objDescriptor.name = nodeObj.getAttribute(nodePropertyNames.Attributes.name);
objDescriptor.namespace = nodeObj.getNamespace();
objDescriptor.name = nodeObj.getFullyQualifiedName();
} else {
this._logger.error(new Error('Node not loaded, ' + nodeId + ', when getting part descriptor.'));
}
return objDescriptor;
};
PartBrowserControl.prototype._getItemDecorator = function (decorator) {
var result;
result = this._client.decoratorManager.getDecoratorForWidget(decorator, WIDGET_NAME);
if (!result) {
result = this._client.decoratorManager.getDecoratorForWidget(DEFAULT_DECORATOR, WIDGET_NAME);
}
return result;
};
PartBrowserControl.prototype._getPartDescriptor = function (id) {
var desc = this._getObjectDescriptor(id);
if (desc) {
desc.decoratorClass = this._getItemDecorator(desc.decorator);
desc.control = this;
desc.metaInfo = {};
desc.metaInfo[CONSTANTS.GME_ID] = id;
desc.preferencesHelper = PreferencesHelper.getPreferences();
desc.aspect = this._aspect;
}
return desc;
};
PartBrowserControl.prototype.registerComponentIDForPartID = function (componentID, partId) {
this._componentIDPartIDMap[componentID] = this._componentIDPartIDMap[componentID] || [];
if (this._componentIDPartIDMap[componentID].indexOf(partId) === -1) {
this._componentIDPartIDMap[componentID].push(partId);
}
};
PartBrowserControl.prototype.unregisterComponentIDFromPartID = function (componentID, partId) {
var idx;
if (this._componentIDPartIDMap && this._componentIDPartIDMap[componentID]) {
idx = this._componentIDPartIDMap[componentID].indexOf(partId);
if (idx !== -1) {
this._componentIDPartIDMap[componentID].splice(idx, 1);
if (this._componentIDPartIDMap[componentID].length === 0) {
delete this._componentIDPartIDMap[componentID];
}
}
}
};
PartBrowserControl.prototype._initDragDropFeatures = function () {
var dragEffects = this._partBrowserView.DRAG_EFFECTS;
this._partBrowserView.getDragEffects = function (/*el*/) {
return [dragEffects.DRAG_CREATE_INSTANCE];
};
this._partBrowserView.getDragItems = function (el) {
return [el.attr('id')];
};
};
PartBrowserControl.prototype._updateDecorators = function () {
var i,
keys = Object.keys(this._partInstances || {});
for (i = 0; i < keys.length; i += 1) {
if (this._descriptorCollection[keys[i]] && this._descriptorCollection[keys[i]].visibility !== 'hidden') {
this._partInstances[keys[i]].update();
}
}
};
PartBrowserControl.prototype._updateLibrarySelector = function () {
var self = this,
libraryNames = self._client.getLibraryNames().sort();
if (libraryNames.length > 0) {
libraryNames.unshift('-');
libraryNames.unshift(NO_LIBS);
libraryNames.unshift(ALL_NSP);
}
self._partBrowserView.updateSelectorInfo(libraryNames);
};
return PartBrowserControl;
});