2 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
13 * or implied. See the License for the specific language governing
14 * permissions and limitations under the License.
17 import React from 'react';
18 import Select from 'react-select';
20 import Common from '../../../../../../common/Common';
21 import Logger from '../../../../../../common/Logger';
23 import Icon from '../../../../../icons/Icon';
24 import iconSettings from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/settings.svg';
25 import iconExpanded from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/expanded.svg';
26 import iconCollapsed from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg';
27 import iconOccurrenceDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg';
28 import iconOccurrenceStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg';
29 import iconOccurrenceStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg';
30 import iconFragmentDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg';
31 import iconFragmentStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg';
32 import iconFragmentStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg';
37 export default class Actions extends React.Component {
39 // ///////////////////////////////////////////////////////////////////////////////////////////////
43 * @param props element properties.
44 * @param context react context.
46 constructor(props, context) {
47 super(props, context);
58 this.show = this.show.bind(this);
60 this.onClickOccurrenceToggle = this.onClickOccurrenceToggle.bind(this);
61 this.onClickOccurrenceFrom = this.onClickOccurrenceFrom.bind(this);
62 this.onClickOccurrenceTo = this.onClickOccurrenceTo.bind(this);
64 this.onClickFragmentToggle = this.onClickFragmentToggle.bind(this);
65 this.onChangeFragmentGuard = this.onChangeFragmentGuard.bind(this);
66 this.onChangeFragmentOperator = this.onChangeFragmentOperator.bind(this);
68 this.onMouseOut = this.onMouseOut.bind(this);
71 // ///////////////////////////////////////////////////////////////////////////////////////////////
75 * @param id message ID.
76 * @param position xy coordinates.
79 const message = this.props.model.getMessageById(id);
81 let occurrencesToggle = false;
82 let fragmentToggle = false;
85 message.occurrences = message.occurrences || { start: [], stop: [] };
86 message.occurrences.start = message.occurrences.start || [];
87 message.occurrences.stop = message.occurrences.stop || [];
88 message.fragment = message.fragment || {};
89 message.fragment.start = message.fragment.start || false;
90 message.fragment.stop = message.fragment.stop || false;
91 message.fragment.guard = message.fragment.guard || '';
92 message.fragment.operator = message.fragment.operator || '';
94 const mo = message.occurrences;
95 occurrencesToggle = (mo.start.length > 0 || mo.stop.length > 0);
97 const mf = message.fragment;
98 fragmentToggle = (mf.start || mf.stop);
112 // ///////////////////////////////////////////////////////////////////////////////////////////////
115 * Toggle occurrence state.
117 onClickOccurrenceToggle() {
118 const message = this.state.message;
120 const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
121 const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
122 const oExpanded = oFromState > 0 || oToState > 0;
124 this.setState({ occurrencesExpanded: true });
126 const occurrencesExpanded = !this.state.occurrencesExpanded;
127 this.setState({ occurrencesExpanded });
132 // ///////////////////////////////////////////////////////////////////////////////////////////////
137 onClickOccurrenceFrom() {
138 const message = this.state.message;
140 Actions._toggleOccurrence(message.occurrences, message.from);
142 this.setState({ message });
143 this.props.application.renderDiagram();
146 // ///////////////////////////////////////////////////////////////////////////////////////////////
151 onClickOccurrenceTo() {
152 const message = this.state.message;
154 Actions._toggleOccurrence(message.occurrences, message.to);
156 this.setState({ message });
157 this.props.application.renderDiagram();
160 // ///////////////////////////////////////////////////////////////////////////////////////////////
165 onClickFragmentToggle() {
166 const message = this.state.message;
168 Actions._toggleFragment(message.fragment);
170 this.setState({ message });
171 this.props.application.renderDiagram();
174 // ///////////////////////////////////////////////////////////////////////////////////////////////
178 * @param event update event.
180 onChangeFragmentGuard(event) {
181 const message = this.state.message;
183 const options = this.props.application.getOptions();
184 message.fragment.guard = Common.sanitizeText(event.target.value, options, 'guard');
186 this.setState({ message });
187 this.props.application.renderDiagram();
190 // ///////////////////////////////////////////////////////////////////////////////////////////////
194 * @param value updated value.
196 onChangeFragmentOperator(value) {
197 const message = this.state.message;
199 message.fragment.operator = value.value;
201 this.setState({ message });
202 this.props.application.renderDiagram();
205 // ///////////////////////////////////////////////////////////////////////////////////////////////
208 * Handle mouse movement.
211 this.setState({ id: -1, visible: false, x: 0, y: 0 });
214 // ///////////////////////////////////////////////////////////////////////////////////////////////
222 const actionsStyles = { };
223 const message = this.state.message;
224 if (!message || !this.state.visible) {
228 return (<div className="asdcs-actions" ></div>);
231 // Position and display.
233 actionsStyles.display = 'block';
234 actionsStyles.left = this.state.x - 10;
235 actionsStyles.top = this.state.y - 10;
237 const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
238 const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
239 const fState = Actions.getFragmentState(message.fragment);
241 const oExpanded = this.state.occurrencesExpanded || (oFromState > 0) || (oToState > 0);
242 const oAuxClassName = oExpanded ? '' : 'asdcs-hidden';
244 const fExpanded = fState !== 0;
245 const fAuxClassName = fExpanded ? '' : 'asdcs-hidden';
247 const fragmentOperatorOptions = [{
258 const operator = message.fragment.operator || 'alt';
262 className="asdcs-actions"
263 style={actionsStyles}
264 onMouseLeave={this.onMouseOut}
266 <div className="asdcs-actions-header">
267 <div className="asdcs-actions-icon">
268 <Icon glyph={iconSettings} />
272 <div className="asdcs-actions-options">
274 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence">
276 className="asdcs-actions-option asdcs-actions-option-occurrence-toggle"
277 onClick={this.onClickOccurrenceToggle}
279 <span className="asdcs-label">Occurrence</span>
280 <div className="asdcs-actions-state">
281 <Icon glyph={iconCollapsed} className={oExpanded ? 'asdcs-hidden' : ''} />
282 <Icon glyph={iconExpanded} className={oExpanded ? '' : 'asdcs-hidden'} />
288 className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`}
289 onClick={this.onClickOccurrenceFrom}
291 <span className="asdcs-label">From</span>
292 <div className="asdcs-actions-state">
293 <span className="asdcs-annotation"></span>
294 <Icon glyph={iconOccurrenceDefault} className={oFromState === 0 ? '' : 'asdcs-hidden'} />
295 <Icon glyph={iconOccurrenceStart} className={oFromState === 1 ? '' : 'asdcs-hidden'} />
296 <Icon glyph={iconOccurrenceStop} className={oFromState === 2 ? '' : 'asdcs-hidden'} />
301 className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`}
302 onClick={this.onClickOccurrenceTo}
304 <span className="asdcs-label">To</span>
305 <div className="asdcs-actions-state">
306 <span className="asdcs-annotation"></span>
307 <Icon glyph={iconOccurrenceDefault} className={oToState === 0 ? '' : 'asdcs-hidden'} />
308 <Icon glyph={iconOccurrenceStart} className={oToState === 1 ? '' : 'asdcs-hidden'} />
309 <Icon glyph={iconOccurrenceStop} className={oToState === 2 ? '' : 'asdcs-hidden'} />
313 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment">
315 className="asdcs-actions-option asdcs-actions-fragment-toggle"
316 onClick={this.onClickFragmentToggle}
318 <span className="asdcs-label">Fragment</span>
319 <div className="asdcs-actions-state">
320 <span className="asdcs-annotation"></span>
321 <Icon glyph={iconFragmentDefault} className={fState === 0 ? '' : 'asdcs-hidden'} />
322 <Icon glyph={iconFragmentStart} className={fState === 1 ? '' : 'asdcs-hidden'} />
323 <Icon glyph={iconFragmentStop} className={fState === 2 ? '' : 'asdcs-hidden'} />
328 <div className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}>
329 <div className="asdcs-label">Operator</div>
330 <div className="asdcs-value">
332 className="asdcs-editable-select"
337 onChange={this.onChangeFragmentOperator}
338 options={fragmentOperatorOptions}
343 <div className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}>
344 <div className="asdcs-label">Guard</div>
345 <div className="asdcs-value">
347 className="asdcs-editable"
351 value={message.fragment.guard}
352 placeholder="Condition"
353 onChange={this.onChangeFragmentGuard}
360 <div className="asdcs-actions-footer"></div>
367 // ///////////////////////////////////////////////////////////////////////////////////////////////
370 * Toggle through three occurrence states on click.
371 * @param occurrence occurrences state, updated as side-effect.
372 * @param lifelineId message end that's being toggled.
375 static _toggleOccurrence(occurrence, lifelineId) {
376 const o = occurrence;
378 const rm = function rm(array, value) {
379 const index = array.indexOf(value);
381 array.splice(index, 1);
385 const add = function add(array, value) {
386 if (array.indexOf(value) === -1) {
391 if (o.start && o.start.indexOf(lifelineId) !== -1) {
393 rm(o.start, lifelineId);
394 add(o.stop, lifelineId);
395 } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) {
397 rm(o.start, lifelineId);
398 rm(o.stop, lifelineId);
401 add(o.start, lifelineId);
402 rm(o.stop, lifelineId);
406 // ///////////////////////////////////////////////////////////////////////////////////////////////
409 * Toggle fragment setting on click.
413 static _toggleFragment(fragment) {
415 if (f.start === true) {
418 } else if (f.stop === true) {
429 // ///////////////////////////////////////////////////////////////////////////////////////////////
432 * Get ternary occurrences state.
433 * @param o occurrences.
434 * @param lifelineId from/to lifeline ID.
438 static getOccurrenceState(o, lifelineId) {
439 if (o.start.indexOf(lifelineId) !== -1) {
442 if (o.stop.indexOf(lifelineId) !== -1) {
448 // ///////////////////////////////////////////////////////////////////////////////////////////////
451 * Get ternary fragment state.
456 static getFragmentState(f) {
467 /** Element properties. */
468 Actions.propTypes = {
469 application: React.PropTypes.object.isRequired,
470 model: React.PropTypes.object.isRequired,