RecordProviderFactory.hpp
1 #pragma once
2 #include <Device/Node/DeviceNode.hpp>
3 
4 #include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>
5 #include <Explorer/Explorer/DeviceExplorerModel.hpp>
6 
7 #include <Scenario/Palette/ScenarioPoint.hpp>
8 #include <Scenario/Process/Algorithms/Accessors.hpp>
9 
10 #include <Recording/Record/RecordTools.hpp>
11 
12 #include <score/plugins/Interface.hpp>
13 #include <score/plugins/documentdelegate/DocumentDelegateView.hpp>
15 #include <score/tools/ObjectMatches.hpp>
16 
17 #include <core/document/Document.hpp>
18 #include <core/document/DocumentView.hpp>
19 
20 #include <QApplication>
21 #include <QTimer>
22 #include <QWidget>
23 
24 #include <score_plugin_recording_export.h>
25 
26 #include <verdigris>
27 
28 namespace Scenario
29 {
30 class ProcessModel;
31 }
32 namespace Explorer
33 {
34 class DeviceExplorerModel;
35 }
36 namespace Recording
37 {
38 struct RecordContext : public QObject
39 {
40  W_OBJECT(RecordContext)
41 public:
42  using clock = std::chrono::steady_clock;
44  RecordContext(const RecordContext& other) = delete;
45  RecordContext(RecordContext&& other) = delete;
46  RecordContext& operator=(const RecordContext& other) = delete;
47  RecordContext& operator=(RecordContext&& other) = delete;
48 
49  void start()
50  {
51  firstValueTime = clock::now();
52  startTimer();
53  }
54 
55  bool started() const
56  {
57  return firstValueTime.time_since_epoch() != clock::duration::zero();
58  }
59 
60  TimeVal time() const { return GetTimeDifference(firstValueTime); }
61 
62  double timeInDouble() const { return GetTimeDifferenceInDouble(firstValueTime); }
63 
64  const score::DocumentContext& context;
65  Scenario::ProcessModel& scenario;
67  RecordCommandDispatcher dispatcher;
68 
69  Scenario::Point point;
70  clock::time_point firstValueTime{};
71  QTimer timer;
72 
73 public:
74  void startTimer() W_SIGNAL(startTimer);
75 
76 public:
77  void on_startTimer()
78  {
79  context.document.view()->viewDelegate().getWidget()->setEnabled(false);
80  timer.start();
81  }
82  W_SLOT(on_startTimer)
83 };
84 
86 {
87  virtual ~RecordProvider();
88  virtual bool setup(const Box&, const RecordListening&) = 0;
89  virtual void stop() = 0;
90 };
91 
92 // A recording session.
93 class Recorder
94 {
95 public:
96  Recorder(RecordContext& ctx) //: m_context{ctx}
97  {
98  // Algorithm :
99  // 1. Get all selected addresses.
100  // 2. Generate the concrete recorders that match these addresses.
101  // Use settings to select them recursively or not..
102  // 3. Create a box corresponding to the case where we record
103  // in the void, in an existing interval, starting from a state / event...
104 
105  // Have a "record as" attribute on nodes to indicate if
106  // it should be recorded as a message, or automation, or ...
107  }
108 
109  bool setup() { return false; }
110 
111  void stop() { }
112 
113 private:
114  // RecordContext& m_context;
115  std::vector<std::unique_ptr<RecordProvider>> m_recorders;
116 };
117 
118 // Sets-up the recording of a single class.
119 template <typename T>
120 class SingleRecorder final : public QObject
121 {
122 public:
123  T recorder;
124 
126  : recorder{ctx}
127  {
128  }
129 
130  bool setup()
131  {
132  RecordContext& ctx = recorder.context;
134  // Get the listening of the selected addresses
135  auto recordListening = GetAddressesToRecordRecursive(ctx.explorer);
136  if(recordListening.empty())
137  return false;
138 
139  // Disable listening for everything
140  ctx.explorer.deviceModel().listening().stop();
141 
142  // Create the processes, etc.
143  Box box = CreateBox(ctx);
144 
145  if(!recorder.setup(box, recordListening))
146  {
147  ctx.explorer.deviceModel().listening().restore();
148  return false;
149  }
150 
152  ctx.timer.stop();
153  ctx.timer.setTimerType(Qt::PreciseTimer);
154  ctx.timer.setInterval(ReasonableUpdateInterval(recorder.count()));
155  QObject::connect(&ctx.timer, &QTimer::timeout, this, [&, box]() {
156  // Move end event by the current duration.
157  auto& cur_date = box.interval.date();
158  box.moveCommand.update(
159  ctx.scenario, {}, box.endEvent,
160  cur_date + GetTimeDifference(ctx.firstValueTime), 0, true);
161 
162  box.moveCommand.redo(ctx.context);
163  });
164 
165  // In case where the software is exited
166  // during recording.
167  QObject::connect(
169  [&]() { ctx.timer.stop(); });
170 
171  return true;
172  }
173 
174  void stop()
175  {
176  RecordContext& ctx = recorder.context;
177  ctx.timer.stop();
178 
179  recorder.stop();
180 
181  ctx.explorer.deviceModel().listening().restore(); // Commit
182  ctx.dispatcher.commit();
183  ctx.context.document.view()->viewDelegate().getWidget()->setEnabled(true);
184  }
185 
186 private:
187 };
188 
189 class SCORE_PLUGIN_RECORDING_EXPORT RecorderFactory : public score::InterfaceBase
190 {
191  SCORE_INTERFACE(RecorderFactory, "64999184-a705-4686-b967-14e8f79692f1")
192 public:
193  virtual ~RecorderFactory();
194 
195  virtual Priority matches(const Device::Node&, const score::DocumentContext& ctx) = 0;
196 
197  virtual std::unique_ptr<RecordProvider>
198  make(const Device::NodeList&, const score::DocumentContext& ctx) = 0;
199 };
200 }
Definition: DeviceExplorerModel.hpp:67
void identified_object_destroyed(IdentifiedObjectAbstract *o)
Will be called in the IdentifiedObjectAbstract destructor.
Definition: RecordProviderFactory.hpp:190
Definition: RecordProviderFactory.hpp:94
Definition: RecordProviderFactory.hpp:121
The core hierarchical and temporal process of score.
Definition: ScenarioModel.hpp:37
Base class for plug-in interfaces.
Definition: Interface.hpp:52
Main plug-in of score.
Definition: score-plugin-dataflow/Dataflow/PortItem.hpp:14
Definition: RecordTools.hpp:64
Definition: RecordProviderFactory.hpp:39
Definition: RecordProviderFactory.hpp:86
Definition: ScenarioPoint.hpp:13
Definition: TimeValue.hpp:21
Definition: ObjectMatches.hpp:6
Definition: DocumentContext.hpp:18