UNPKG

webgme-bip

Version:

Design studio for component-based modeling with BIP.

409 lines (346 loc) 15.6 kB
/*globals define, WebGMEGlobal*/ /*jshint browser: true*/ /** * @author kecso / https://github.com/kecso */ /** * Generated by VisualizerGenerator 1.7.0 from webgme on Wed Apr 12 2017 11:41:59 GMT-0500 (Central Daylight Time). */ define([ 'js/Constants', 'q', 'common/util/ejs', 'bipsrc/templates/ejsCache', 'bipsrc/parsers/javaExtra', 'bipsrc/util/utils', 'bipsrc/bower_components/pegjs/peg-0.10.0' ], function (CONSTANTS, Q, ejs, ejsCache, javaParser, utils, peg) { 'use strict'; var BIPCodeEditorControl; BIPCodeEditorControl = function (options) { this._logger = options.logger.fork('Control'); this._client = options.client; this._widget = options.widget; this._currentNodeId = null; this._gatheringSegments = false; this._missedEvents = false; this._territory = null; this._segmentInfo = {}; this._UID = null; this._initialize(); this._logger.debug('ctor finished'); }; BIPCodeEditorControl.prototype._initialize = function () { var self = this; this._UID = this._client.addUI(self, function (events) { self._eventCallback(events); }); this._initWidgetEventHandlers(); }; BIPCodeEditorControl.prototype._initWidgetEventHandlers = function () { var self = this; this._widget.onSave = function (segmentedDocumentObject) { // console.log(segmentedDocumentObject); self._SaveDocument(segmentedDocumentObject); }; }; /* * * * * * * * Visualizer content update callbacks * * * * * * * */ // One major concept here is with managing the territory. The territory // defines the parts of the project that the visualizer is interested in // (this allows the browser to then only load those relevant parts). BIPCodeEditorControl.prototype.selectedObjectChanged = function (nodeId) { var node = this._client.getNode(nodeId), typeId = node !== null ? node.getMetaTypeId() : null; if (typeof nodeId === 'string' && this._currentNodeId !== nodeId && typeof typeId === 'string' && this._client.getNode(typeId).getAttribute('name') === 'ComponentType') { //we have a viable component type so let us change things this._currentNodeId = nodeId; this._selfPatterns = {}; this._selfPatterns[nodeId] = {children: 1}; this._client.updateTerritory(this._UID, this._selfPatterns); } else { this._logger.info('received unwanted object change event'); } }; BIPCodeEditorControl.prototype._getComponentTypeModel = function (cTypeId) { var self = this, deferred = Q.defer(), model = {}, context; Q.ninvoke(self._client, 'getCoreInstance', {}) .then(function (context_) { context = context_; return context.core.loadByPath(context.rootNode, cTypeId); }) .then(function (componentType) { if (componentType) { return utils.getModelOfComponentType(context.core, componentType); } else { throw new Error('Component was removed!'); } }) .then(deferred.resolve) .catch(deferred.reject); return deferred.promise; }; BIPCodeEditorControl.prototype._getSegmentOffset = function (segmentedDocument, segmentId) { var compiledText = '', index = 0, sId = segmentedDocument.composition[0] || null; while (sId !== null && sId !== segmentId && index < segmentedDocument.composition.length) { compiledText += segmentedDocument.segments[sId].value + '\n'; sId = segmentedDocument.composition[++index]; } return compiledText.split('\n').length; }; BIPCodeEditorControl.prototype._buildSegmentInfo = function (nodeId) { var self = this, deferred = Q.defer(), model, segmentId, guardNames = [], guardExpressionParser, addSegment = function (segmentId, segmentPath, segmentModel, readonly) { var fullSegmentId = segmentId + '*' + segmentPath; segmentedDocument.composition.push(fullSegmentId); segmentedDocument.segments[fullSegmentId] = { value: ejs.render(ejsCache.componentType[segmentId], segmentModel), options: {readonly: readonly === true} }; return fullSegmentId; }, segmentedDocument = {composition: [], segments: {}, errors: []}; self._getComponentTypeModel(nodeId) .then(function (model_) { var i, wholeDocument = ejs.render(ejsCache.componentType.complete, model_), parseResult; model = model_; parseResult = javaParser.checkWholeFile(wholeDocument); if (parseResult) { segmentedDocument.errors.push(parseResult); } for (i = 0; i < model.guards.length; i += 1) { guardNames.push(model.guards[i].name); } if (guardNames.length > 0) { guardExpressionParser = peg.generate( ejs.render(ejsCache.guardExpression, {guardNames: guardNames}) ); } addSegment('constantImports', model.path, model, true); addSegment('userImports', model.path, model); addSegment('portsAnnotations', model.path, model, true); addSegment('classStart', model.path, model, true); addSegment('userDefinitions', model.path, model); addSegment('classInitializations', model.path, model, true); addSegment('userConstructors', model.path, model); for (i = 0; i < model.transitions.length; i += 1) { segmentId = addSegment('singleTransitionAnnotation', model.transitions[i].path, model.transitions[i], true); //FIXME should we allow empty string or have a constant 'true' in case of no expression if (model.transitions[i].guard.length > 0) { try { parseResult = guardExpressionParser.parse(model.transitions[i].guard); } catch (e) { segmentedDocument.errors.push({ message: 'Guard expression should be a logical expression ' + 'that has only defined guard names as symbols.', line: self._getSegmentOffset(segmentedDocument, segmentId) }); } } segmentId = addSegment('singleTransition', model.transitions[i].path, model.transitions[i]); parseResult = javaParser.checkForSingleFunction( segmentedDocument.segments[segmentId].value, null, 'public', self._getSegmentOffset(segmentedDocument, segmentId)); if (parseResult) { segmentedDocument.errors.push(parseResult); } } for (i = 0; i < model.guards.length; i += 1) { addSegment('singleGuardAnnotation', model.guards[i].path, model.guards[i], true); segmentId = addSegment('singleGuard', model.guards[i].path, model.guards[i]); parseResult = javaParser.checkForSingleFunction( segmentedDocument.segments[segmentId].value, 'boolean', 'public', self._getSegmentOffset(segmentedDocument, segmentId)); if (parseResult) { segmentedDocument.errors.push(parseResult); } } addSegment('classEnd', model.path, model, true); deferred.resolve(segmentedDocument); }) .catch(deferred.reject); return deferred.promise; }; BIPCodeEditorControl.prototype._SaveDocument = function (changedSegments) { var segment, segmentId; this._client.startTransaction(); for (segmentId in changedSegments) { segment = changedSegments[segmentId]; segmentId = segmentId.split('*'); switch (segmentId[0]) { case 'userImports': this._client.setAttribute(segmentId[1], 'forwards', segment); break; case 'userDefinitions': this._client.setAttribute(segmentId[1], 'definitions', segment); break; case 'userConstructors': this._client.setAttribute(segmentId[1], 'constructors', segment); break; case 'singleTransition': this._client.setAttribute(segmentId[1], 'transitionMethod', segment); break; case 'singleGuard': this._client.setAttribute(segmentId[1], 'guardMethod', segment); break; } } this._client.completeTransaction(); }; /* * * * * * * * Node Event Handling * * * * * * * */ //TODO needs a better change management BIPCodeEditorControl.prototype._eventCallback = function (events) { var self = this, componentRemoved = false, i; if (events.length > 1) { if (self._gatheringSegments) { self._missedEvents = true; } else { for (i = 0; i < events.length; i += 1) { if (events[i].eid === this._currentNodeId && events[i].etype === CONSTANTS.TERRITORY_EVENT_UNLOAD) { componentRemoved = true; break; } } if (componentRemoved !== true) { self._buildSegmentInfo(this._currentNodeId) .then(function (segmentedDocumentObject) { self._gatheringSegments = false; if (self._missedEvents) { self._missedEvents = false; self._eventCallback([{ eid: self._currentNodeId, etype: CONSTANTS.TERRITORY_EVENT_UPDATE }, {}]); } else { self._widget.setSegmentedDocument(segmentedDocumentObject); } }) .catch(function (err) { self._gatheringSegments = false; self._logger.error('error during segment info build:', err); if (self._missedEvents) { self._missedEvents = false; self._eventCallback([{ eid: self._currentNodeId, etype: CONSTANTS.TERRITORY_EVENT_UPDATE }, {}]); } }); } } } }; BIPCodeEditorControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) { if (this._currentNodeId === activeObjectId) { // The same node selected as before - do not trigger } else { this.selectedObjectChanged(activeObjectId); } }; /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */ BIPCodeEditorControl.prototype.destroy = function () { this._detachClientEventListeners(); this._removeToolbarItems(); }; BIPCodeEditorControl.prototype._attachClientEventListeners = function () { this._detachClientEventListeners(); WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this); }; BIPCodeEditorControl.prototype._detachClientEventListeners = function () { WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged); }; BIPCodeEditorControl.prototype.onActivate = function () { this._attachClientEventListeners(); this._displayToolbarItems(); if (typeof this._currentNodeId === 'string') { WebGMEGlobal.State.registerActiveObject(this._currentNodeId, {suppressVisualizerFromNode: true}); } }; BIPCodeEditorControl.prototype.onDeactivate = function () { this._detachClientEventListeners(); this._hideToolbarItems(); }; /* * * * * * * * * * Updating the toolbar * * * * * * * * * */ BIPCodeEditorControl.prototype._displayToolbarItems = function () { if (this._toolbarInitialized === true) { for (var i = this._toolbarItems.length; i--;) { this._toolbarItems[i].show(); } } else { this._initializeToolbar(); } }; BIPCodeEditorControl.prototype._hideToolbarItems = function () { if (this._toolbarInitialized === true) { for (var i = this._toolbarItems.length; i--;) { this._toolbarItems[i].hide(); } } }; BIPCodeEditorControl.prototype._removeToolbarItems = function () { if (this._toolbarInitialized === true) { for (var i = this._toolbarItems.length; i--;) { this._toolbarItems[i].destroy(); } } }; BIPCodeEditorControl.prototype._initializeToolbar = function () { // var self = this, // toolBar = WebGMEGlobal.Toolbar; this._toolbarItems = []; // this._toolbarItems.push(toolBar.addSeparator()); // // /************** Go to hierarchical parent button ****************/ // this.$btnModelHierarchyUp = toolBar.addButton({ // title: 'Go to parent', // icon: 'glyphicon glyphicon-circle-arrow-up', // clickFn: function (/*data*/) { // WebGMEGlobal.State.registerActiveObject(self._currentNodeParentId); // } // }); // this._toolbarItems.push(this.$btnModelHierarchyUp); // this.$btnModelHierarchyUp.hide(); // // /************** Checkbox example *******************/ // // this.$cbShowConnection = toolBar.addCheckBox({ // title: 'toggle checkbox', // icon: 'gme icon-gme_diagonal-arrow', // checkChangedFn: function (data, checked) { // self._logger.debug('Checkbox has been clicked!'); // } // }); // this._toolbarItems.push(this.$cbShowConnection); this._toolbarInitialized = true; }; return BIPCodeEditorControl; });