Loading...
Searching...
No Matches
ScenarioPaste.hpp
1#pragma once
2#include <Process/ProcessList.hpp>
3
4#include <Scenario/Commands/Scenario/PasteAnchors.hpp>
5#include <Scenario/Document/ScenarioDocument/ScenarioDocumentModel.hpp>
6#include <Scenario/Process/ScenarioModel.hpp>
7
8#include <score/application/GUIApplicationContext.hpp>
9#include <score/document/DocumentContext.hpp>
10#include <score/document/DocumentInterface.hpp>
11#include <score/model/EntitySerialization.hpp>
12#include <score/model/path/PathSerialization.hpp>
13#include <score/plugins/SerializableHelpers.hpp>
14#include <score/tools/IdentifierGeneration.hpp>
15
16#include <ossia/detail/flat_map.hpp>
17#include <ossia/detail/hash_map.hpp>
18
19namespace Scenario
20{
21
22std::vector<Process::CableData>
23cableDataFromCablesJson(const rapidjson::Document::ConstArray& arr);
24std::vector<Process::CableData>
25cableDataFromCablesJson(const rapidjson::Document::Array& arr);
26
27// e.g. IntervalModel being copied in a Scenario
28template <typename CopiedObjects, typename ParentObject>
29ossia::flat_map<Id<Process::Cable>, Process::CableData> mapCopiedCables(
30 const score::DocumentContext& ctx, std::vector<Process::CableData>& cables,
31 std::vector<CopiedObjects*>& intervals,
32 const std::vector<Id<CopiedObjects>>& interval_ids, const ParentObject& scenario)
33{
34 ossia::flat_map<Id<Process::Cable>, Process::CableData> cable_map;
35
36 {
37 ossia::hash_map<Id<CopiedObjects>, Id<CopiedObjects>> id_map;
38 {
39 int i = 0;
40 for(CopiedObjects* interval : intervals)
41 {
42 id_map[interval->id()] = interval_ids[i];
43 i++;
44 }
45 }
46
47 auto& doc = score::IDocument::modelDelegate<ScenarioDocumentModel>(ctx.document);
48 auto cable_ids = getStrongIdRange<Process::Cable>(cables.size(), doc.cables);
49
50 int i = 0;
51 Path<ParentObject> p{scenario};
52 for(Process::CableData& cd : cables)
53 {
54 auto& source_vec = cd.source.unsafePath().vec();
55 auto& sink_vec = cd.sink.unsafePath().vec();
56 SCORE_ASSERT(!source_vec.empty());
57 SCORE_ASSERT(!sink_vec.empty());
58 int32_t source_itv_id = source_vec.front().id();
59 int32_t sink_itv_id = sink_vec.front().id();
60
61 for(CopiedObjects* interval : intervals)
62 {
63 auto id = interval->id().val();
64 if(id == source_itv_id)
65 source_itv_id = id_map.at(interval->id()).val();
66 if(id == sink_itv_id)
67 sink_itv_id = id_map.at(interval->id()).val();
68 }
69 source_vec.front()
70 = ObjectIdentifier{source_vec.front().objectName(), source_itv_id};
71 sink_vec.front() = ObjectIdentifier{sink_vec.front().objectName(), sink_itv_id};
72
73 source_vec.insert(
74 source_vec.begin(), p.unsafePath().vec().begin(), p.unsafePath().vec().end());
75 sink_vec.insert(
76 sink_vec.begin(), p.unsafePath().vec().begin(), p.unsafePath().vec().end());
77
78 cable_map.insert({cable_ids[i], std::move(cd)});
79 i++;
80 }
81
82 for(CopiedObjects* interval : intervals)
83 {
84 const auto ports = interval->template findChildren<Process::Port*>();
85 for(Process::Port* port : ports)
86 {
87 while(!port->cables().empty())
88 {
89 port->removeCable(port->cables().back());
90 }
91 }
92 }
93 }
94
95 return cable_map;
96}
97
99{
101 const rapidjson::Value& obj, const Scenario::ProcessModel& scenario,
102 const score::DocumentContext& ctx)
103 {
104 // TODO this is really a bad idea... either they should be properly added,
105 // or the json should be modified without including anything in the
106 // scenario. Especially their parents aren't coherent (TimeSync must not
107 // have a parent because it tries to access the event in the scenario if it
108 // has one) We deserialize everything
109 {
110 const auto& json_arr = obj["Intervals"].GetArray();
111 intervals.reserve(json_arr.Size());
112 for(const auto& element : json_arr)
113 {
114 intervals.emplace_back(new IntervalModel{
115 JSONObject::Deserializer{element}, scenario.context(), (QObject*)&scenario});
116 }
117 }
118 {
119 const auto& json_arr = obj["TimeNodes"].GetArray();
120 timesyncs.reserve(json_arr.Size());
121 for(const auto& element : json_arr)
122 {
123 timesyncs.emplace_back(
124 new TimeSyncModel{JSONObject::Deserializer{element}, nullptr});
125 }
126 }
127 {
128 const auto& json_arr = obj["Events"].GetArray();
129 events.reserve(json_arr.Size());
130 for(const auto& element : json_arr)
131 {
132 events.emplace_back(new EventModel{JSONObject::Deserializer{element}, nullptr});
133 }
134 }
135 {
136 const auto& json_arr = obj["States"].GetArray();
137 states.reserve(json_arr.Size());
138 for(const auto& element : json_arr)
139 {
140 states.emplace_back(new StateModel{
141 JSONObject::Deserializer{element}, scenario.context(), (QObject*)&scenario});
142 }
143 }
144 {
145 const auto& json_arr = obj["Cables"].GetArray();
146 cables = cableDataFromCablesJson(json_arr);
147 }
148
149 // We generate identifiers for the forthcoming elements
150 interval_ids = getStrongIdRange2<IntervalModel>(
151 intervals.size(), scenario.intervals, intervals);
152 timesync_ids = getStrongIdRange2<TimeSyncModel>(
153 timesyncs.size(), scenario.timeSyncs, timesyncs);
154 event_ids = getStrongIdRange2<EventModel>(events.size(), scenario.events, events);
155 state_ids = getStrongIdRange2<StateModel>(states.size(), scenario.states, states);
156
157 remapAnchors(obj, scenario, ctx);
158 }
159
160 // Retargets anchors to the new identifiers of the pasted elements
161 void remapAnchors(
162 const rapidjson::Value& obj, const Scenario::ProcessModel& scenario,
163 const score::DocumentContext& ctx)
164 {
165 CopiedPaths paths;
166 paths.sameDocument = copiedFromHere(obj, ctx);
167 if(auto it = obj.FindMember("Origin"); it != obj.MemberEnd())
168 {
169 ObjectPath origin;
170 origin <<= JsonValue{it->value};
171 const auto here = score::IDocument::unsafe_path(scenario);
172 auto pair = [&](auto& models, auto& ids) {
173 for(std::size_t i = 0; i < models.size(); i++)
174 {
175 auto from = origin.vec();
176 from.emplace_back(models[i]->objectName(), models[i]->id());
177 auto to = here.vec();
178 to.emplace_back(models[i]->objectName(), ids[i]);
179 paths.moved.emplace_back(ObjectPath{std::move(from)}, ObjectPath{std::move(to)});
180 }
181 };
182 pair(intervals, interval_ids);
183 pair(timesyncs, timesync_ids);
184 pair(events, event_ids);
185 pair(states, state_ids);
186 }
187
188 for(auto o : intervals)
189 remapCopiedAnchors(*o, paths);
190 for(auto o : timesyncs)
191 remapCopiedAnchors(*o, paths);
192 for(auto o : events)
193 remapCopiedAnchors(*o, paths);
194 for(auto o : states)
195 remapCopiedAnchors(*o, paths);
196 }
197
198 std::vector<TimeSyncModel*> timesyncs;
199 std::vector<IntervalModel*> intervals;
200 std::vector<EventModel*> events;
201 std::vector<StateModel*> states;
202 std::vector<Process::CableData> cables;
203
204 std::vector<Id<IntervalModel>> interval_ids;
205 std::vector<Id<TimeSyncModel>> timesync_ids;
206 std::vector<Id<EventModel>> event_ids;
207 std::vector<Id<StateModel>> state_ids;
208};
209
211{
213 const rapidjson::Value::ConstArray& sourceProcesses,
214 const Scenario::IntervalModel& parent, const score::DocumentContext& ctx)
215 {
216 // TODO this is (again) really a bad idea... either they should be properly added,
217 // or the json should be modified without including anything in the
218 // scenario. Especially their parents aren't coherent (TimeSync must not
219 // have a parent because it tries to access the event in the scenario if it
220 // has one) We deserialize everything
221 {
222 auto& pl = ctx.app.interfaces<Process::ProcessFactoryList>();
223 const auto& json_arr = sourceProcesses;
224 processes.reserve(json_arr.Size());
225 int i = 0;
226 for(const auto& element : json_arr)
227 {
228 JSONObject::Deserializer deserializer{element};
229 auto proc = deserialize_interface(
230 pl, deserializer, ctx, const_cast<Scenario::IntervalModel*>(&parent));
231 if(proc)
232 {
233 processes.emplace_back(proc);
234 sources.push_back(i);
235 }
236 i++;
237 }
238 }
239
240 // We generate identifiers for the forthcoming elements
241 processes_ids = getStrongIdRange2<Process::ProcessModel>(
242 processes.size(), parent.processes, processes);
243 }
244
245 // "ProcessPaths" holds the original path of each copied process, or
246 // "ProcessesParent" the path of the interval they all come from.
247 void remapAnchors(
248 const rapidjson::Value& copy, const Scenario::IntervalModel& parent,
249 const score::DocumentContext& ctx)
250 {
251 CopiedPaths paths;
252 paths.sameDocument = copiedFromHere(copy, ctx);
253 if(auto it = copy.FindMember("ProcessPaths");
254 it != copy.MemberEnd() && it->value.IsArray())
255 {
256 const auto& arr = it->value.GetArray();
257 const auto here = score::IDocument::unsafe_path(parent);
258 for(std::size_t i = 0; i < processes.size(); i++)
259 {
260 if(sources[i] >= (int)arr.Size())
261 continue;
262 ObjectPath from;
263 from <<= JsonValue{arr[sources[i]]};
264 auto to = here.vec();
265 to.emplace_back(processes[i]->objectName(), processes_ids[i]);
266 paths.moved.emplace_back(std::move(from), ObjectPath{std::move(to)});
267 }
268 }
269 else if(auto it = copy.FindMember("ProcessesParent"); it != copy.MemberEnd())
270 {
271 ObjectPath parentPath;
272 parentPath <<= JsonValue{it->value};
273 const auto here = score::IDocument::unsafe_path(parent);
274 for(std::size_t i = 0; i < processes.size(); i++)
275 {
276 auto from = parentPath.vec();
277 from.emplace_back(processes[i]->objectName(), processes[i]->id());
278 auto to = here.vec();
279 to.emplace_back(processes[i]->objectName(), processes_ids[i]);
280 paths.moved.emplace_back(ObjectPath{std::move(from)}, ObjectPath{std::move(to)});
281 }
282 }
283
284 for(auto proc : processes)
285 remapCopiedAnchors(*proc, paths);
286 }
287
288 std::vector<Process::ProcessModel*> processes;
289 std::vector<Id<Process::ProcessModel>> processes_ids;
291 std::vector<int> sources;
292};
293}
Definition JSONVisitor.hpp:423
The ObjectIdentifier class.
Definition ObjectIdentifier.hpp:21
The ObjectPath class.
Definition ObjectPath.hpp:37
The Path class is a typesafe wrapper around ObjectPath.
Definition Path.hpp:52
Definition Port.hpp:106
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:62
Definition TimeSyncModel.hpp:34
The id_base_t class.
Definition Identifier.hpp:59
Main plug-in of score.
Definition ConnectionsList.hpp:22
bool copiedFromHere(const rapidjson::Value &copy, const score::DocumentContext &ctx)
Compares the copy's "OriginDocument" key with score::IDocument::copyOrigin()
Definition PasteAnchors.cpp:26
void remapCopiedAnchors(QObject &root, const CopiedPaths &paths)
Definition PasteAnchors.cpp:84
Definition JSONVisitor.hpp:372
Definition CableData.hpp:18
Paths of the copied objects and of their copies.
Definition PasteAnchors.hpp:24
Definition ScenarioPaste.hpp:211
std::vector< int > sources
Index of each process in the copied array.
Definition ScenarioPaste.hpp:291
Definition ScenarioPaste.hpp:99
Definition DocumentContext.hpp:18