2 * Copyright © 2016-2017 European Support Limited
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 PropTypes from 'prop-types';
19 import Select from 'react-select';
21 import Common from '../../../../../../common/Common';
22 import Logger from '../../../../../../common/Logger';
24 import Icon from '../../../../../icons/Icon';
25 import iconSettings from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/settings.svg';
26 import iconExpanded from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/expanded.svg';
27 import iconCollapsed from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/collapsed.svg';
28 import iconOccurrenceDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/occurrence-default.svg';
29 import iconOccurrenceStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/occurrence-start.svg';
30 import iconOccurrenceStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/occurrence-stop.svg';
31 import iconFragmentDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/fragment-default.svg';
32 import iconFragmentStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/fragment-start.svg';
33 import iconFragmentStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icons/fragment-stop.svg';
38 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(
70 this.onMouseOut = this.onMouseOut.bind(this);
73 // ///////////////////////////////////////////////////////////////////////////////////////////////
77 * @param id message ID.
78 * @param position xy coordinates.
81 const message = this.props.model.getMessageById(id);
83 let occurrencesToggle = false;
84 let fragmentToggle = false;
86 message.occurrences = message.occurrences || {
90 message.occurrences.start = message.occurrences.start || [];
91 message.occurrences.stop = message.occurrences.stop || [];
92 message.fragment = message.fragment || {};
93 message.fragment.start = message.fragment.start || false;
94 message.fragment.stop = message.fragment.stop || false;
95 message.fragment.guard = message.fragment.guard || '';
96 message.fragment.operator = message.fragment.operator || '';
98 const mo = message.occurrences;
99 occurrencesToggle = mo.start.length > 0 || mo.stop.length > 0;
101 const mf = message.fragment;
102 fragmentToggle = mf.start || mf.stop;
116 // ///////////////////////////////////////////////////////////////////////////////////////////////
119 * Toggle occurrence state.
121 onClickOccurrenceToggle() {
122 const message = this.state.message;
124 const oFromState = Actions.getOccurrenceState(
128 const oToState = Actions.getOccurrenceState(
132 const oExpanded = oFromState > 0 || oToState > 0;
134 this.setState({ occurrencesExpanded: true });
136 const occurrencesExpanded = !this.state.occurrencesExpanded;
137 this.setState({ occurrencesExpanded });
142 // ///////////////////////////////////////////////////////////////////////////////////////////////
147 onClickOccurrenceFrom() {
148 const message = this.state.message;
150 Actions._toggleOccurrence(message.occurrences, message.from);
152 this.setState({ message });
153 this.props.application.renderDiagram();
156 // ///////////////////////////////////////////////////////////////////////////////////////////////
161 onClickOccurrenceTo() {
162 const message = this.state.message;
164 Actions._toggleOccurrence(message.occurrences, message.to);
166 this.setState({ message });
167 this.props.application.renderDiagram();
170 // ///////////////////////////////////////////////////////////////////////////////////////////////
175 onClickFragmentToggle() {
176 const message = this.state.message;
178 Actions._toggleFragment(message.fragment);
180 this.setState({ message });
181 this.props.application.renderDiagram();
184 // ///////////////////////////////////////////////////////////////////////////////////////////////
188 * @param event update event.
190 onChangeFragmentGuard(event) {
191 const message = this.state.message;
193 const options = this.props.application.getOptions();
194 message.fragment.guard = Common.sanitizeText(
200 this.setState({ message });
201 this.props.application.renderDiagram();
204 // ///////////////////////////////////////////////////////////////////////////////////////////////
208 * @param value updated value.
210 onChangeFragmentOperator(value) {
211 const message = this.state.message;
213 message.fragment.operator = value.value;
215 this.setState({ message });
216 this.props.application.renderDiagram();
219 // ///////////////////////////////////////////////////////////////////////////////////////////////
222 * Handle mouse movement.
225 this.setState({ id: -1, visible: false, x: 0, y: 0 });
228 // ///////////////////////////////////////////////////////////////////////////////////////////////
235 const actionsStyles = {};
236 const message = this.state.message;
237 if (!message || !this.state.visible) {
240 return <div className="asdcs-actions" />;
243 // Position and display.
245 actionsStyles.display = 'block';
246 actionsStyles.left = this.state.x - 10;
247 actionsStyles.top = this.state.y - 10;
249 const oFromState = Actions.getOccurrenceState(
253 const oToState = Actions.getOccurrenceState(
257 const fState = Actions.getFragmentState(message.fragment);
260 this.state.occurrencesExpanded || oFromState > 0 || oToState > 0;
261 const oAuxClassName = oExpanded ? '' : 'asdcs-hidden';
263 const fExpanded = fState !== 0;
264 const fAuxClassName = fExpanded ? '' : 'asdcs-hidden';
266 const fragmentOperatorOptions = [
281 const operator = message.fragment.operator || 'alt';
285 className="asdcs-actions"
286 style={actionsStyles}
287 onMouseLeave={this.onMouseOut}>
288 <div className="asdcs-actions-header">
289 <div className="asdcs-actions-icon">
290 <Icon glyph={iconSettings} />
294 <div className="asdcs-actions-options">
295 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence">
297 className="asdcs-actions-option asdcs-actions-option-occurrence-toggle"
298 onClick={this.onClickOccurrenceToggle}>
299 <span className="asdcs-label">Occurrence</span>
300 <div className="asdcs-actions-state">
302 glyph={iconCollapsed}
303 className={oExpanded ? 'asdcs-hidden' : ''}
307 className={oExpanded ? '' : 'asdcs-hidden'}
314 className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`}
315 onClick={this.onClickOccurrenceFrom}>
316 <span className="asdcs-label">From</span>
317 <div className="asdcs-actions-state">
318 <span className="asdcs-annotation" />
320 glyph={iconOccurrenceDefault}
322 oFromState === 0 ? '' : 'asdcs-hidden'
326 glyph={iconOccurrenceStart}
328 oFromState === 1 ? '' : 'asdcs-hidden'
332 glyph={iconOccurrenceStop}
334 oFromState === 2 ? '' : 'asdcs-hidden'
341 className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`}
342 onClick={this.onClickOccurrenceTo}>
343 <span className="asdcs-label">To</span>
344 <div className="asdcs-actions-state">
345 <span className="asdcs-annotation" />
347 glyph={iconOccurrenceDefault}
348 className={oToState === 0 ? '' : 'asdcs-hidden'}
351 glyph={iconOccurrenceStart}
352 className={oToState === 1 ? '' : 'asdcs-hidden'}
355 glyph={iconOccurrenceStop}
356 className={oToState === 2 ? '' : 'asdcs-hidden'}
361 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment">
363 className="asdcs-actions-option asdcs-actions-fragment-toggle"
364 onClick={this.onClickFragmentToggle}>
365 <span className="asdcs-label">Fragment</span>
366 <div className="asdcs-actions-state">
367 <span className="asdcs-annotation" />
369 glyph={iconFragmentDefault}
371 fState === 0 ? '' : 'asdcs-hidden'
375 glyph={iconFragmentStart}
377 fState === 1 ? '' : 'asdcs-hidden'
381 glyph={iconFragmentStop}
383 fState === 2 ? '' : 'asdcs-hidden'
391 className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}>
392 <div className="asdcs-label">Operator</div>
393 <div className="asdcs-value">
395 className="asdcs-editable-select"
400 onChange={this.onChangeFragmentOperator}
401 options={fragmentOperatorOptions}
407 className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}>
408 <div className="asdcs-label">Guard</div>
409 <div className="asdcs-value">
411 className="asdcs-editable"
415 value={message.fragment.guard}
416 placeholder="Condition"
417 onChange={this.onChangeFragmentGuard}
423 <div className="asdcs-actions-footer" />
428 // ///////////////////////////////////////////////////////////////////////////////////////////////
431 * Toggle through three occurrence states on click.
432 * @param occurrence occurrences state, updated as side-effect.
433 * @param lifelineId message end that's being toggled.
436 static _toggleOccurrence(occurrence, lifelineId) {
437 const o = occurrence;
439 const rm = function rm(array, value) {
440 const index = array.indexOf(value);
442 array.splice(index, 1);
446 const add = function add(array, value) {
447 if (array.indexOf(value) === -1) {
452 if (o.start && o.start.indexOf(lifelineId) !== -1) {
454 rm(o.start, lifelineId);
455 add(o.stop, lifelineId);
456 } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) {
458 rm(o.start, lifelineId);
459 rm(o.stop, lifelineId);
462 add(o.start, lifelineId);
463 rm(o.stop, lifelineId);
467 // ///////////////////////////////////////////////////////////////////////////////////////////////
470 * Toggle fragment setting on click.
474 static _toggleFragment(fragment) {
476 if (f.start === true) {
479 } else if (f.stop === true) {
490 // ///////////////////////////////////////////////////////////////////////////////////////////////
493 * Get ternary occurrences state.
494 * @param o occurrences.
495 * @param lifelineId from/to lifeline ID.
499 static getOccurrenceState(o, lifelineId) {
500 if (o.start.indexOf(lifelineId) !== -1) {
503 if (o.stop.indexOf(lifelineId) !== -1) {
509 // ///////////////////////////////////////////////////////////////////////////////////////////////
512 * Get ternary fragment state.
517 static getFragmentState(f) {
528 /** Element properties. */
529 Actions.propTypes = {
530 application: PropTypes.object.isRequired,
531 model: PropTypes.object.isRequired
534 export default Actions;