Commands/Scenario/ScenarioPaste.hpp
1 #pragma once
2 #include <Process/ProcessList.hpp>
3 
4 #include <Scenario/Document/ScenarioDocument/ScenarioDocumentModel.hpp>
5 #include <Scenario/Process/ScenarioModel.hpp>
6 
7 #include <score/application/GUIApplicationContext.hpp>
8 #include <score/document/DocumentContext.hpp>
9 #include <score/model/EntitySerialization.hpp>
10 #include <score/plugins/SerializableHelpers.hpp>
11 #include <score/tools/IdentifierGeneration.hpp>
12 
13 #include <ossia/detail/flat_map.hpp>
14 #include <ossia/detail/hash_map.hpp>
15 
16 namespace Scenario
17 {
18 
19 std::vector<Process::CableData>
20 cableDataFromCablesJson(const rapidjson::Document::ConstArray& arr);
21 std::vector<Process::CableData>
22 cableDataFromCablesJson(const rapidjson::Document::Array& arr);
23 
24 // e.g. IntervalModel being copied in a Scenario
25 template <typename CopiedObjects, typename ParentObject>
26 ossia::flat_map<Id<Process::Cable>, Process::CableData> mapCopiedCables(
27  const score::DocumentContext& ctx, std::vector<Process::CableData>& cables,
28  std::vector<CopiedObjects*>& intervals,
29  const std::vector<Id<CopiedObjects>>& interval_ids, const ParentObject& scenario)
30 {
31  ossia::flat_map<Id<Process::Cable>, Process::CableData> cable_map;
32 
33  {
34  ossia::hash_map<Id<CopiedObjects>, Id<CopiedObjects>> id_map;
35  {
36  int i = 0;
37  for(CopiedObjects* interval : intervals)
38  {
39  id_map[interval->id()] = interval_ids[i];
40  i++;
41  }
42  }
43 
44  auto& doc = score::IDocument::modelDelegate<ScenarioDocumentModel>(ctx.document);
45  auto cable_ids = getStrongIdRange<Process::Cable>(cables.size(), doc.cables);
46 
47  int i = 0;
48  Path<ParentObject> p{scenario};
49  for(Process::CableData& cd : cables)
50  {
51  auto& source_vec = cd.source.unsafePath().vec();
52  auto& sink_vec = cd.sink.unsafePath().vec();
53  SCORE_ASSERT(!source_vec.empty());
54  SCORE_ASSERT(!sink_vec.empty());
55  int32_t source_itv_id = source_vec.front().id();
56  int32_t sink_itv_id = sink_vec.front().id();
57 
58  for(CopiedObjects* interval : intervals)
59  {
60  auto id = interval->id().val();
61  if(id == source_itv_id)
62  source_itv_id = id_map.at(interval->id()).val();
63  if(id == sink_itv_id)
64  sink_itv_id = id_map.at(interval->id()).val();
65  }
66  source_vec.front()
67  = ObjectIdentifier{source_vec.front().objectName(), source_itv_id};
68  sink_vec.front() = ObjectIdentifier{sink_vec.front().objectName(), sink_itv_id};
69 
70  source_vec.insert(
71  source_vec.begin(), p.unsafePath().vec().begin(), p.unsafePath().vec().end());
72  sink_vec.insert(
73  sink_vec.begin(), p.unsafePath().vec().begin(), p.unsafePath().vec().end());
74 
75  cable_map.insert({cable_ids[i], std::move(cd)});
76  i++;
77  }
78 
79  for(CopiedObjects* interval : intervals)
80  {
81  const auto ports = interval->template findChildren<Process::Port*>();
82  for(Process::Port* port : ports)
83  {
84  while(!port->cables().empty())
85  {
86  port->removeCable(port->cables().back());
87  }
88  }
89  }
90  }
91 
92  return cable_map;
93 }
94 
96 {
98  const rapidjson::Value& obj, const Scenario::ProcessModel& scenario,
99  const score::DocumentContext& ctx)
100  {
101  // TODO this is really a bad idea... either they should be properly added,
102  // or the json should be modified without including anything in the
103  // scenario. Especially their parents aren't coherent (TimeSync must not
104  // have a parent because it tries to access the event in the scenario if it
105  // has one) We deserialize everything
106  {
107  const auto& json_arr = obj["Intervals"].GetArray();
108  intervals.reserve(json_arr.Size());
109  for(const auto& element : json_arr)
110  {
111  intervals.emplace_back(new IntervalModel{
112  JSONObject::Deserializer{element}, scenario.context(), (QObject*)&scenario});
113  }
114  }
115  {
116  const auto& json_arr = obj["TimeNodes"].GetArray();
117  timesyncs.reserve(json_arr.Size());
118  for(const auto& element : json_arr)
119  {
120  timesyncs.emplace_back(
121  new TimeSyncModel{JSONObject::Deserializer{element}, nullptr});
122  }
123  }
124  {
125  const auto& json_arr = obj["Events"].GetArray();
126  events.reserve(json_arr.Size());
127  for(const auto& element : json_arr)
128  {
129  events.emplace_back(new EventModel{JSONObject::Deserializer{element}, nullptr});
130  }
131  }
132  {
133  const auto& json_arr = obj["States"].GetArray();
134  states.reserve(json_arr.Size());
135  for(const auto& element : json_arr)
136  {
137  states.emplace_back(new StateModel{
138  JSONObject::Deserializer{element}, scenario.context(), (QObject*)&scenario});
139  }
140  }
141  {
142  const auto& json_arr = obj["Cables"].GetArray();
143  cables = cableDataFromCablesJson(json_arr);
144  }
145 
146  // We generate identifiers for the forthcoming elements
147  interval_ids = getStrongIdRange2<IntervalModel>(
148  intervals.size(), scenario.intervals, intervals);
149  timesync_ids = getStrongIdRange2<TimeSyncModel>(
150  timesyncs.size(), scenario.timeSyncs, timesyncs);
151  event_ids = getStrongIdRange2<EventModel>(events.size(), scenario.events, events);
152  state_ids = getStrongIdRange2<StateModel>(states.size(), scenario.states, states);
153  }
154 
155  std::vector<TimeSyncModel*> timesyncs;
156  std::vector<IntervalModel*> intervals;
157  std::vector<EventModel*> events;
158  std::vector<StateModel*> states;
159  std::vector<Process::CableData> cables;
160 
161  std::vector<Id<IntervalModel>> interval_ids;
162  std::vector<Id<TimeSyncModel>> timesync_ids;
163  std::vector<Id<EventModel>> event_ids;
164  std::vector<Id<StateModel>> state_ids;
165 };
166 
168 {
170  const rapidjson::Value::Array& sourceProcesses,
171  const Scenario::IntervalModel& parent, const score::DocumentContext& ctx)
172  {
173  // TODO this is (again) really a bad idea... either they should be properly added,
174  // or the json should be modified without including anything in the
175  // scenario. Especially their parents aren't coherent (TimeSync must not
176  // have a parent because it tries to access the event in the scenario if it
177  // has one) We deserialize everything
178  {
179  static auto& pl = ctx.app.interfaces<Process::ProcessFactoryList>();
180  const auto& json_arr = sourceProcesses;
181  processes.reserve(json_arr.Size());
182  for(const auto& element : json_arr)
183  {
184  JSONObject::Deserializer deserializer{element};
185  auto proc = deserialize_interface(
186  pl, deserializer, ctx, const_cast<Scenario::IntervalModel*>(&parent));
187  if(proc)
188  processes.emplace_back(proc);
189  }
190  }
191 
192  // We generate identifiers for the forthcoming elements
193  processes_ids = getStrongIdRange2<Process::ProcessModel>(
194  processes.size(), parent.processes, processes);
195  }
196 
197  std::vector<Process::ProcessModel*> processes;
198  std::vector<Id<Process::ProcessModel>> processes_ids;
199 };
200 }
Definition: JSONVisitor.hpp:423
The ObjectIdentifier class.
Definition: ObjectIdentifier.hpp:21
The Path class is a typesafe wrapper around ObjectPath.
Definition: Path.hpp:52
Definition: score-lib-process/Process/Dataflow/Port.hpp:102
Definition: ProcessList.hpp:10
Definition: EventModel.hpp:36
Definition: IntervalModel.hpp:50
score::EntityMap< Process::ProcessModel, true > processes
Definition: IntervalModel.hpp:62
The core hierarchical and temporal process of score.
Definition: ScenarioModel.hpp:37
Definition: StateModel.hpp:63
Definition: TimeSyncModel.hpp:35
The id_base_t class.
Definition: Identifier.hpp:57
Main plug-in of score.
Definition: score-plugin-dataflow/Dataflow/PortItem.hpp:14
Definition: Cable.hpp:45
Definition: Commands/Scenario/ScenarioPaste.hpp:168
Definition: Commands/Scenario/ScenarioPaste.hpp:96
const T & interfaces() const
Access to a specific interface list.
Definition: ApplicationContext.hpp:67
Definition: DocumentContext.hpp:18