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 {
40 // ///////////////////////////////////////////////////////////////////////////////////////////////
44 * @param props element properties.
45 * @param context react context.
47 constructor(props, context) {
48 super(props, context);
59 this.show = this.show.bind(this);
61 this.onClickOccurrenceToggle = this.onClickOccurrenceToggle.bind(this);
62 this.onClickOccurrenceFrom = this.onClickOccurrenceFrom.bind(this);
63 this.onClickOccurrenceTo = this.onClickOccurrenceTo.bind(this);
65 this.onClickFragmentToggle = this.onClickFragmentToggle.bind(this);
66 this.onChangeFragmentGuard = this.onChangeFragmentGuard.bind(this);
67 this.onChangeFragmentOperator = this.onChangeFragmentOperator.bind(this);
69 this.onMouseOut = this.onMouseOut.bind(this);
72 // ///////////////////////////////////////////////////////////////////////////////////////////////
76 * @param id message ID.
77 * @param position xy coordinates.
80 const message = this.props.model.getMessageById(id);
82 let occurrencesToggle = false;
83 let fragmentToggle = false;
86 message.occurrences = message.occurrences || { start: [], stop: [] };
87 message.occurrences.start = message.occurrences.start || [];
88 message.occurrences.stop = message.occurrences.stop || [];
89 message.fragment = message.fragment || {};
90 message.fragment.start = message.fragment.start || false;
91 message.fragment.stop = message.fragment.stop || false;
92 message.fragment.guard = message.fragment.guard || '';
93 message.fragment.operator = message.fragment.operator || '';
95 const mo = message.occurrences;
96 occurrencesToggle = (mo.start.length > 0 || mo.stop.length > 0);
98 const mf = message.fragment;
99 fragmentToggle = (mf.start || mf.stop);
113 // ///////////////////////////////////////////////////////////////////////////////////////////////
116 * Toggle occurrence state.
118 onClickOccurrenceToggle() {
119 const message = this.state.message;
121 const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
122 const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
123 const oExpanded = oFromState > 0 || oToState > 0;
125 this.setState({ occurrencesExpanded: true });
127 const occurrencesExpanded = !this.state.occurrencesExpanded;
128 this.setState({ occurrencesExpanded });
133 // ///////////////////////////////////////////////////////////////////////////////////////////////
138 onClickOccurrenceFrom() {
139 const message = this.state.message;
141 Actions._toggleOccurrence(message.occurrences, message.from);
143 this.setState({ message });
144 this.props.application.renderDiagram();
147 // ///////////////////////////////////////////////////////////////////////////////////////////////
152 onClickOccurrenceTo() {
153 const message = this.state.message;
155 Actions._toggleOccurrence(message.occurrences, message.to);
157 this.setState({ message });
158 this.props.application.renderDiagram();
161 // ///////////////////////////////////////////////////////////////////////////////////////////////
166 onClickFragmentToggle() {
167 const message = this.state.message;
169 Actions._toggleFragment(message.fragment);
171 this.setState({ message });
172 this.props.application.renderDiagram();
175 // ///////////////////////////////////////////////////////////////////////////////////////////////
179 * @param event update event.
181 onChangeFragmentGuard(event) {
182 const message = this.state.message;
184 const options = this.props.application.getOptions();
185 message.fragment.guard = Common.sanitizeText(event.target.value, options, 'guard');
187 this.setState({ message });
188 this.props.application.renderDiagram();
191 // ///////////////////////////////////////////////////////////////////////////////////////////////
195 * @param value updated value.
197 onChangeFragmentOperator(value) {
198 const message = this.state.message;
200 message.fragment.operator = value.value;
202 this.setState({ message });
203 this.props.application.renderDiagram();
206 // ///////////////////////////////////////////////////////////////////////////////////////////////
209 * Handle mouse movement.
212 this.setState({ id: -1, visible: false, x: 0, y: 0 });
215 // ///////////////////////////////////////////////////////////////////////////////////////////////
223 const actionsStyles = { };
224 const message = this.state.message;
225 if (!message || !this.state.visible) {
229 return (<div className="asdcs-actions" ></div>);
232 // Position and display.
234 actionsStyles.display = 'block';
235 actionsStyles.left = this.state.x - 10;
236 actionsStyles.top = this.state.y - 10;
238 const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
239 const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
240 const fState = Actions.getFragmentState(message.fragment);
242 const oExpanded = this.state.occurrencesExpanded || (oFromState > 0) || (oToState > 0);
243 const oAuxClassName = oExpanded ? '' : 'asdcs-hidden';
245 const fExpanded = fState !== 0;
246 const fAuxClassName = fExpanded ? '' : 'asdcs-hidden';
248 const fragmentOperatorOptions = [{
259 const operator = message.fragment.operator || 'alt';
263 className="asdcs-actions"
264 style={actionsStyles}
265 onMouseLeave={this.onMouseOut}
267 <div className="asdcs-actions-header">
268 <div className="asdcs-actions-icon">
269 <Icon glyph={iconSettings} />
273 <div className="asdcs-actions-options">
275 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence">
277 className="asdcs-actions-option asdcs-actions-option-occurrence-toggle"
278 onClick={this.onClickOccurrenceToggle}
280 <span className="asdcs-label">Occurrence</span>
281 <div className="asdcs-actions-state">
282 <Icon glyph={iconCollapsed} className={oExpanded ? 'asdcs-hidden' : ''} />
283 <Icon glyph={iconExpanded} className={oExpanded ? '' : 'asdcs-hidden'} />
289 className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`}
290 onClick={this.onClickOccurrenceFrom}
292 <span className="asdcs-label">From</span>
293 <div className="asdcs-actions-state">
294 <span className="asdcs-annotation"></span>
295 <Icon glyph={iconOccurrenceDefault} className={oFromState === 0 ? '' : 'asdcs-hidden'} />
296 <Icon glyph={iconOccurrenceStart} className={oFromState === 1 ? '' : 'asdcs-hidden'} />
297 <Icon glyph={iconOccurrenceStop} className={oFromState === 2 ? '' : 'asdcs-hidden'} />
302 className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`}
303 onClick={this.onClickOccurrenceTo}
305 <span className="asdcs-label">To</span>
306 <div className="asdcs-actions-state">
307 <span className="asdcs-annotation"></span>
308 <Icon glyph={iconOccurrenceDefault} className={oToState === 0 ? '' : 'asdcs-hidden'} />
309 <Icon glyph={iconOccurrenceStart} className={oToState === 1 ? '' : 'asdcs-hidden'} />
310 <Icon glyph={iconOccurrenceStop} className={oToState === 2 ? '' : 'asdcs-hidden'} />
314 <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment">
316 className="asdcs-actions-option asdcs-actions-fragment-toggle"
317 onClick={this.onClickFragmentToggle}
319 <span className="asdcs-label">Fragment</span>
320 <div className="asdcs-actions-state">
321 <span className="asdcs-annotation"></span>
322 <Icon glyph={iconFragmentDefault} className={fState === 0 ? '' : 'asdcs-hidden'} />
323 <Icon glyph={iconFragmentStart} className={fState === 1 ? '' : 'asdcs-hidden'} />
324 <Icon glyph={iconFragmentStop} className={fState === 2 ? '' : 'asdcs-hidden'} />
329 <div className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}>
330 <div className="asdcs-label">Operator</div>
331 <div className="asdcs-value">
333 className="asdcs-editable-select"
338 onChange={this.onChangeFragmentOperator}
339 options={fragmentOperatorOptions}
344 <div className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}>
345 <div className="asdcs-label">Guard</div>
346 <div className="asdcs-value">
348 className="asdcs-editable"
352 value={message.fragment.guard}
353 placeholder="Condition"
354 onChange={this.onChangeFragmentGuard}
361 <div className="asdcs-actions-footer"></div>
368 // ///////////////////////////////////////////////////////////////////////////////////////////////
371 * Toggle through three occurrence states on click.
372 * @param occurrence occurrences state, updated as side-effect.
373 * @param lifelineId message end that's being toggled.
376 static _toggleOccurrence(occurrence, lifelineId) {
377 const o = occurrence;
379 const rm = function rm(array, value) {
380 const index = array.indexOf(value);
382 array.splice(index, 1);
386 const add = function add(array, value) {
387 if (array.indexOf(value) === -1) {
392 if (o.start && o.start.indexOf(lifelineId) !== -1) {
394 rm(o.start, lifelineId);
395 add(o.stop, lifelineId);
396 } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) {
398 rm(o.start, lifelineId);
399 rm(o.stop, lifelineId);
402 add(o.start, lifelineId);
403 rm(o.stop, lifelineId);
407 // ///////////////////////////////////////////////////////////////////////////////////////////////
410 * Toggle fragment setting on click.
414 static _toggleFragment(fragment) {
416 if (f.start === true) {
419 } else if (f.stop === true) {
430 // ///////////////////////////////////////////////////////////////////////////////////////////////
433 * Get ternary occurrences state.
434 * @param o occurrences.
435 * @param lifelineId from/to lifeline ID.
439 static getOccurrenceState(o, lifelineId) {
440 if (o.start.indexOf(lifelineId) !== -1) {
443 if (o.stop.indexOf(lifelineId) !== -1) {
449 // ///////////////////////////////////////////////////////////////////////////////////////////////
452 * Get ternary fragment state.
457 static getFragmentState(f) {
468 /** Element properties. */
469 Actions.propTypes = {
470 application: PropTypes.object.isRequired,
471 model: PropTypes.object.isRequired,
474 export default Actions;