State.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2014
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "State.h"
24
25#include <cmath>
26
27#include <IceUtil/UUID.h>
28
30
35
37{
38 State::State(const QString& uuid) :
39 QObject(),
40 margin(30, 140, 30, 30),
41 size(StateInstance::StateDefaultSize),
42 dirty(false),
43 editable(true),
44 active(false)
45 {
46 UUID = uuid.isEmpty() ? QString::fromStdString(IceUtil::generateUUID()) : uuid;
48 connect(this,
50 this,
51 SLOT(setDirty(statechartmodel::SignalType)));
52 connect(
53 this,
55 this,
57 connect(
58 this,
60 this,
62 }
63
65 {
66 emit stateDeleted();
67 }
68
69 void
70 State::addReferences(const QMap<QString, StatePtr>& uuidStateMap)
71 {
73
74 for (StateInstanceMap::const_iterator i = substates.begin(); i != substates.end(); ++i)
75 {
76 std::shared_ptr<RegularState> regularState =
77 std::dynamic_pointer_cast<RegularState>(*i); // ugly
78
79 if (regularState && !regularState->getStateClass())
80 {
81 const QString& substateUUID = regularState->getClassUUID();
82
83 if (uuidStateMap.contains(substateUUID))
84 {
85 regularState->setStateClass(uuidStateMap[substateUUID]);
86 }
87 }
88 }
89
91 // TODO: Now we can add all detached transitions to state instances
92 }
93
96 {
98
99 for (auto p : localParameters.toStdMap())
100 {
101 result.insert(p.first, p.second);
102 }
103
104 return result;
105 }
106
108 State::getTransitions(bool withStartTransition) const
109 {
110 CTransitionList result;
111 foreach (TransitionPtr t, transitions)
112 {
113 if (withStartTransition || t->sourceState)
114 {
115 result.append(t);
116 }
117 }
118 return result;
119 }
120
121 void
122 State::setStateName(const QString& newName)
123 {
124 if (stateName == newName)
125 {
127 }
128 else
129 {
130 stateName = newName;
132 }
133 }
134
137 {
139 return t ? t->destinationState : StateInstancePtr();
140 }
141
144 {
146 return t ? t->mappingToNextStatesInput : ParameterMappingList();
147 }
148
151 {
152 auto events = getOutgoingEvents();
153 for (const StateInstancePtr& substate : getSubstates())
154 {
155 if (substate->getType() == eFinalState)
156 {
157 bool found = false;
158 for (EventPtr& event : events)
159 {
160 if (event->name == substate->getInstanceName())
161 {
162 found = true;
163 break;
164 }
165 }
166 if (!found)
167 {
168 EventPtr evt(new Event());
169 evt->name = substate->getInstanceName();
170 events.push_back(evt);
171 }
172 }
173 }
174 return events;
175 }
176
179 {
180 foreach (TransitionPtr t, transitions)
181 {
182 if (!t->sourceState)
183 {
184 return t;
185 }
186 }
187
188 return TransitionPtr();
189 }
190
193 {
194 foreach (TransitionPtr t, transitions)
195 {
196 if (!t->sourceState)
197 {
198 return t;
199 }
200 }
201
202 return TransitionPtr();
203 }
204
205 void
207 {
208 foreach (StateInstancePtr instance, substates)
209 {
210 if (instance->getStateClass())
211 {
212 connect(instance->getStateClass().get(),
215 this,
216 SLOT(updateTransition(
218 Qt::UniqueConnection);
219 }
220 }
221 }
222
223 bool
225 {
226 return editable;
227 }
228
229 void
230 State::setDescription(const QString& newDescription)
231 {
232 if (description == newDescription)
233 {
235 }
236 else
237 {
238 description = newDescription;
240 }
241 }
242
243 void
244 State::setSize(const QSizeF& newSize)
245 {
246
247 // ARMARX_INFO_S << "new size of " << stateName << ": " << newSize.width() << ", " << newSize.height() ;
248 if (size == newSize)
249 {
251 }
252 else
253 {
254 size = newSize;
256 emit resized();
257 }
258 }
259
260 void
261 State::setSubstateAreaSize(const QSizeF& newSize)
262 {
263 QSizeF adjustedNewSize(newSize.width() + margin.left() + margin.width(),
264 newSize.height() + margin.top() + margin.height());
265 setSize(adjustedNewSize);
266 }
267
268 void
270 {
271 this->editable = editable;
272 }
273
275 State::addSubstate(StatePtr newSubstate, QString instanceName, const QPointF& pos)
276 {
277 ARMARX_CHECK_EXPRESSION(newSubstate);
278
279 if (!checkSubstate(newSubstate))
280 {
281 return StateInstancePtr();
282 }
283
284 if (instanceName.length() == 0)
285 {
286 instanceName = newSubstate->getStateName();
287 }
288
289 if (substates.find(instanceName) != substates.end())
290 {
291 return StateInstancePtr();
292 }
293
294 StateInstancePtr instance(new LocalState(newSubstate, instanceName, shared_from_this()));
295
296 instance = addSubstate(instance);
297
298 if (instance)
299 {
300 if (pos.x() != 0 && pos.y() != 0)
301 {
302 instance->setPosition(pos);
303 }
304
305 connect(newSubstate.get(),
308 this,
309 SLOT(updateTransition(
311 Qt::UniqueConnection);
312 addDetachedTransitions(instance);
313 }
314
315 return instance;
316 }
317
320 const QString& remoteStateOffererName,
321 QString instanceName,
322 const QPointF& pos)
323 {
324 ARMARX_CHECK_EXPRESSION(newRemoteSubstate);
325
326 if (!checkSubstate(newRemoteSubstate))
327 {
328 return StateInstancePtr();
329 }
330
331 if (instanceName.length() == 0)
332 {
333 instanceName = newRemoteSubstate->getStateName();
334 }
335
336 StateInstancePtr instance(new RemoteState(
337 newRemoteSubstate, instanceName, remoteStateOffererName, shared_from_this()));
338
339
340 instance = addSubstate(instance);
341
342 if (instance)
343 {
344 if (pos.x() != 0 && pos.y() != 0)
345 {
346 instance->setPosition(pos);
347 }
348
349 connect(newRemoteSubstate.get(),
352 this,
353 SLOT(updateTransition(
355 Qt::UniqueConnection);
356 addDetachedTransitions(instance);
357 }
358
359 return instance;
360 }
361
363 State::addDynamicRemoteSubstate(StatePtr state, QString instanceName, const QPointF& pos)
364
365 {
366
367 if (!checkSubstate(state))
368 {
369 return StateInstancePtr();
370 }
371
372 if (instanceName.length() == 0)
373 {
374 instanceName = state->getStateName();
375 }
376
377 if (substates.find(instanceName) != substates.end())
378 {
379 return StateInstancePtr();
380 }
381
382 StateInstancePtr newstateInstance(
383 new DynamicRemoteState(state, instanceName, shared_from_this()));
384
385 newstateInstance = addSubstate(newstateInstance);
386
387 if (newstateInstance)
388 {
389
390 if (pos.x() != 0 && pos.y() != 0)
391 {
392 newstateInstance->setPosition(pos);
393 }
394
395 connect(newstateInstance->getStateClass().get(),
397 this,
398 SLOT(updateTransition(QString, StatePtr, SignalType)),
399 Qt::UniqueConnection);
400
401 addDetachedTransitions(newstateInstance);
402 }
403
404 return newstateInstance;
405 }
406
408 State::addEndSubstate(const QString& endstateName, const QString& eventName, const QPointF& pos)
409 {
410 StateInstancePtr instance(new EndState(endstateName, eventName, shared_from_this()));
411 instance = addSubstate(instance);
412
413 if (instance)
414 {
415 if (pos.x() != 0 && pos.y() != 0)
416 {
417 instance->setPosition(pos);
418 }
419
420 emit outgoingTransitionChanged(eventName, shared_from_this(), eAdded);
421 }
422
423 return instance;
424 }
425
428 {
429 if (substates.find(stateInstance->getInstanceName()) != substates.end())
430 {
431 return StateInstancePtr();
432 }
433 if (stateInstance->getStateClass() && !checkSubstate(stateInstance->getStateClass()))
434 {
435 return StateInstancePtr();
436 }
437
438 substates.insert(stateInstance->getInstanceName(), stateInstance);
439
440
441 emit substateChanged(stateInstance, eAdded);
442
443 if (substates.size() == 1) //needs to go after statechanged-> otherwise crash
444 {
445 setStartState(stateInstance);
446 }
447
448 return stateInstance;
449 }
450
451 void
453 {
455
456 if (!t)
457 {
458 ARMARX_WARNING << "No start transition found!";
459 return;
460 }
461
462 if (t->destinationState == newStartState)
463 {
465 }
466 else
467 {
468 t->destinationState = newStartState;
469 t->supportPoints.controlPoints.clear();
470 t->supportPoints.endPoint.reset();
471 t->supportPoints.startPoint.reset();
473 }
474 }
475
476 void
478 {
480
481 if (!t)
482 {
483 ARMARX_WARNING << "No start transition found!";
484 return;
485 }
486
487 if (t->mappingToNextStatesInput == newStartStateInputMapping)
488 {
490 }
491 else
492 {
493 t->mappingToNextStatesInput = newStartStateInputMapping;
495 }
496 }
497
498 bool
499 State::renameSubstate(QString oldName, QString newName)
500 {
501 if (substates.find(newName) != substates.end())
502 {
503 return false;
504 }
505
506 StateInstanceMap::iterator it = substates.find(oldName);
507
508 if (it != substates.end())
509 {
510 EndStatePtr endState = std::dynamic_pointer_cast<EndState>(it.value());
511
512 if (endState)
513 {
515 endState->getEventName(), shared_from_this(), eRemoved);
516 }
517
518 it.value()->setInstanceName(newName);
519 StateInstanceMap::iterator newIt = substates.insert(newName, it.value());
520 substates.remove(oldName);
521
522 if (endState)
523 {
525 endState->getEventName(), shared_from_this(), eAdded);
526 }
527
528 emit substateChanged(newIt.value(), eChanged);
529 }
530
531 return true;
532 }
533
534 bool
536 {
537 if (!substate)
538 {
539 return false;
540 }
541
542 return removeSubstate(substate->getInstanceName());
543 }
544
545 bool
546 containsOutgoingEvent(const QString& eventName, const EventList& events)
547 {
548 for (const EventPtr& evt : events)
549 {
550 if (evt->name == eventName)
551 {
552 return true;
553 }
554 }
555 return false;
556 }
557
558 bool
559 State::removeSubstate(QString stateInstanceName)
560 {
561 StateInstanceMap::iterator it = substates.find(stateInstanceName);
562
563 if (it != substates.end())
564 {
565 foreach (TransitionPtr t, transitions)
566 {
567 if (t->sourceState &&
568 t->sourceState ==
569 it.value() // reflexive edges should not be detached but removed
570 && t->destinationState == it.value())
571 {
573 }
574 else if (t->destinationState == it.value() && t->sourceState)
575 {
577 t, calcDetachedTransitionLastControlPoint(t->sourceState));
578 }
579 else if (t->destinationState == it.value())
580 {
582 }
583 else if (t->sourceState == it.value())
584 {
586 }
587 }
588 EndStatePtr endState = std::dynamic_pointer_cast<EndState>(it.value());
589
590 if (endState)
591 {
593 endState->getEventName(), shared_from_this(), eRemoved);
594 }
595
596 substates.erase(it);
597 emit substateChanged(it.value(), eRemoved);
598 return true;
599 }
600 else
601 {
602 return false;
603 }
604 }
605
607 State::replaceSubstate(QString stateInstanceName, StateInstancePtr newInstance)
608 {
609 StateInstanceMap::iterator it = substates.find(stateInstanceName);
610
611 if (it != substates.end())
612 {
613 // TODO: This should also try to keep all transitions
614 if (newInstance->getStateClass() && !checkSubstate(newInstance->getStateClass()))
615 {
616 return StateInstancePtr();
617 }
618 removeSubstate(stateInstanceName);
619 newInstance->setPosition(it.value()->getTopLeft());
620 return addSubstate(newInstance);
621 }
622
623 return StateInstancePtr();
624 }
625
626 void
628 {
629 while (!substates.empty())
630 {
631 removeSubstate(substates.begin().key());
632 }
633
634 substates = newSubstateList;
635
636 foreach (StateInstancePtr instance, substates)
637 {
638 if (instance->getStateClass())
639 {
640 connect(instance->getStateClass().get(),
643 this,
644 SLOT(updateTransition(
646 Qt::UniqueConnection);
647 }
648
649 emit substateChanged(instance, eAdded);
650 addDetachedTransitions(instance);
651 }
652 }
653
654 void
656 {
657 if (activeSubstate == newActiveState)
658 {
660 }
661 else
662 {
663 // ARMARX_INFO << "Setting new substate of state " << getStateName();
664 auto tempState = activeSubstate;
665 activeSubstate = newActiveState;
666 if (tempState)
667 {
668 emit substateChanged(tempState, eChanged);
669 }
671 if (newActiveState)
672 {
673 emit substateChanged(newActiveState, eChanged);
674 }
675 }
676 }
677
678 void
680 {
681 if (activeSubstate && activeSubstate->getStateClass())
682 {
683 activeSubstate->getStateClass()->clearActiveSubstates();
684 }
685 auto tempState = activeSubstate;
686 activeSubstate.reset();
687 if (tempState)
688 {
689 // tempState->setActive(false);
690 emit substateChanged(tempState, eChanged);
691 }
693 }
694
695 void
697 {
698 // TODO: This should allow for a more fine-granular set operation and emit the signal more intelligently
699 auto keys = newInputParameters.keys();
700
701 for (const auto& key : keys)
702 {
703 if (localParameters.count(key) > 0)
704 {
705 throw LocalException("Key ")
706 << key << " is already used in localParameters in state " << stateName;
707 }
708 }
709
710 inputParameters = newInputParameters;
712 }
713
714 void
716 {
717 // TODO: This should allow for a more fine-granular set operation and emit the signal more intelligently
718 auto keys = newLocalParameters.keys();
719
720 for (const auto& key : keys)
721 {
722 if (inputParameters.count(key) > 0)
723 {
724 throw LocalException("Key ")
725 << key << " is already used in inputParameters in state " << stateName;
726 }
727 }
728
729 localParameters = newLocalParameters;
731 }
732
733 void
735 {
736 // TODO: This should allow for a more fine-granular set operation and emit the signal more intelligently
737 outputParameters = newOutputParameters;
739 }
740
741 void
743 {
744 if (!checkTransition(newTransition))
745 {
746 return;
747 }
748
749 transitions.push_back(newTransition);
750 emit transitionChanged(newTransition, eAdded);
751 }
752
753 void
755 const ParameterMappingList& mappingToNextStateInput,
756 const ParameterMappingList& mappingToParentLocal,
757 const ParameterMappingList& mappingToParentOutput)
758 {
759 TransitionPtr t = findTransition(transition);
760
761 if (t)
762 {
763 t->mappingToNextStatesInput = mappingToNextStateInput;
764 t->mappingToParentStatesLocal = mappingToParentLocal;
765 t->mappingToParentStatesOutput = mappingToParentOutput;
767 }
768 else
769 {
770 throw LocalException("Could not find transition in state");
771 }
772 }
773
774 void
776 const SupportPoints& points,
777 const QPointPtr& labelCenterPosition,
778 const FloatPtr& labelFontPointSize)
779 {
780 TransitionPtr t = findTransition(transition);
781
782 if (t)
783 {
784 auto oldPoints = t->supportPoints.toPointList();
785 auto newPoints = points.toPointList();
786 bool changed = newPoints.size() != oldPoints.size();
787
788 if (!changed)
789 {
790 int size = oldPoints.size();
791
792 for (int i = 0; i < size; ++i)
793 {
794 if ((oldPoints.at(i) - newPoints.at(i)).manhattanLength() > 2)
795 {
796 changed = true;
797 break;
798 }
799 }
800 }
801 t->labelCenterPosition = labelCenterPosition;
802 t->labelFontPointSize = labelFontPointSize;
803 t->supportPoints = points;
804 emit transitionChanged(t, changed ? eChanged : eUnchanged);
805 }
806 else
807 {
808 throw LocalException("Could not find transition in state");
809 }
810 }
811
812 void
814 {
815 emit transitionChanged(transition, eActivated);
816 }
817
818 void
820 {
821 TransitionPtr t = findTransition(transition);
822
823 if (t)
824 {
825 t->transitionUserCode = enabled;
827 }
828 else
829 {
830 throw LocalException("Could not find transition in state");
831 }
832 }
833
834 void
835 State::addDetachedTransition(const QString& eventName, StateInstancePtr sourceState)
836 {
837 if (!sourceState)
838 {
839 return;
840 }
841
842 TransitionPtr t(new Transition());
843 t->sourceState = sourceState;
844 t->eventName = eventName;
845
846 QPointF lastControlPoint = calcDetachedTransitionLastControlPoint(sourceState);
847 t->supportPoints.controlPoints.append(lastControlPoint);
848 t->supportPoints.endPoint = std::make_shared<QPointF>(
849 calcDetachedTransitionEndPoint(sourceState, lastControlPoint));
850 addTransition(t);
851 }
852
853 void
855 StateInstancePtr newDest,
856 QPointList newSupportPoints)
857 {
858 foreach (TransitionPtr t, transitions)
859 {
860 if (t.get() == transition.get())
861 {
862 if (transition->destinationState == newDest)
863 {
864 return;
865 }
866 // if(!t->destinationState)
867 t->supportPoints = SupportPoints(newSupportPoints);
868 t->destinationState = newDest;
869
870 if (t->destinationState == t->sourceState) // reflexive edge
871 {
872 QPointF p = calcDetachedTransitionLastControlPoint(t->sourceState);
873 QPointList controlPoints;
874 controlPoints.push_back(p - QPointF(30, 30));
875 controlPoints.push_back(p);
876 controlPoints.push_back(p + QPointF(30, 30));
877
878 t->supportPoints.controlPoints = controlPoints;
879 }
880 else
881 {
882 t->supportPoints.controlPoints.clear();
883 t->supportPoints.endPoint.reset();
884 t->supportPoints.startPoint.reset();
885 bendTransition(t, 50, (rand() % 20) - 10);
886 }
887
888 if (!t->destinationState->getStateClass())
889 {
891 }
892
894 }
895 }
896 }
897
898 void
899 State::detachTransitionDestination(TransitionCPtr transition, QPointF floatingEndPoint)
900 {
901 // if(!transition->destinationState)
902 // return;
903 TransitionPtr t = findTransition(transition);
904
905 if (t)
906 {
907 ARMARX_INFO << "Detaching transition " << t->eventName;
908 t->supportPoints = SupportPoints(QPointList({floatingEndPoint}));
909 if (t->sourceState)
910 {
911 t->supportPoints.endPoint = std::make_shared<QPointF>(
912 calcDetachedTransitionEndPoint(t->sourceState, floatingEndPoint));
913 }
914 t->destinationState.reset();
915 t->labelCenterPosition.reset();
917 }
918 }
919
920 void
922 {
923 if (transition->sourceState)
924 {
926 transition, calcDetachedTransitionLastControlPoint(transition->sourceState));
927 }
928 }
929
930 void
932 {
934
935 while (!transitions.empty())
936 {
938 }
939
940 transitions = newTransitionList;
941 transitions.push_front(startT ? startT : TransitionPtr(new Transition()));
942
943 foreach (TransitionPtr t, transitions)
944 {
945 emit transitionChanged(t, eAdded);
946 }
947 }
948
949 void
950 State::addSupportPoint(TransitionCPtr transition, QPointF supportPoint)
951 {
952 ARMARX_ERROR_S << "NYI";
953 // auto t = findTransition(transition);
954 // float minDist = std::numeric_limits<float>::max();
955 // int index = -1;
956 // QList<QPointF> list = t->supportPoints;
957 // if(t->sourceState)
958 // list.push_front(t->sourceState->getBounds().center());
959 // if(t->destinationState)
960 // list.push_back(t->destinationState->getBounds().center());
961 // for(int i = 0; i < t->supportPoints.size(); i++)
962 // {
963 // const QPointF& curP = list.at(i);
964 // float d = (curP-supportPoint).manhattanLength();
965
966 // if(d < minDist)
967 // {
968 // minDist = d;
969 // index = i;
970 // }
971 // ARMARX_INFO_S << VAROUT(index) << " " << VAROUT(d);
972 // }
973 // float prevDistance = index> 0 ? (list.at(index-1)-supportPoint).manhattanLength() : std::numeric_limits<float>::max();
974 // float distanceToNext = index< list.size()-1 ? (list.at(index+1)-supportPoint).manhattanLength() : std::numeric_limits<float>::max();
975 // if(prevDistance < distanceToNext)
976 // list.insert(index, supportPoint);
977 // else
978 // list.insert(index+1, supportPoint);
979 // if(t->sourceState)
980 // list.pop_front();
981 // if(t->destinationState)
982 // list.pop_back();
983 // t->supportPoints = list;
984 // emit transitionChanged(t, eChanged);
985 }
986
987 void
988 State::setOutgoingEvents(const EventList& outgoingEvents)
989 {
990 auto checkEventExistsInSubstates = [&, this](EventPtr& e)
991 {
992 for (const StateInstancePtr& substate : substates)
993 {
994 if (substate->getType() == eFinalState)
995 {
996 EndStateCPtr endstate = std::dynamic_pointer_cast<const EndState>(substate);
997
998 if (endstate && endstate->getEventName() == e->name)
999 {
1000 return true;
1001 }
1002 }
1003 }
1004
1005 return false;
1006 };
1007
1008 if (this->outgoingTransitions == outgoingEvents)
1009 {
1011 }
1012 else
1013 {
1014 auto oldTransitions = outgoingTransitions;
1015 this->outgoingTransitions = outgoingEvents;
1016 // notify for new events
1017 foreach (EventPtr ev, outgoingEvents)
1018 {
1019 bool found = false;
1020 foreach (EventPtr evOld, oldTransitions)
1021 {
1022 if (evOld->name == ev->name)
1023 {
1024 found = true;
1025 }
1026 }
1027
1028 if (!found && !checkEventExistsInSubstates(ev))
1029 {
1030 emit outgoingTransitionChanged(ev->name, shared_from_this(), eAdded);
1031 }
1032 }
1033 // notify for removed events
1034 foreach (EventPtr evOld, oldTransitions)
1035 {
1036 bool found = false;
1037 foreach (EventPtr ev, outgoingEvents)
1038 {
1039 if (evOld->name == ev->name)
1040 {
1041 found = true;
1042 }
1043 }
1044
1045 if (!found && !checkEventExistsInSubstates(evOld))
1046 {
1047 emit outgoingTransitionChanged(evOld->name, shared_from_this(), eRemoved);
1048 }
1049 }
1050
1051
1052 emit stateChanged(eChanged);
1053 }
1054 }
1055
1056 void
1057 State::updateTransition(const QString& eventName, StatePtr stateClass, SignalType signalType)
1058 {
1059 ARMARX_INFO_S << getStateName() << " was updated by substate "
1060 << stateClass->getStateName();
1061
1062 // TODO: Rename transitions is buggy
1063 switch (signalType)
1064 {
1065 case eAdded:
1066 {
1067 QList<StateInstancePtr> instances = getInstances(stateClass);
1068 foreach (StateInstancePtr instance, instances)
1069 {
1070 addDetachedTransition(eventName, instance);
1071 }
1072 }
1073 break;
1074
1075 case eRemoved:
1076 {
1077 ARMARX_INFO_S << "Removing transitions for event " << eventName;
1078 QList<StateInstancePtr> instances = getInstances(stateClass);
1079 foreach (StateInstancePtr instance, instances)
1080 {
1081 TransitionPtr t = getTransition(eventName, instance);
1082
1083 if (t && !containsOutgoingEvent(eventName, stateClass->getOutgoingEvents()))
1084 {
1086 }
1087 }
1088 }
1089
1090 break;
1091
1092 default:
1093
1094 break;
1095 }
1096 }
1097
1098 void
1099 State::setDirty(SignalType signalType)
1100 {
1101 if (signalType != eUnchanged)
1102 {
1103 setDirty(true);
1104 }
1105 }
1106
1107 void
1108 State::setDirty(StateInstancePtr substate, SignalType signalType)
1109 {
1110 if (signalType != eUnchanged)
1111 {
1112 setDirty(true);
1113 }
1114 }
1115
1116 void
1117 State::setDirty(TransitionCPtr transition, SignalType signalType)
1118 {
1119 if (signalType != eUnchanged)
1120 {
1121 setDirty(true);
1122 }
1123 }
1124
1125 void
1126 State::setDirty(bool dirty)
1127 {
1128 if (this->dirty != dirty)
1129 {
1131 }
1132
1133 this->dirty = dirty;
1134 }
1135
1136 QList<StateInstancePtr>
1138 {
1139 QList<StateInstancePtr> result;
1140
1141 for (StateInstanceMap::const_iterator s = substates.begin(); s != substates.end(); s++)
1142 {
1143 if (s.value()->getStateClass() == stateClass)
1144 {
1145 result.push_back(s.value());
1146 }
1147 }
1148
1149 return result;
1150 }
1151
1153 State::getTransition(const QString& eventName, StateInstancePtr sourceInstance) const
1154 {
1155 foreach (TransitionPtr t, transitions)
1156 {
1157 if (t->eventName == eventName && t->sourceState == sourceInstance)
1158 {
1159 return t;
1160 }
1161 }
1162 return TransitionPtr();
1163 }
1164
1165 bool
1167 {
1168 int index = transitions.indexOf(transition);
1169
1170 if (index != -1)
1171 {
1172 // ARMARX_INFO_S << "Removing transitions for event " << transition->eventName
1173 // << " from " << (transition->sourceState ? transition->sourceState->getInstanceName() : "None")
1174 // << " to " << (transition->destinationState ? transition->destinationState->getInstanceName() : "None");
1175 emit transitionChanged(transition, eRemoved);
1176 transitions.erase(transitions.begin() + index);
1177 return true;
1178 }
1179
1180 return false;
1181 }
1182
1183 bool
1185 {
1186 if (!transition)
1187 {
1188 ARMARX_WARNING << "Transition must not be NULL";
1189 return false;
1190 }
1191
1192 TransitionPtr t = getTransition(transition->eventName, transition->sourceState);
1193
1194 if (t)
1195 {
1196 ARMARX_WARNING << "Transition with event " << transition->eventName << " for state "
1197 << transition->sourceState->getInstanceName() << " already exists";
1198 return false;
1199 }
1200
1201 if (!transition->destinationState && transition->supportPoints.controlPoints.size() == 0)
1202 {
1204 << "If no destination is set for a transition, it must have 1 support point";
1205 return false;
1206 }
1207
1208 if (!transition->sourceState)
1209 {
1210 ARMARX_WARNING << "A Transition must have a source start";
1211 return false;
1212 }
1213
1214 return true;
1215 }
1216
1217 bool
1219 {
1220 ARMARX_INFO << "UUID parent: " << getUUID() << " new: " << newState->getUUID();
1221
1222 if (getUUID() == newState->getUUID())
1223 {
1224 return false;
1225 }
1226 return true;
1227 }
1228
1231 {
1232 for (int i = 0; i < transitions.size(); i++)
1233 {
1234 if (t.get() == transitions.at(i).get())
1235 {
1236 return transitions.at(i);
1237 }
1238 }
1239
1240 return TransitionPtr();
1241 }
1242
1244 State::findTransition(const QString& eventName,
1245 const QString& transitionSourceName,
1246 const QString& transitionDestinationName) const
1247 {
1248 for (const TransitionPtr& t : transitions)
1249 {
1250 if (t->eventName == eventName &&
1251 t->sourceState->getInstanceName() == transitionSourceName &&
1252 t->destinationState->getInstanceName() == transitionDestinationName)
1253 {
1254 return t;
1255 }
1256 }
1257 return TransitionPtr();
1258 }
1259
1260 bool
1262 {
1263 if (!sC)
1264 {
1265 return false;
1266 }
1267
1268 for (auto it = substates.begin(); it != substates.end(); it++)
1269 {
1270 StateInstancePtr state = (it.value());
1271 if (!state)
1272 {
1273 continue;
1274 }
1275 if (!state->getStateClass())
1276 {
1277 continue;
1278 }
1279
1280 if (state->getStateClass()->getUUID() == sC->getUUID())
1281 {
1282 return true;
1283 }
1284
1285 if (state->getStateClass()->hasDescendant(sC))
1286 {
1287 return true;
1288 }
1289 }
1290 return false;
1291 }
1292
1293 QString
1295 {
1296 switch (type)
1297 {
1298 case eNormalState:
1299 return "Normal State";
1300 break;
1301
1302 case eRemoteState:
1303 return "Remote State";
1304 break;
1305
1306 case eDynamicRemoteState:
1307 return "Dynamic Remote State";
1308 break;
1309
1310 case eFinalState:
1311 return "Final State";
1312 break;
1313
1314 case eUndefined:
1315 return "";
1316 break;
1317
1318 default:
1319 return "Unknown State Type";
1320 }
1321 }
1322
1323 void
1324 State::addDetachedTransitions(StateInstancePtr instance)
1325 {
1326 if (!instance->getStateClass())
1327 {
1328 return; // This not only happens for end states but also the class-reference is not existing during loading
1329 }
1330
1331 QList<EventPtr> events = instance->getStateClass()->getAllEvents();
1332
1333 float angleStep = 20;
1334 float length = instance->getClassSize().width() * instance->getScale() * 0.8f;
1335 QPointF center = instance->getBounds().center();
1336 int count = events.size();
1337 float startAngle = angleStep * (count - 1) / 2.0f;
1338
1339 float angle = startAngle;
1340
1341 foreach (EventPtr event, events)
1342 {
1343 TransitionPtr t(new Transition());
1344 t->sourceState = instance;
1345 t->eventName = event->name;
1346 t->supportPoints.append(center + QPointF(cos(angle / 180.0 * M_PI) * length,
1347 sin(angle / 180.0 * M_PI) * length));
1348 addTransition(t);
1349 angle -= angleStep;
1350 }
1351 }
1352
1353 QPointF
1354 State::calcDetachedTransitionLastControlPoint(StateInstancePtr instance) const
1355 {
1356 QPointF p;
1357 float angle = ((double)(rand() % 360));
1358 float length =
1359 std::max(instance->getClassSize().width(), instance->getClassSize().height());
1360 length *= instance->getScale() * 0.8;
1361 // ARMARX_INFO << VAROUT(angle) << " " << VAROUT(length);
1362 p = instance->getBounds().center();
1363 // ARMARX_INFO << VAROUT(p);
1364 // p.setX(instance->getBounds().center().x);
1365 p.setX(p.x() + cos(angle / 180.0 * M_PI) * length);
1366 p.setY(p.y() + sin(angle / 180.0 * M_PI) * length);
1367 return p;
1368 }
1369
1370 QPointF
1371 State::calcDetachedTransitionEndPoint(StateInstancePtr instance,
1372 const QPointF& lastControlPoint) const
1373 {
1374 QPointF line = lastControlPoint - instance->getBounds().center();
1375 QPointF p = line * 0.1 + lastControlPoint;
1376
1377 return p;
1378 }
1379
1380 void
1381 State::bendTransition(TransitionCPtr transition, int u, int v)
1382 {
1383 TransitionPtr t = findTransition(transition);
1384
1385 if (t && t->sourceState && t->destinationState)
1386 {
1387 QPointList supportPoints;
1388 QPointF p1 = t->sourceState->getBounds().center();
1389 QPointF p2 = t->destinationState->getBounds().center();
1390 // t->supportPoints.startPoint = std::make_shared<QPointF>(p1);
1391 // t->supportPoints.endPoint = std::make_shared<QPointF>(p2);
1392 QPointF dirU = p2 - p1;
1393 QPointF dirV = QPointF(dirU.y(), -dirU.x());
1394 supportPoints.push_back(p1 + dirU * u / 100 + dirV * v / 100);
1395 t->supportPoints.setControlPoints(supportPoints);
1396 emit transitionChanged(t, eChanged);
1397 }
1398 }
1399} // namespace armarx::statechartmodel
uint8_t index
#define M_PI
Definition MathTools.h:17
const StateInstanceMap & getSubstates() const
Definition State.h:115
TransitionList transitions
Definition State.h:314
void stateChanged(statechartmodel::SignalType signalType)
StateInstancePtr addRemoteSubstate(StatePtr newRemoteSubstate, const QString &remoteStateOffererName, QString instanceName="", const QPointF &pos=QPointF())
Definition State.cpp:319
void setTransitionMapping(TransitionCPtr transition, const ParameterMappingList &mappingToNextStateInput, const ParameterMappingList &mappingToParentLocal, const ParameterMappingList &mappingToParentOutput)
Definition State.cpp:754
StateParameterMap outputParameters
Definition State.h:309
QString getStateName() const
Definition State.h:68
bool hasDescendant(statechartmodel::StatePtr state) const
Definition State.cpp:1261
bool checkTransition(TransitionPtr transition) const
Definition State.cpp:1184
void bendTransition(TransitionCPtr transition, int u, int v)
Definition State.cpp:1381
StateInstanceMap substates
Definition State.h:311
void addTransition(TransitionPtr newTransition)
Definition State.cpp:742
TransitionPtr getTransition(const QString &eventName, StateInstancePtr sourceInstance) const
Definition State.cpp:1153
void setLocalParameters(const StateParameterMap &newLocalParameters)
Definition State.cpp:715
void outgoingTransitionChanged(const QString &eventName, statechartmodel::StatePtr stateClass, statechartmodel::SignalType signalType)
void setStartState(StateInstancePtr newStartState)
Definition State.cpp:452
void setActiveSubstate(StateInstancePtr newActiveState)
Definition State.cpp:655
void replaceSubstates(StateInstanceMap newSubstateList)
Definition State.cpp:627
bool renameSubstate(QString oldName, QString newName)
Definition State.cpp:499
void setEditable(bool editable)
Definition State.cpp:269
void setStateName(const QString &newName)
Definition State.cpp:122
void setInputParameters(const StateParameterMap &newInputParameters)
Definition State.cpp:696
void updateTransitionDestination(TransitionCPtr transition, StateInstancePtr newDest, QPointList newSupportPoints=QPointList())
Definition State.cpp:854
QString getUUID() const
Definition State.h:74
StateInstancePtr getStartState() const
Definition State.cpp:136
StateInstancePtr replaceSubstate(QString stateInstanceName, StateInstancePtr newInstance)
Definition State.cpp:607
void substateChanged(statechartmodel::StateInstancePtr substate, statechartmodel::SignalType signalType)
const EventList & getOutgoingEvents() const
Definition State.h:130
TransitionPtr findTransition(TransitionCPtr t) const
Definition State.cpp:1230
bool checkSubstate(StatePtr newState) const
Definition State.cpp:1218
static QString StateTypeToString(eStateType type)
Definition State.cpp:1294
ParameterMappingList getStartStateInputMapping() const
Definition State.cpp:143
StateInstancePtr activeSubstate
Definition State.h:312
void setTransitionSupportPoints(statechartmodel::TransitionCPtr transition, const SupportPoints &points, const QPointPtr &labelCenterPosition=QPointPtr(), const FloatPtr &labelFontPointSize=FloatPtr())
Definition State.cpp:775
void setTransitionUserCodeEnabled(TransitionCPtr transition, bool enabled=true)
Definition State.cpp:819
StateParameterMap localParameters
Definition State.h:308
void addReferences(const QMap< QString, armarx::statechartmodel::StatePtr > &uuidStateMap)
Annotates the State object created by parseXml() before with references to other states.
Definition State.cpp:70
void replaceTransitions(TransitionList newTransitionList)
Definition State.cpp:931
void transitionChanged(statechartmodel::TransitionCPtr transition, statechartmodel::SignalType signalType)
void addSupportPoint(TransitionCPtr transition, QPointF supportPoint)
Definition State.cpp:950
void setDescription(const QString &newDescription)
Definition State.cpp:230
CTransitionList getTransitions(bool withStartTransition=false) const
Definition State.cpp:108
void detachTransitionDestination(TransitionCPtr transition, QPointF floatingEndPoint)
Definition State.cpp:899
StateInstancePtr addDynamicRemoteSubstate(StatePtr state, QString instanceName, const QPointF &pos)
Definition State.cpp:363
void dirtyStatusChanged(bool newStatus)
StateInstancePtr addEndSubstate(const QString &endstateName, const QString &eventName, const QPointF &pos=QPointF())
Definition State.cpp:408
void setOutgoingEvents(const EventList &outgoingEvents)
Definition State.cpp:988
void stateDeleted()
stateDeleted Signals that the destructor of this state was called.
const StateParameterMap getInputAndLocalParameters() const
Definition State.cpp:95
void addDetachedTransition(const QString &eventName, StateInstancePtr sourceState)
Definition State.cpp:835
void setOutputParameters(const StateParameterMap &newOutputParameters)
Definition State.cpp:734
void setTransitionActivated(TransitionCPtr transition)
Definition State.cpp:813
void setStartStateInputMapping(const ParameterMappingList &newStartStateInputMapping)
Definition State.cpp:477
StateParameterMap inputParameters
Definition State.h:307
EventList getAllEvents() const
Definition State.cpp:150
QList< StateInstancePtr > getInstances(statechartmodel::StatePtr stateClass) const
Definition State.cpp:1137
void setSize(const QSizeF &newSize)
Definition State.cpp:244
bool removeTransition(TransitionPtr transition)
Definition State.cpp:1166
TransitionCPtr getStartTransition() const
Definition State.cpp:192
bool removeSubstate(StateInstancePtr substate)
Definition State.cpp:535
void setSubstateAreaSize(const QSizeF &newSize)
Definition State.cpp:261
StateInstancePtr addSubstate(StateInstancePtr stateInstance)
Definition State.cpp:427
void updateTransition(const QString &eventName, statechartmodel::StatePtr stateClass, statechartmodel::SignalType signalType)
Definition State.cpp:1057
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::shared_ptr< State > StatePtr
Definition State.h:48
bool containsOutgoingEvent(const QString &eventName, const EventList &events)
Definition State.cpp:546
QMap< QString, StateParameterPtr > StateParameterMap
std::shared_ptr< StateInstance > StateInstancePtr
QList< ParameterMappingPtr > ParameterMappingList
Definition XmlWriter.h:49
QList< TransitionPtr > TransitionList
Definition State.h:50
std::shared_ptr< Event > EventPtr
Definition XmlWriter.h:46
std::shared_ptr< const Transition > TransitionCPtr
Definition Transition.h:91
std::shared_ptr< const EndState > EndStateCPtr
Definition XmlWriter.h:52
SignalType
The SignalType enum.
Definition SignalType.h:34
QList< EventPtr > EventList
Definition XmlWriter.h:47
QList< TransitionCPtr > CTransitionList
Definition State.h:51
std::shared_ptr< EndState > EndStatePtr
Definition EndState.h:45
std::shared_ptr< Transition > TransitionPtr
Definition Transition.h:90
QMap< QString, StateInstancePtr > StateInstanceMap
Definition State.h:52
std::shared_ptr< QPointF > QPointPtr
Definition Transition.h:40
std::shared_ptr< Transition > TransitionPtr
Definition Transition.h:143
IceInternal::Handle< Event > EventPtr
Typedef of EventPtr as IceInternal::Handle<Event> for convenience.
Definition Event.h:40
QList< QPointF > QPointList
Definition Transition.h:38
std::shared_ptr< float > FloatPtr
Definition Transition.h:39
double angle(const Point &a, const Point &b, const Point &c)
Definition point.hpp:109
QList< QPointF > toPointList() const