ScenarioCreationState.hpp
1 #pragma once
2 #include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>
3 #include <Explorer/Explorer/DeviceExplorerModel.hpp>
4 
5 #include <Scenario/Commands/Scenario/Creations/CreateInterval.hpp>
6 #include <Scenario/Commands/Scenario/Creations/CreateInterval_State.hpp>
7 #include <Scenario/Commands/Scenario/Creations/CreateInterval_State_Event.hpp>
8 #include <Scenario/Commands/Scenario/Creations/CreateInterval_State_Event_TimeSync.hpp>
9 #include <Scenario/Commands/Scenario/Creations/CreateSequence.hpp>
10 #include <Scenario/Commands/Scenario/Creations/CreationMetaCommand.hpp>
11 #include <Scenario/Commands/State/AddMessagesToState.hpp>
12 #include <Scenario/Palette/ScenarioPaletteBaseStates.hpp>
13 #include <Scenario/Palette/ScenarioPaletteBaseTransitions.hpp>
14 #include <Scenario/Palette/Tool.hpp>
15 #include <Scenario/Palette/Tools/ScenarioRollbackStrategy.hpp>
16 #include <Scenario/Process/Algorithms/Accessors.hpp>
17 #include <Scenario/Settings/ScenarioSettingsModel.hpp>
18 #include <Scenario/Tools/elementFindingHelper.hpp>
19 
20 #include <score/application/GUIApplicationContext.hpp>
21 #include <score/command/Dispatchers/MultiOngoingCommandDispatcher.hpp>
22 #include <score/document/DocumentInterface.hpp>
23 #include <score/selection/SelectionDispatcher.hpp>
24 
25 #include <QDebug>
26 
27 namespace Scenario
28 {
29 
30 template <int Value>
31 class StrongQState : public QState
32 {
33 public:
34  static constexpr auto value() { return Value; }
35  StrongQState(QState* parent)
36  : QState{parent}
37  {
38  this->setObjectName(debug_StateMachineIDs<Value>());
39  }
40 };
41 
42 template <typename Scenario_T>
43 class CreationStateBase : public StateBase<Scenario_T>
44 {
45 public:
47 
48  QVector<Id<StateModel>> createdStates;
49  QVector<Id<EventModel>> createdEvents;
50  QVector<Id<TimeSyncModel>> createdTimeSyncs;
51  QVector<Id<IntervalModel>> createdIntervals;
52 
53  void clearCreatedIds()
54  {
55  createdEvents.clear();
56  createdIntervals.clear();
57  createdTimeSyncs.clear();
58  createdStates.clear();
59  }
60 };
61 
62 // Here to prevent pollution of the CreationState header with the command
63 // dispatcher
64 template <typename Scenario_T, typename ToolPalette_T>
65 class CreationState : public CreationStateBase<Scenario_T>
66 {
67 public:
69  const ToolPalette_T& sm, const score::CommandStackFacade& stack,
70  const Scenario_T& scenarioPath, QState* parent)
71  : CreationStateBase<Scenario_T>{scenarioPath, parent}
72  , m_parentSM{sm}
73  , m_dispatcher{stack}
74  {
75  }
76 
77 protected:
78  void createToState_base(const Id<StateModel>& originalState)
79  {
80  if(this->hoveredState)
81  {
82  const bool graphal = isCreatingGraph();
83  const bool differentParents
84  = Scenario::parentEvent(originalState, m_parentSM.model()).timeSync()
85  != Scenario::parentEvent(*this->hoveredState, m_parentSM.model()).timeSync();
86 
87  if(graphal && differentParents)
88  {
89  auto cmd = new Scenario::Command::CreateInterval{
90  this->m_scenario, originalState, *this->hoveredState, true};
91 
92  m_dispatcher.submit(cmd);
93 
94  this->createdIntervals.append(cmd->createdInterval());
95  }
96  else
97  {
98  // make sure the hovered corresponding timesync dont have a date prior
99  // to original state date
100  if(getDate(m_parentSM.model(), originalState)
101  < getDate(m_parentSM.model(), *this->hoveredState))
102  {
103  auto cmd = new Scenario::Command::CreateInterval{
104  this->m_scenario, originalState, *this->hoveredState};
105 
106  m_dispatcher.submit(cmd);
107 
108  this->createdIntervals.append(cmd->createdInterval());
109  }
110  }
111  }
112  }
113 
114  void createToEvent_base(const Id<StateModel>& originalState)
115  {
116  if(this->hoveredEvent)
117  {
118  const bool graphal = isCreatingGraph();
119  const bool differentParents
120  = Scenario::parentEvent(originalState, m_parentSM.model()).timeSync()
121  != m_parentSM.model().event(*this->hoveredEvent).timeSync();
122  const bool timeIsInOrder = getDate(m_parentSM.model(), originalState)
123  < getDate(m_parentSM.model(), *this->hoveredEvent);
124  // make sure the hovered corresponding timesync dont have a date prior to
125  // original state date
126  if((graphal || timeIsInOrder) && differentParents)
127  {
129  this->m_scenario, originalState, *this->hoveredEvent, this->currentPoint.y,
130  graphal};
131 
132  m_dispatcher.submit(cmd);
133 
134  this->createdIntervals.append(cmd->createdInterval());
135  this->createdStates.append(cmd->createdState());
136  } // else do nothing
137  }
138  }
139 
140  void createToTimeSync_base(const Id<StateModel>& originalState)
141  {
142  if(this->hoveredTimeSync)
143  {
144  const bool graphal = isCreatingGraph();
145  const bool differentParents
146  = Scenario::parentEvent(originalState, m_parentSM.model()).timeSync()
147  != *this->hoveredTimeSync;
148  const bool timeIsInOrder = getDate(m_parentSM.model(), originalState)
149  < getDate(m_parentSM.model(), *this->hoveredTimeSync);
150  // make sure the hovered corresponding timesync dont have a date prior to
151  // original state date
152  if((graphal || timeIsInOrder) && differentParents)
153  {
155  this->m_scenario, originalState, *this->hoveredTimeSync,
156  this->currentPoint.y, graphal};
157 
158  m_dispatcher.submit(cmd);
159 
160  this->createdStates.append(cmd->createdState());
161  this->createdEvents.append(cmd->createdEvent());
162  this->createdIntervals.append(cmd->createdInterval());
163  }
164  }
165  }
166 
167  void createToNothing_base(const Id<StateModel>& originalState)
168  {
169  if(m_parentSM.editionSettings().tool() != Tool::CreateSequence)
170  {
172  this->m_scenario,
173  originalState, // Put there in createInitialState
174  this->currentPoint.date, this->currentPoint.y, isCreatingGraph()};
175 
176  m_dispatcher.submit(cmd);
177 
178  this->createdStates.append(cmd->createdState());
179  this->createdEvents.append(cmd->createdEvent());
180  this->createdTimeSyncs.append(cmd->createdTimeSync());
181  this->createdIntervals.append(cmd->createdInterval());
182  }
183  else
184  {
185 
186  // This
187  auto cmd = Scenario::Command::CreateSequence::make(
188  this->m_parentSM.context().context, this->m_parentSM.model(),
189  originalState, // Put there in createInitialState
190  this->currentPoint.date, this->currentPoint.y);
191 
192  m_dispatcher.submitQuiet(cmd);
193 
194  this->createdStates.append(cmd->createdState());
195  this->createdEvents.append(cmd->createdEvent());
196  this->createdTimeSyncs.append(cmd->createdTimeSync());
197  this->createdIntervals.append(cmd->createdInterval());
198  }
199  }
200 
201  void makeSnapshot()
202  {
203  const score::DocumentContext& ctx = this->m_parentSM.context().context;
204  if(!ctx.app.settings<Scenario::Settings::Model>().getSnapshotOnCreate())
205  return;
206 
207  using namespace Command;
208  if(m_parentSM.editionSettings().tool() == Tool::CreateSequence)
209  return;
210 
211  if(this->createdStates.empty())
212  return;
213 
214  if(!this->createdIntervals.empty())
215  {
216  const auto& cst = m_parentSM.model().intervals.at(this->createdIntervals.last());
217  if(!cst.processes.empty())
218  {
219  // In case of the presence of a sequence, we
220  // only use the sequence's namespace, hence we don't need to make a
221  // snapshot at the end..
222  return;
223  }
224  }
225 
226  auto& device_explorer
227  = ctx.template plugin<Explorer::DeviceDocumentPlugin>().explorer();
228 
229  State::MessageList messages = getSelectionSnapshot(device_explorer);
230  if(messages.empty())
231  return;
232 
233  m_dispatcher.submit(new AddMessagesToState{
234  m_parentSM.model().states.at(this->createdStates.last()), messages});
235  }
236 
237  template <typename DestinationState, typename Function>
238  void add_transition(QState* from, DestinationState* to, Function&& fun)
239  {
240  using transition_type = Transition_T<Scenario_T, DestinationState::value()>;
241  auto trans = score::make_transition<transition_type>(from, to, *this);
242  trans->setObjectName(QString::number(DestinationState::value()));
243  QObject::connect(trans, &transition_type::triggered, this, fun);
244  }
245 
246  void commit()
247  {
248  this->makeSnapshot();
249  this->m_dispatcher.template commit<Scenario::Command::CreationMetaCommand>();
250 
251  // Select all the created elements
252  Selection sel;
253  if(!this->createdStates.empty())
254  {
255  auto& s = this->createdStates.back();
256  auto sp = m_parentSM.model().states.find(s);
257  if(sp == m_parentSM.model().states.end())
258  {
259  qDebug() << "Error: tried to select state but it did not exist";
260  }
261  else
262  {
263  sel.append(*sp);
264  }
265  }
266 
267  if(!this->createdIntervals.empty())
268  {
269  auto& i = this->createdIntervals.back();
270  auto ip = m_parentSM.model().intervals.find(i);
271  if(ip == m_parentSM.model().intervals.end())
272  {
273  qDebug() << "Error: tried to select interval but it did not exist";
274  }
275  else
276  {
277  sel.append(*ip);
278  }
279  }
280 
281  score::SelectionDispatcher d{this->m_parentSM.context().context.selectionStack};
282  d.select(sel);
283  this->clearCreatedIds();
284  }
285 
286  void rollback()
287  {
288  m_dispatcher.template rollback<ScenarioRollbackStrategy>();
289  this->clearCreatedIds();
290  }
291 
292  inline bool isCreatingGraph() const noexcept
293  {
294  return this->m_parentSM.editionSettings().tool() == Scenario::Tool::CreateGraph;
295  }
296 
297  const ToolPalette_T& m_parentSM;
298  MultiOngoingCommandDispatcher m_dispatcher;
299 
300  Scenario::Point m_clickedPoint{};
301 };
302 }
The MultiOngoingCommandDispatcher class.
Definition: MultiOngoingCommandDispatcher.hpp:33
Definition: CreateInterval_State_Event_TimeSync.hpp:30
Definition: CreateInterval_State_Event.hpp:26
Definition: CreateInterval_State.hpp:26
The CreateEventAfterEventCommand class.
Definition: CreateInterval.hpp:33
Definition: ScenarioCreationState.hpp:44
Definition: ScenarioCreationState.hpp:66
Definition: ScenarioSettingsModel.hpp:19
Definition: ScenarioPaletteBaseStates.hpp:20
Definition: ScenarioCreationState.hpp:32
Definition: ScenarioPaletteBaseTransitions.hpp:23
Definition: Selection.hpp:12
The id_base_t class.
Definition: Identifier.hpp:57
A small abstraction layer over the score::CommandStack.
Definition: CommandStackFacade.hpp:20
The SelectionDispatcher class.
Definition: SelectionDispatcher.hpp:15
Main plug-in of score.
Definition: score-plugin-dataflow/Dataflow/PortItem.hpp:14
Definition: ScenarioPoint.hpp:13
T & settings() const
Access a specific Settings model instance.
Definition: ApplicationContext.hpp:40
Definition: DocumentContext.hpp:18