Loading...
Searching...
No Matches
AutomationDropHandler.cpp
1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3#include "AutomationDropHandler.hpp"
4
5#include <Device/Node/NodeListMimeSerialization.hpp>
6
7#include <Process/ProcessMimeSerialization.hpp>
8
9#include <Scenario/Commands/Cohesion/CreateCurves.hpp>
10#include <Scenario/Commands/CommandAPI.hpp>
11#include <Scenario/Commands/Interval/AddLayerInNewSlot.hpp>
12#include <Scenario/Commands/Interval/AddProcessToInterval.hpp>
13#include <Scenario/Commands/Interval/ResizeInterval.hpp>
14#include <Scenario/Commands/Metadata/ChangeElementName.hpp>
15#include <Scenario/Commands/Scenario/ScenarioPasteElements.hpp>
16#include <Scenario/Document/ScenarioDocument/ScenarioDocumentModel.hpp>
17#include <Scenario/Process/ScenarioModel.hpp>
18#include <Scenario/Process/ScenarioPresenter.hpp>
19
20#include <Dataflow/Commands/CableHelpers.hpp>
21
22#include <score/document/DocumentContext.hpp>
23
24#include <ossia/detail/thread.hpp>
25#include <ossia/network/value/value_traits.hpp>
26
27#include <QFileInfo>
28#include <QUrl>
29namespace Scenario
30{
31
32DropScenario::DropScenario()
33{
34 // TODO give them a mime type ?
35 m_acceptableSuffixes.push_back("scenario");
36}
37
38bool DropScenario::drop(
39 const ScenarioPresenter& pres, QPointF pos, const QMimeData& mime)
40{
41 if(mime.hasUrls())
42 {
43 const auto& doc = pres.context().context;
44 auto& sm = pres.model();
45 auto path = mime.urls().first().toLocalFile();
46 if(QFile f{path}; QFileInfo{f}.suffix() == "scenario" && f.open(QIODevice::ReadOnly))
47 {
48 CommandDispatcher<> d{doc.commandStack};
50 sm, readJson(f.readAll()), pres.toScenarioPoint(pos)));
51 return true;
52 }
53 }
54
55 return false;
56}
57
58DropScoreInScenario::DropScoreInScenario()
59{
60 m_acceptableSuffixes.push_back("score");
61 m_acceptableSuffixes.push_back("scorebin");
62}
63
64bool DropScoreInScenario::drop(
65 const ScenarioPresenter& pres, QPointF pos, const QMimeData& mime)
66{
67 if(mime.hasUrls())
68 {
69 const auto& doc = pres.context().context;
70 auto& sm = pres.model();
71 auto path = mime.urls().first().toLocalFile();
72 if(QFile f{path}; QFileInfo{f}.suffix() == "score" && f.open(QIODevice::ReadOnly))
73 {
74 rapidjson::Document res;
75 res.SetObject();
76
77 auto obj = readJson(f.readAll());
78 auto& docobj = obj["Document"];
79
80 // ScenarioPasteElements expects the cable address to start from the topmost interval in the copied
81 // content
82 res.AddMember("Cables", docobj["Cables"], res.GetAllocator());
83 for(auto& c : res["Cables"].GetArray())
84 {
85 auto source = c["Source"].GetArray();
86 source.Erase(source.Begin());
87 source.Erase(source.Begin());
88 auto sink = c["Sink"].GetArray();
89 sink.Erase(sink.Begin());
90 sink.Erase(sink.Begin());
91 }
92
93 auto& scenar = docobj["BaseScenario"];
94
95 {
96 rapidjson::Value arr(rapidjson::kArrayType);
97 arr.PushBack(scenar["Constraint"], obj.GetAllocator());
98 res.AddMember("Intervals", arr, res.GetAllocator());
99 }
100 {
101 rapidjson::Value arr(rapidjson::kArrayType);
102 arr.PushBack(scenar["StartState"], obj.GetAllocator());
103 arr.PushBack(scenar["EndState"], obj.GetAllocator());
104 res.AddMember("States", arr, res.GetAllocator());
105 }
106 {
107 rapidjson::Value arr(rapidjson::kArrayType);
108 arr.PushBack(scenar["StartEvent"], obj.GetAllocator());
109 arr.PushBack(scenar["EndEvent"], obj.GetAllocator());
110 res.AddMember("Events", arr, res.GetAllocator());
111 }
112 {
113 rapidjson::Value arr(rapidjson::kArrayType);
114 arr.PushBack(scenar["StartTimeNode"], obj.GetAllocator());
115 arr.PushBack(scenar["EndTimeNode"], obj.GetAllocator());
116 res.AddMember("TimeNodes", arr, res.GetAllocator());
117 }
118
119 CommandDispatcher<> d{doc.commandStack};
121 sm, res, pres.toScenarioPoint(pos)));
122 return true;
123 }
124 }
125
126 return false;
127}
128
129static void getAddressesRecursively(
130 const Device::Node& node, State::Address curAddr,
131 std::vector<Device::FullAddressSettings>& addresses)
132{
133 // TODO refactor with CreateCurves and AddressAccessorEditWidget
134 if(node.is<Device::AddressSettings>())
135 {
136 const Device::AddressSettings& addr = node.get<Device::AddressSettings>();
137 // FIXME see https://github.com/ossia/libossia/issues/291
138 if(ossia::is_numeric(addr.value) || ossia::is_array(addr.value))
139 {
141 static_cast<Device::AddressSettingsCommon&>(as) = addr;
142 as.address = curAddr;
143 addresses.push_back(std::move(as));
144 }
145 // TODO interpolation
146 }
147
148 for(auto& child : node)
149 {
150 const Device::AddressSettings& addr = child.get<Device::AddressSettings>();
151
152 State::Address newAddr{curAddr};
153 newAddr.path.append(addr.name);
154 getAddressesRecursively(child, newAddr, addresses);
155 }
156}
157
158bool AutomationDropHandler::drop(
159 const score::DocumentContext& ctx, const IntervalModel& cst, QPointF p,
160 const QMimeData& mime)
161{
162 // TODO refactor with AddressEditWidget
163 if(mime.formats().contains(score::mime::nodelist()))
164 {
166 Device::FreeNodeList nl = des.deserialize();
167 if(nl.empty())
168 return false;
169
170 std::vector<Device::FullAddressSettings> addresses;
171 for(auto& np : nl)
172 {
173 getAddressesRecursively(np.second, np.first, addresses);
174 }
175
176 if(addresses.empty())
177 return false;
178
179 CreateCurvesFromAddresses({&cst}, addresses, ctx.commandStack);
180
181 return true;
182 }
183 else
184 {
185 return false;
186 }
187}
188
189bool DropScoreInInterval::drop(
190 const score::DocumentContext& doc, const IntervalModel& interval, QPointF p,
191 const QMimeData& mime)
192{
193 if(mime.hasUrls())
194 {
195 auto path = mime.urls().first().toLocalFile();
196 if(QFile f{path}; QFileInfo{f}.suffix() == "score" && f.open(QIODevice::ReadOnly))
197 {
198 auto obj = readJson(f.readAll());
199 auto& docobj = obj["Document"];
200 auto& scenar = docobj["BaseScenario"];
201 auto& itv = scenar["Constraint"];
202
203 Scenario::Command::Macro m{new Command::DropProcessInIntervalMacro, doc};
204 for(auto& json : itv["Processes"].GetArray())
205 {
206 m.loadProcessInSlot(interval, json);
207 }
208
209 // Reload cables
210 {
211 ObjectPath old_path{
212 {"Scenario::ScenarioDocumentModel", 1},
213 {"Scenario::BaseScenario", 0},
214 {"Scenario::IntervalModel", 0}};
215 auto new_path = score::IDocument::path(interval).unsafePath();
216 auto cables = Dataflow::serializedCablesFromCableJson(
217 old_path, docobj["Cables"].GetArray());
218
219 auto& document
220 = score::IDocument::get<Scenario::ScenarioDocumentModel>(doc.document);
221 for(auto& c : cables)
222 {
223 c.first = getStrongId(document.cables);
224 }
225 m.loadCables(new_path, cables);
226 }
227
228 // Finally we show the newly created rack
229 m.showRack(interval);
230
231 m.commit();
232
233 return true;
234 }
235 }
236
237 return false;
238}
239
240}
The CommandDispatcher class.
Definition CommandDispatcher.hpp:13
The ObjectPath class.
Definition ObjectPath.hpp:37
Definition CommandAPI.hpp:28
Definition ScenarioPasteElements.hpp:26
Main plug-in of score.
Definition score-plugin-dataflow/Dataflow/PortItem.hpp:13
Definition AddressSettings.hpp:24
Definition AddressSettings.hpp:49
Definition AddressSettings.hpp:62
Definition MimeVisitor.hpp:9
The Address struct.
Definition Address.hpp:58
Definition DocumentContext.hpp:18