DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Module.cpp
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
3 #include "stdafx.h"
4 #include "moc_Module.cpp"
5 #include "Module.h"
6 #include "DynExpManager.h"
7 
8 namespace DynExp
9 {
11  {
12  bool IsExiting = false;
13  std::chrono::time_point<std::chrono::system_clock> LastMainLoopExecution; // LastUpdate.time_since_epoch() == 0 now.
14  auto ReturnCode = Util::DynExpErrorCodes::NoError;
15 
16  try
17  {
18  // Throw if Module->TreatModuleExceptionsAsWarnings() is true, but MaxAllowedSubsequentExceptions have been occurred
19  // in a row to avoid infinite loops due to an exception occurring in each pass.
20  unsigned int NumSubsequentExceptions = 0;
21  constexpr unsigned int MaxAllowedSubsequentExceptions = 10;
22 
23  auto& NewEventNotifier = Module->GetModuleData()->ModuleThreadOnly.GetNewEventNotifier();
24 
25  while (!IsExiting)
26  {
27  try
28  {
29  if (Module->IsExiting() || Instance.IsExiting())
30  IsExiting = true;
31 
32  if (!IsExiting)
33  {
34  if (!Instance.CareAboutWrappers())
35  {
36  if (!Module->IsPaused())
37  {
38  Module->ModuleThreadOnly.OnPause(Instance);
39  Module->SetPaused(true, Instance.GetNotReadyObjectNamesString());
40  }
41  else
42  Module->ModuleThreadOnly.SetReasonWhyPaused(Instance.GetNotReadyObjectNamesString());
43 
44  std::this_thread::sleep_for(std::chrono::milliseconds(100));
45  continue;
46  }
47  else if (Module->IsPaused())
48  {
49  Module->SetPaused(false);
50  Module->ModuleThreadOnly.OnResume(Instance);
51  }
52  }
53 
54  while (Module->GetModuleData()->GetNumEnqueuedEvents())
55  Module->ModuleThreadOnly.HandleEvent(Instance);
56 
57  if (!IsExiting)
58  {
59  auto MainLoopDelay = Module->GetMainLoopDelay();
60  auto Now = std::chrono::system_clock::now();
61 
62  if (Now - LastMainLoopExecution >= MainLoopDelay || MainLoopDelay == decltype(MainLoopDelay)::max())
63  {
64  ReturnCode = Module->ModuleThreadOnly.ModuleMainLoop(Instance);
65 
66  if (ReturnCode != Util::DynExpErrorCodes::NoError)
67  IsExiting = true;
68 
69  LastMainLoopExecution = Now;
70  }
71 
72  if (MainLoopDelay == decltype(MainLoopDelay)::max())
73  NewEventNotifier.Wait();
74  else if (MainLoopDelay.count() == 0)
75  std::this_thread::yield();
76  else
77  NewEventNotifier.Wait(MainLoopDelay);
78  }
79 
80  NumSubsequentExceptions = 0;
81  }
82  catch ([[maybe_unused]] const Util::LinkedObjectNotLockedException& e)
83  {
84  // In this case, terminate the module since this error cannot be fixed while the module is running.
85  throw;
86  }
87  catch ([[maybe_unused]] const Util::InvalidObjectLinkException& e)
88  {
89  // In this case, terminate the module since this error cannot be fixed while the module is running.
90  throw;
91  }
92  catch (const Util::Exception& e)
93  {
94  ++NumSubsequentExceptions;
95 
96  if (Module->TreatModuleExceptionsAsWarnings() && NumSubsequentExceptions < MaxAllowedSubsequentExceptions)
97  Module->SetWarning(e);
98  else
99  throw;
100  }
101  catch (const std::exception& e)
102  {
103  ++NumSubsequentExceptions;
104 
105  if (Module->TreatModuleExceptionsAsWarnings() && NumSubsequentExceptions < MaxAllowedSubsequentExceptions)
106  Module->SetWarning(e.what(), Util::DynExpErrorCodes::GeneralError);
107  else
108  throw;
109  }
110  // No catch (...) to terminate module in that case regardless of TreatExceptionsAsWarnings
111  // since we do not know at all what has happened.
112  }
113  }
114  catch (const Util::Exception& e)
115  {
116  Util::EventLog().Log("A module has been terminated because of the error reported below.", Util::ErrorType::Error);
117  Util::EventLog().Log(e);
118 
119  // std::abort() is called when (e.g. timeout) exception occurrs while setting the caught exception.
120  Module->GetModuleData()->ModuleThreadOnly.SetException(std::current_exception());
121  Module->ModuleThreadOnly.OnError(Instance);
122 
123  return e.ErrorCode;
124  }
125  catch (const std::exception& e)
126  {
127  Util::EventLog().Log("A module has been terminated because of the following error: " + std::string(e.what()), Util::ErrorType::Error);
128 
129  // std::abort() is called when (e.g. timeout) exception occurrs while setting the caught exception.
130  Module->GetModuleData()->ModuleThreadOnly.SetException(std::current_exception());
131  Module->ModuleThreadOnly.OnError(Instance);
132 
134  }
135  catch (...)
136  {
137  Util::EventLog().Log("A module has been terminated because of an unknown error.", Util::ErrorType::Error);
138 
139  // std::abort() is called when (e.g. timeout) exception occurrs while setting the caught exception.
140  Module->GetModuleData()->ModuleThreadOnly.SetException(std::current_exception());
141  Module->ModuleThreadOnly.OnError(Instance);
142 
144  }
145 
146  return ReturnCode;
147  }
148 
150  {
151  }
152 
154  {
155  if (!Event)
156  throw Util::InvalidArgException("Event cannot be nullptr.");
157 
158  EventQueue.push(std::move(Event));
160  }
161 
163  {
164  if (EventQueue.empty())
165  return nullptr;
166 
167  auto Event = std::move(EventQueue.front());
168  EventQueue.pop();
169 
170  return Event;
171  }
172 
174  {
175  ModuleException = nullptr;
176  EventQueueType().swap(EventQueue); // clear EventQueue
177 
179  }
180 
182  {
183  }
184 
186  {
187  }
188 
189  ModuleBase::ModuleBase(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params)
190  : RunnableObject(OwnerThreadID, std::move(Params)),
191  ModuleThreadOnly(*this), EventListenersOnly(*this),
192  ModuleData(std::move(dynamic_Params_cast<ModuleBase>(GetParams())->ModuleData))
193  {
194  if (!ModuleData)
195  throw Util::InvalidArgException("ModuleData cannot be nullptr.");
196  }
197 
199  {
200  }
201 
203  {
205  }
206 
208  {
210  }
211 
213  {
214  GetNonConstModuleData()->EnqueueEvent(std::move(Event));
215  }
216 
218  {
220  }
221 
223  {
225 
227 
228  {
229  // Locks ModuleData
230  auto ModuleDataPtr = GetModuleData();
231 
232  if (!ModuleDataPtr->GetNumEnqueuedEvents())
233  return;
234 
235  EventPtr = ModuleDataPtr->PopEvent();
236  } // ModuleData unlocked here
237 
238  if (EventPtr)
239  EventPtr->Invoke(Instance);
240  }
241 
243  {
245 
246  auto RegisteredEvent = std::find(RegisteredEvents.cbegin(), RegisteredEvents.cend(), &EventListeners);
247  if (RegisteredEvent != RegisteredEvents.cend())
248  return;
249 
250  RegisteredEvents.push_back(&EventListeners);
251  }
252 
254  {
256 
257  auto RegisteredEvent = std::find(RegisteredEvents.cbegin(), RegisteredEvents.cend(), &EventListeners);
258  if (RegisteredEvent == RegisteredEvents.cend())
259  return;
260 
261  RegisteredEvents.erase(RegisteredEvent);
262  }
263 
265  {
267 
268  return ModuleMainLoop(Instance);
269  }
270 
272  {
274 
275  OnPauseChild(Instance);
276  }
277 
279  {
281 
282  OnResumeChild(Instance);
283  }
284 
286  {
288 
289  try
290  {
291  OnErrorChild(Instance);
292  }
293  catch (const Util::Exception& e)
294  {
295  Util::EventLog().Log("Calling a module's error handler, the error listed below occurred.", Util::ErrorType::Error);
296  Util::EventLog().Log(e);
297  }
298  catch (const std::exception& e)
299  {
300  Util::EventLog().Log("Calling a module's error handler, the error listed below occurred.", Util::ErrorType::Error);
301  Util::EventLog().Log(e.what());
302  }
303  catch (...)
304  {
305  Util::EventLog().Log("Calling a module's error handler, an unknown error occurred.", Util::ErrorType::Error);
306  }
307  }
308 
310  {
311  ModuleData->ModuleBaseOnly.Reset();
312  RegisteredEvents.clear();
313 
315  }
316 
318  {
320 
322  *this,
325  ), this));
326  }
327 
329  {
330  GetModuleData()->ModuleBaseOnly.GetNewEventNotifier().Notify();
331  }
332 
333  void ModuleBase::TerminateChild(const std::chrono::milliseconds Timeout)
334  {
335  try
336  {
339  }
340  catch (const Util::Exception& e)
341  {
342  // Exception occurring while trying to issue an OnExit event is swallowed and logged. It is tried to terminate
343  // the module anyway.
344  Util::EventLog().Log("A module has been terminated whithout cleaning up since the error reported below has occurred while issuing an exit event.",
346  Util::EventLog().Log(e);
347  }
348  }
349 
350  std::unique_ptr<BusyDialog> ModuleBase::MakeStartupBusyDialogChild(QWidget* ParentWidget) const
351  {
352  auto StartupDialog = std::make_unique<BusyDialog>(ParentWidget);
353  StartupDialog->SetDescriptionText("Starting module's dependencies...");
354 
355  return StartupDialog;
356  }
357 
358  std::exception_ptr ModuleBase::GetExceptionChild(const std::chrono::milliseconds Timeout) const
359  {
360  using namespace std::chrono_literals;
361 
362  // If ModuleData cannot be locked because it is continuously locked by main/module thread, dead lock
363  // is avoided since GetModuleData throws Util::TimeoutException after timeout in this case.
364  // Short timeout only since main thread should not block.
366  }
367 
369  {
370  using namespace std::chrono_literals;
371  auto LockedModuleData = GetModuleData(ShortTimeoutDefault);
372 
373  auto Exception = GetExceptionUnsafe(LockedModuleData);
374  Util::ForwardException(Exception);
375 
376  return IsRunning() && !IsExiting();
377  }
378 
380  {
381  // Copy vector since EventListenersBase::Deregister() removes entry from RegisteredEvents
382  // via call to ModuleBase::RemoveRegisteredEvent().
383  auto Events = RegisteredEvents;
384 
385  for (auto Event : Events)
386  Event->Deregister(*this);
387  }
388 
389  ModuleInstance::ModuleInstance(ModuleBase& Owner, std::promise<void>&& ThreadExitedPromise,
390  const ModuleBase::ModuleDataGetterType ModuleDataGetter)
391  : RunnableInstance(Owner, std::move(ThreadExitedPromise)),
392  ModuleDataGetter(ModuleDataGetter)
393  {
394  }
395 
397  : RunnableInstance(std::move(Other)), ModuleDataGetter(Other.ModuleDataGetter)
398  {
399  }
400 
402  {
403  }
404 
405  constexpr Qt::WindowFlags QModuleWidget::GetQtWindowFlagsResizable()
406  {
407  return Qt::CustomizeWindowHint | Qt::WindowTitleHint |
408  Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
409  }
410 
412  {
413  return Qt::CustomizeWindowHint | Qt::WindowTitleHint |
414  Qt::WindowCloseButtonHint;
415  }
416 
417  QModuleWidget::QModuleWidget(QModuleBase& Owner, QWidget* Parent)
418  : QWidget(Parent), Owner(Owner), DynExpMgr(nullptr),
419  DockWindowShortcut(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_D), this)),
420  FocusMainWindowShortcut(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_0), this))
421  {
422  connect(DockWindowShortcut, &QShortcut::activated, this, &QModuleWidget::OnDockWindow);
423  connect(FocusMainWindowShortcut, &QShortcut::activated, this, &QModuleWidget::OnFocusMainWindow);
424  }
425 
426  Qt::WindowFlags QModuleWidget::GetQtWindowFlags() const noexcept
427  {
429  }
430 
432  {
433  return DynExpMgr ? DynExpMgr->GetDataSaveDirectory() : "";
434  }
435 
436  void QModuleWidget::SetDataSaveDirectory(std::string_view Directory) const
437  {
438  DynExpMgr->SetDataSaveDirectory(Directory);
439  }
440 
441  void QModuleWidget::EnableDockWindowShortcut(bool Enable) noexcept
442  {
443  DockWindowShortcut->setEnabled(Enable);
444  }
445 
446  void QModuleWidget::closeEvent(QCloseEvent* Event)
447  {
448  if (DynExpMgr)
449  if (QMessageBox::question(this, "DynExp - Stop module?",
450  QString::fromStdString("Do you want to stop this module?"),
451  QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::No)
452  == QMessageBox::StandardButton::Yes)
453  if (DynExpMgr->StopItem(&Owner))
454  {
455  Event->accept();
456  return;
457  }
458 
459  Event->ignore();
460  }
461 
463  {
465  }
466 
468  {
469  Owner.SetFocus();
470  }
471 
473  {
475  }
476 
477  QModuleDockWidget::QModuleDockWidget(QModuleBase& Owner, QWidget* Parent, Qt::WindowFlags Flags)
478  : QDockWidget(Parent, Flags), Owner(Owner)
479  {
480  }
481 
482  void QModuleDockWidget::closeEvent(QCloseEvent* Event)
483  {
484  Event->ignore();
486  }
487 
488  // Delegate Ctrl+1 - Ctrl+9 to main window
489  void QModuleDockWidget::keyPressEvent(QKeyEvent* Event)
490  {
491  if (Event->modifiers().testFlag(Qt::ControlModifier))
492  if (Event->key() >= Qt::Key_1 && Event->key() <= Qt::Key_1 + 8)
493  {
496 
497  return;
498  }
499 
500  QDockWidget::keyPressEvent(Event);
501  }
502 
504  {
506  }
507 
508  void WindowStyleParamsExtension::ApplyTo(QWidget& Widget, bool Show) const
509  {
510  if (WindowState == WindowStateType::Minimized)
511  Widget.showMinimized();
512  else
513  {
514  QPoint WindowPos(WindowPosX, WindowPosY);
515  QSize WindowSize(Util::NumToT<int>(WindowWidth.Get()), Util::NumToT<int>(WindowHeight.Get()));
516  if (!WindowSize.isEmpty())
517  {
518  Widget.move(WindowPos);
519  Widget.resize(WindowSize);
520  }
521 
522  if (Show)
523  {
524  if (WindowState == WindowStateType::Maximized)
525  Widget.showMaximized();
526  else
527  Widget.showNormal();
528  }
529  }
530  }
531 
532  void WindowStyleParamsExtension::FromWidget(const QWidget& Widget)
533  {
534  if (Widget.isMinimized())
535  WindowState = WindowStateType::Minimized;
536  else
537  {
538  WindowState = Widget.isMaximized() ? WindowStateType::Maximized : WindowStateType::Normal;
539 
540  auto WindowPos = Widget.pos();
541  auto WindowSize = Widget.size();
542  WindowPosX = WindowPos.x();
543  WindowPosY = WindowPos.y();
544  WindowWidth = WindowSize.width();
545  WindowHeight = WindowSize.height();
546  }
547  }
548 
550  {
551  }
552 
554  {
555  }
556 
557  QModuleBase::QModuleBase(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType&& Params)
558  : ModuleBase(OwnerThreadID, std::move(Params)), Widget(nullptr), MdiArea(nullptr)
559  {
560  }
561 
563  {
564  }
565 
566  QAction& QModuleBase::InitUI(DynExpManager& DynExpMgr, QMdiArea* const MdiArea)
567  {
568  if (!MdiArea)
569  throw Util::InvalidArgException("MdiArea cannot be nullptr.");
570 
571  // Make UI
572  auto WidgetPtr = MakeUIWidget();
573  if (!WidgetPtr)
574  throw Util::InvalidDataException("Overridden QModuleBase::MakeUIWidget() must not return nullptr.");
575  Widget = WidgetPtr.get();
576  Widget->DynExpMgr = &DynExpMgr;
577 
578  // Initialize container widgets
579  this->MdiArea = MdiArea;
580  MdiSubWindow = std::make_unique<QMdiSubWindow>(); // Gets a parent when inserting into MdiArea
581  DockWidget = std::make_unique<QModuleDockWidget>(*this, nullptr, Widget->GetQtWindowFlags()); // nullptr parent to make it floating.
582  DockWidget->setAllowedAreas(Qt::DockWidgetArea::NoDockWidgetArea);
583  DockWidget->setFeatures(QDockWidget::DockWidgetFeature::DockWidgetClosable | QDockWidget::DockWidgetFeature::DockWidgetFloatable);
584  DockWidget->setLocale(QLocale(QLocale::Language::English, QLocale::Country::UnitedStates)); // For number format.
585 
586  // Insert new Widget into main MDI area. MdiSubWindow becomes Widget's parent.
587  MdiSubWindow->setWidget(WidgetPtr.release());
588  MdiArea->addSubWindow(MdiSubWindow.get(), Widget->GetQtWindowFlags());
590 
593 
594  // Create action to push module's window into focus.
595  // Longer timeout while fetching object name since it could take longer if the entire project is started (empiric value).
596  ModuleWindowFocusAction = std::make_unique<QAction>(QString::fromStdString(GetObjectName(std::chrono::seconds(1))));
597  QObject::connect(ModuleWindowFocusAction.get(), &QAction::triggered, Widget, &QModuleWidget::OnFocusWindow);
598 
599  MdiSubWindow->show();
600 
601  return *ModuleWindowFocusAction;
602  }
603 
605  {
606  // Widget is deleted by its respective parent's destructor.
607  MdiSubWindow.reset();
608  DockWidget.reset();
609  ModuleWindowFocusAction.reset();
610  }
611 
613  {
614  if (!Widget)
615  return;
616 
617  Widget->setEnabled(false);
618  }
619 
621  {
622  if (!Widget)
623  return;
624 
625  Widget->setEnabled(true);
627  }
628 
630  {
632  throw Util::InvalidStateException("UI widget has not been created yet.");
633 
634  if (Widget->parent() != MdiSubWindow.get())
636  else
637  ModuleWindowFocusAction->setIcon(QIcon());
638  }
639 
640  void QModuleBase::DockWindow() noexcept
641  {
642  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
643  return;
644 
645  DockWidget->hide();
646  MdiSubWindow->setWidget(Widget); // Sets Widget parent.
647  MdiArea->addSubWindow(MdiSubWindow.get(), Widget->GetQtWindowFlags());
648  MdiSubWindow->show();
650  }
651 
653  {
654  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
655  return;
656 
657  MdiArea->removeSubWindow(MdiSubWindow.get());
658  MdiSubWindow->setWidget(nullptr);
659  Widget->setParent(DockWidget.get());
660  DockWidget->setWidget(Widget);
661  DockWidget->showNormal();
663  }
664 
666  {
667  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
668  return;
669 
670  if (Widget->parent() == MdiSubWindow.get())
671  UndockWindow();
672  else
673  DockWindow();
674 
675  SetFocus();
676  }
677 
678  void QModuleBase::SetFocus() noexcept
679  {
680  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
681  return;
682 
683  if (Widget->parent() != MdiSubWindow.get())
684  {
685  Widget->activateWindow();
686  Widget->raise();
687  }
688  else
689  {
690  FocusMainWindow();
691  MdiArea->setActiveSubWindow(MdiSubWindow.get());
692  }
693  }
694 
696  {
697  if (!Widget)
698  return;
699 
701  }
702 
703  void QModuleBase::SendKeyPressEventToMainWindow(QKeyEvent* Event) noexcept
704  {
705  if (!Widget)
706  return;
707 
708  Widget->DynExpMgr->PostKeyPressEvent(Event);
709  }
710 
712  {
713  // Just because this is the default and we don't want to throw here.
714  if (!Widget || !MdiSubWindow)
715  return true;
716 
717  return Widget->parent() == MdiSubWindow.get();
718  }
719 
721  {
722  if (!Widget || !MdiSubWindow)
723  throw Util::InvalidStateException("UI widget has not been created yet.");
724 
725  if (Widget->parent() != MdiSubWindow.get())
726  return false;
727 
728  return MdiArea->currentSubWindow() == MdiSubWindow.get();
729  }
730 
732  {
733  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
734  return;
735 
736  auto ModuleParams = DynExp::dynamic_Params_cast<QModuleBase>(GetParams());
737  if (ModuleParams->WindowStyleParams.WindowDockingState == WindowStyleParamsExtension::WindowDockingStateType::Docked)
738  DockWindow();
739  else
740  UndockWindow();
741  ModuleParams->WindowStyleParams.ApplyTo(IsWindowDocked() ? static_cast<QWidget&>(*MdiSubWindow) : static_cast<QWidget&>(*DockWidget));
742  }
743 
745  {
746  if (!Widget || !MdiArea || !MdiSubWindow || !DockWidget)
747  return;
748 
749  auto ModuleParams = DynExp::dynamic_Params_cast<QModuleBase>(GetParams());
750  ModuleParams->WindowStyleParams.FromWidget(IsWindowDocked() ? static_cast<QWidget&>(*MdiSubWindow) : static_cast<QWidget&>(*DockWidget));
751  ModuleParams->WindowStyleParams.WindowDockingState = IsWindowDocked() ?
752  WindowStyleParamsExtension::WindowDockingStateType::Docked : WindowStyleParamsExtension::WindowDockingStateType::Undocked;
753  }
754 
755  void QModuleBase::SetWidgetProperties(QWidget* const WindowWidget) const
756  {
757  if (!WindowWidget)
758  throw Util::InvalidArgException("WindowWidget cannot be nullptr.");
759 
760  // Longer timeout while fetching object name since it could take longer if the entire project is started (empiric value).
761  WindowWidget->setWindowTitle(QString::fromStdString(GetObjectName(std::chrono::seconds(1))));
762  WindowWidget->setWindowIcon(QIcon(DynExpUI::Icons::Module));
763 
764  if (!Widget->AllowResize())
765  WindowWidget->layout()->setSizeConstraint(QLayout::SetFixedSize);
766  }
767 
769  {
771  }
772 }
Implements DynExp's main UI window called DynExpManager.
Implementation of DynExp module objects.
Implements DynExp's main window as a Qt-based user interface (UI).
Definition: DynExpManager.h:21
void SetDataSaveDirectory(std::string_view Directory) const
Sets a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to st...
void FocusMainWindow() noexcept
Focuses/activates DynExp's main window and moves it on top of other windows if possible.
std::string GetDataSaveDirectory() const
Recalls a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to...
bool StopItem(DynExp::RunnableObject *Object, bool Force=false) noexcept
Calls DynExp::RunnableObject::Terminate() on a DynExp::RunnableObject instance.
virtual ~EventBase()=0
Definition: Module.cpp:149
Common base class for all managers of event listeners of type TypedEventListeners....
Definition: Module.h:866
virtual ~InterModuleEventBase()=0
Definition: Module.cpp:401
Base class for modules. Modules implement programs on their own (e.g. measurement protocols or server...
Definition: Module.h:392
void TerminateChild(const std::chrono::milliseconds Timeout) override final
Signals derived classes that terminating the RunnableObject instance's thread is about to be requeste...
Definition: Module.cpp:333
ModuleDataTypeSyncPtrType GetModuleData(const std::chrono::milliseconds Timeout=GetModuleDataTimeoutDefault)
Locks the mutex of the module data class instance ModuleData assigned to this ModuleBase instance and...
Definition: Module.cpp:202
virtual void OnErrorChild(ModuleInstance &Instance) const
This handler gets called just before the module thread terminates due to an exception....
Definition: Module.h:673
void OnPause(ModuleInstance &Instance)
This handler gets called just after the module pauses due to e.g. an error in an instrument the modul...
Definition: Module.cpp:271
void NotifyChild() override final
Notify derived classes that some state has changed (e.g. the termination of Thread is requested) and ...
Definition: Module.cpp:328
void RunChild() override final
Refer to Run().
Definition: Module.cpp:317
void OnDeregisterEvents(ModuleInstance *Instance) const
This event is triggered after the OnExit event. It calls EventListenersBase::Deregister() for all man...
Definition: Module.cpp:379
static auto GetExceptionUnsafe(const ModuleDataTypeSyncPtrConstType &ModuleDataPtr)
Getter for ModuleDataBase::ModuleException assuming that the module data has already been locked.
Definition: Module.h:610
virtual void OnInit(ModuleInstance *Instance) const
This event is triggered right before the module thread starts. Override it to lock instruments this m...
Definition: Module.h:719
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
Definition: Module.h:743
virtual ~ModuleBase()=0
Definition: Module.cpp:198
void ResetImpl(dispatch_tag< RunnableObject >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Definition: Module.cpp:309
virtual void OnResumeChild(ModuleInstance &Instance) const
This handler gets called just after the module resumed from a paused state. Override OnResumeChild() ...
Definition: Module.h:672
void MakeAndEnqueueEvent(ReceiverType *Receiver, EventType EventFuncPtr, ArgsTs &&...Args) const
Calls MakeEvent() to construct a new event and subsequently enqueues the event into the module's even...
Definition: Module.h:780
virtual void OnExit(ModuleInstance *Instance) const
This event is triggered right before the module thread terminates (not due to an exception,...
Definition: Module.h:728
void EnqueueEvent(ModuleDataBase::EventPtrType &&Event) const
Enqueues Event at the module event queue's back. Takes ownership of the event. Notifies the module ow...
Definition: Module.cpp:212
void RemoveRegisteredEvent(EventListenersBase &EventListeners)
Removes a manager of event listeners from RegisteredEvents if it was added before....
Definition: Module.cpp:253
void HandleEvent(ModuleInstance &Instance)
Executes and removes the next pending event from the module's event queue.
Definition: Module.cpp:222
ModuleBase(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs a ModuleBase instance.
Definition: Module.cpp:189
Util::SynchronizedPointer< const ModuleDataType > ModuleDataTypeSyncPtrConstType
Alias for the return type of ModuleBase::GetModuleData() const. Data class instances wrapped into Uti...
Definition: Module.h:462
void OnResume(ModuleInstance &Instance)
This handler gets called just after the module resumed from a paused state. Override OnResumeChild() ...
Definition: Module.cpp:278
Util::SynchronizedPointer< ModuleDataType > ModuleDataTypeSyncPtrType
Alias for the return type of ModuleBase::GetModuleData(). Data class instances wrapped into Util::Syn...
Definition: Module.h:456
std::unique_ptr< BusyDialog > MakeStartupBusyDialogChild(QWidget *ParentWidget) const override final
Override to make this function return a pointer to a BusyDialog instance. Refer to Run().
Definition: Module.cpp:350
std::vector< EventListenersBase * > RegisteredEvents
Holds a list of pointers to managers of event listeners of the events this module has registered/subs...
Definition: Module.h:750
void OnError(ModuleInstance &Instance)
This handler gets called just before the module thread terminates due to an exception....
Definition: Module.cpp:285
virtual Util::DynExpErrorCodes::DynExpErrorCodes ModuleMainLoop(ModuleInstance &Instance)=0
Module main loop. The function is executed periodically by the module thread. Also refer to GetMainLo...
void AddRegisteredEvent(EventListenersBase &EventListeners)
Adds a manager of event listeners to RegisteredEvents if it was not already added before....
Definition: Module.cpp:242
std::exception_ptr GetExceptionChild([[maybe_unused]] const std::chrono::milliseconds Timeout) const override final
Definition: Module.cpp:358
static constexpr auto GetModuleDataTimeoutDefault
Determines the default timeout for GetModuleData() to lock the mutex synchronizing the module's data ...
Definition: Module.h:513
bool IsReadyChild() const override final
Returns wheter this Object instance is ready (e.g. it is running or connected to a hardware device) a...
Definition: Module.cpp:368
virtual void OnPauseChild(ModuleInstance &Instance) const
This handler gets called just after the module pauses due to e.g. an error in an instrument the modul...
Definition: Module.h:671
ModuleDataTypeSyncPtrType GetNonConstModuleData(const std::chrono::milliseconds Timeout=GetModuleDataTimeoutDefault) const
Always allows ModuleBase to obtain a non-const pointer to the module's data - even in const event fun...
Definition: Module.cpp:217
Util::DynExpErrorCodes::DynExpErrorCodes ExecModuleMainLoop(ModuleInstance &Instance)
Runs ModuleMainLoop().
Definition: Module.cpp:264
virtual ~ModuleConfiguratorBase()=0
Definition: Module.cpp:185
std::exception_ptr ModuleException
Used to transfer exceptions from the module thread to the main (user interface) thread....
Definition: Module.h:330
Util::OneToOneNotifier NewEventNotifier
Notifies the thread of the module which owns the respective ModuleDataBase's instance when an event h...
Definition: Module.h:323
std::queue< EventPtrType > EventQueueType
A module's event queue is a FIFO queue owning the enqueued events.
Definition: Module.h:181
std::unique_ptr< EventBase > EventPtrType
Pointer owning an event.
Definition: Module.h:176
void Reset()
Resets the ModuleDataBase's instance and calls ResetImpl(dispatch_tag<ModuleDataBase>) subsequently.
Definition: Module.cpp:173
void EnqueueEvent(EventPtrType &&Event)
Enqueues Event at the module event queue's back. Takes ownership of the event. Notifies the module ow...
Definition: Module.cpp:153
EventQueueType EventQueue
FIFO event queue of the module which owns the respective ModuleDataBase's instance.
Definition: Module.h:316
virtual void ResetImpl(dispatch_tag< ModuleDataBase >)
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
Definition: Module.h:310
EventPtrType PopEvent()
Removes one event from the event queue's front and returns the event. Ownership of the event is trans...
Definition: Module.cpp:162
Refer to ParamsBase::dispatch_tag.
Definition: Module.h:189
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition: Module.h:793
bool IsExiting() const noexcept
Getter for ShouldExit.
Definition: Module.h:820
ModuleInstance(ModuleBase &Owner, std::promise< void > &&ThreadExitedPromise, const ModuleBase::ModuleDataGetterType ModuleDataGetter)
Constructs a non-empty RunnableInstance instance.
Definition: Module.cpp:389
virtual ~ModuleParamsBase()=0
Definition: Module.cpp:181
ParamsConstTypeSyncPtrType GetParams(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Locks the mutex of the parameter class instance Params assigned to this Object instance and returns a...
Definition: Object.cpp:436
auto GetObjectName(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns the name of this Object instance.
Definition: Object.h:2128
Refer to ParamsBase::dispatch_tag.
Definition: Object.h:2018
Base class for modules with a Qt-based user interface. Derive from this class to implement modules wi...
Definition: Module.h:1344
void DockUndockWindow() noexcept
Toggles the docking state of Widget. Does nothing if any of Widget, MdiArea, MdiSubWindow,...
Definition: Module.cpp:665
virtual ~QModuleBase()=0
Definition: Module.cpp:562
virtual void UpdateParamsFromWindowStatesChild() override
UpdateParamsFromWindowStates() only calls UpdateParamsFromWindowStatesChild(). Override UpdateParamsF...
Definition: Module.cpp:744
QModuleWidget * Widget
User interface widget belonging to the module.
Definition: Module.h:1491
virtual void RestoreWindowStatesFromParamsChild() override
RestoreWindowStatesFromParams() only calls RestoreWindowStatesFromParamsChild(). Override RestoreWind...
Definition: Module.cpp:731
bool IsActiveWindow()
Checks whether Widget is docked and active.
Definition: Module.cpp:720
void FocusMainWindow() noexcept
Focuses/activates DynExp's main window calling DynExpManager::FocusMainWindow(). Does nothing if Widg...
Definition: Module.cpp:695
void DisableUI()
Disables all user interface controls in Widget. Does nothing if Widget is nullptr.
Definition: Module.cpp:612
bool IsWindowDocked() noexcept
Checks whether Widget is docked.
Definition: Module.cpp:711
virtual void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter)
Use this function to update the module's user interface widget according to the module data obtained ...
Definition: Module.h:1488
QMdiArea * MdiArea
Pointer to DynExpManager's QMdiArea.
Definition: Module.h:1496
void UndockWindow() noexcept
Undocks Widget from MdiArea. Does nothing if any of Widget, MdiArea, MdiSubWindow,...
Definition: Module.cpp:652
void SetWidgetProperties(QWidget *const WindowWidget) const
Used by InitUI() to set the widget properties (such as title, icon, size constraints) of MdiSubWindow...
Definition: Module.cpp:755
std::unique_ptr< QModuleDockWidget > DockWidget
Frame for Widget when the module window is undocked from MdiArea.
Definition: Module.h:1493
void SetFocus() noexcept
Focuses/activates Widget and moves it on top of other windows if possible. Does nothing if any of Wid...
Definition: Module.cpp:678
void HideUI()
Removes MdiSubWindow, DockWidget, and ModuleWindowFocusAction setting them to nullptr.
Definition: Module.cpp:604
void SendKeyPressEventToMainWindow(QKeyEvent *Event) noexcept
Sends a Qt key press event to DynExp's main window calling DynExpManager::PostKeyPressEvent()....
Definition: Module.cpp:703
void UpdateUI()
Enables the user interface controls in Widget. Does nothing if Widget is nullptr. Calls UpdateUIChild...
Definition: Module.cpp:620
QAction & InitUI(DynExpManager &DynExpMgr, QMdiArea *const MdiArea)
Sets up the module's user interface widgets and window frames. Called by the main user interface thre...
Definition: Module.cpp:566
std::unique_ptr< QMdiSubWindow > MdiSubWindow
Frame for Widget when the module window is docked to MdiArea.
Definition: Module.h:1492
QModuleBase(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType &&Params)
Constructs a QModuleBase instance.
Definition: Module.cpp:557
void UpdateModuleWindowFocusAction()
Updates the icon assigned to ModuleWindowFocusAction depending on whether Widget is docked to or undo...
Definition: Module.cpp:629
void DockWindow() noexcept
Docks Widget to MdiArea. Does nothing if any of Widget, MdiArea, MdiSubWindow, or DockWidget are null...
Definition: Module.cpp:640
virtual std::unique_ptr< QModuleWidget > MakeUIWidget()=0
Used by InitUI() as a factory function for the module's user interface widget. Create the widget here...
std::unique_ptr< QAction > ModuleWindowFocusAction
Qt action to push module window into focus. When triggered, QModuleWidget::OnFocusWindow() in invoked...
Definition: Module.h:1494
void ResetImpl(dispatch_tag< ModuleBase >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Definition: Module.cpp:768
virtual ~QModuleConfiguratorBase()=0
Definition: Module.cpp:553
void ResetImpl(dispatch_tag< ModuleDataBase >) override final
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
Definition: Module.cpp:503
QModuleBase & Owner
Module owning this user interface window.
Definition: Module.h:1213
virtual void keyPressEvent(QKeyEvent *Event) override
Qt event indicating that keys were pressed when the QModuleDockWidget window was focused....
Definition: Module.cpp:489
virtual void closeEvent(QCloseEvent *Event) override
Qt event indicating that the QModuleDockWidget window is closed. Docks the module window again to Dyn...
Definition: Module.cpp:482
QModuleDockWidget(QModuleBase &Owner, QWidget *Parent, Qt::WindowFlags Flags)
Constructs a QModuleDockWidget instance.
Definition: Module.cpp:477
virtual ~QModuleParamsBase()=0
Definition: Module.cpp:549
void OnDockWindow()
Qt slot called when DockWindowShortcut is activated, calls QModuleBase::DockUndockWindow().
Definition: Module.cpp:462
virtual bool AllowResize() const noexcept
Indicates the resizing behavior of the user interface window. Override to adjust.
Definition: Module.h:1121
Qt::WindowFlags GetQtWindowFlags() const noexcept
Depending on thr return value of AllowResize(), returns either the return value of GetQtWindowFlagsRe...
Definition: Module.cpp:426
void OnFocusWindow()
Qt slot called when QModuleBase::ModuleWindowFocusAction is triggered, calls QModuleBase::SetFocus().
Definition: Module.cpp:467
virtual void closeEvent(QCloseEvent *Event) override
Qt event indicating that the module window is closed. Asks the user whether to terminate the module....
Definition: Module.cpp:446
QModuleBase & Owner
Module owning this user interface window (reference, because it should never change nor be nullptr).
Definition: Module.h:1162
constexpr static Qt::WindowFlags GetQtWindowFlagsResizable()
Default Qt window flags for resizable module windows.
Definition: Module.cpp:405
QModuleWidget(QModuleBase &Owner, QWidget *Parent=nullptr)
Constructs a QModuleWidget instance.
Definition: Module.cpp:417
void OnFocusMainWindow()
Qt slot called when FocusMainWindowShortcut is activated, calls QModuleBase::FocusMainWindow().
Definition: Module.cpp:472
constexpr static Qt::WindowFlags GetQtWindowFlagsNonResizable()
Default Qt window flags for non-resizable module windows.
Definition: Module.cpp:411
QShortcut * FocusMainWindowShortcut
Shortcut (Ctrl + 0) to activate/focus DynExp's main window.
Definition: Module.h:1166
std::string GetDataSaveDirectory() const
Recalls a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to...
Definition: Module.cpp:431
QShortcut * DockWindowShortcut
Shortcut (Ctrl + D) to dock/undock a module window to/from DynExp's main window.
Definition: Module.h:1165
void SetDataSaveDirectory(std::string_view Directory) const
Sets a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to st...
Definition: Module.cpp:436
void EnableDockWindowShortcut(bool Enable) noexcept
Enables/disables DockWindowShortcut.
Definition: Module.cpp:441
DynExpManager * DynExpMgr
DynExp's main window (pointer, because it is set later by QModuleBase::InitUI()).
Definition: Module.h:1163
Defines data for a thread belonging to a RunnableObject instance. This data is only accessed by the R...
Definition: Object.h:3505
std::string GetNotReadyObjectNamesString() const
Finds all linked Object instances Owner makes use of which are not in a ready state and builds a stri...
Definition: Object.cpp:815
bool CareAboutWrappers()
Unregisters owned LinkedObjectWrapper instances from their destiny resources in case of the respectiv...
Definition: Object.cpp:776
Defines an Object which possesses a thread it runs in. The RunnableObject can be started and stopped ...
Definition: Object.h:2426
std::promise< void > MakeThreadExitedPromise()
Helper function to be used by overridden RunChild() functions in derived classes to (re)initialize th...
Definition: Object.cpp:643
static constexpr auto ShortTimeoutDefault
Default timeout e.g. used as a default for calls to InstrumentBase::GetInstrumentData or ModuleBase::...
Definition: Object.h:2489
bool IsExiting() const noexcept
Returns ShouldExit.
Definition: Object.h:2552
void StoreThread(std::thread &&Thread) noexcept
Stores a thread constructed by a derived class overriding RunChild() in Thread taking ownership of th...
Definition: Object.cpp:651
void EnsureCallFromRunnableThread() const
Asserts that the call to this function is performed from the RunnableObject instance's thread by call...
Definition: Object.cpp:661
bool IsRunning() const noexcept
Returns Running.
Definition: Object.h:2550
ParamsBase::Param< unsigned int > WindowWidth
Window width.
Definition: Module.h:1296
ParamsBase::Param< int > WindowPosY
Window y coordinate.
Definition: Module.h:1295
ParamsBase::Param< int > WindowPosX
Window x coordinate.
Definition: Module.h:1294
ParamsBase::Param< WindowStateType > WindowState
Window show state.
Definition: Module.h:1298
void FromWidget(const QWidget &Widget)
Assigns styles applied to Widget to the bundled parameters.
Definition: Module.cpp:532
void ApplyTo(QWidget &Widget, bool Show=true) const
Applies the bundled style parameters to Widget.
Definition: Module.cpp:508
ParamsBase::Param< unsigned int > WindowHeight
Window height.
Definition: Module.h:1297
Wraps a member function of some object and stores its default arguments. Moving from CallableMemberWr...
Definition: Util.h:448
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
Definition: Util.cpp:309
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
Definition: Exception.h:51
const int ErrorCode
DynExp error code from DynExpErrorCodes::DynExpErrorCodes
Definition: Exception.h:106
An invalid argument like a null pointer has been passed to a function.
Definition: Exception.h:137
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
Definition: Exception.h:163
Thrown when RunnableInstance cannot lock an object to be used by another object due to an invalid lin...
Definition: Exception.h:344
An operation cannot be performed currently since the related object is in an invalid state like an er...
Definition: Exception.h:150
Thrown when RunnableInstance::LockObject() has not been called on an object link parameter to establi...
Definition: Exception.h:329
void Notify()
Set notification to stop waiting (sets EventOccurred to true).
Definition: Util.cpp:69
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition: Util.h:170
constexpr auto UndockedWindow
constexpr auto Module
DynExp's main namespace contains the implementation of DynExp including classes to manage resources (...
T::ParamsType * dynamic_Params_cast(ParamsBasePtrType::element_type *Params)
Casts the parameter base class to a derived Object's parameter class.
Definition: Object.h:1835
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition: Object.h:1807
int ModuleThreadMain(ModuleInstance Instance, ModuleBase *const Module)
Modules run in their own thread. This is the module thread's main function.
Definition: Module.cpp:10
DynExpErrorCodes
DynExp's error codes
Definition: Exception.h:22
void ForwardException(std::exception_ptr e)
Wraps the exception passed to the function in a ForwardedException and throws the ForwardedException....
Definition: Exception.cpp:30
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Definition: Util.cpp:509
std::chrono::duration< double > seconds
Extends std::chrono by a duration data type for seconds capable of storing fractions of seconds.
Definition: Util.h:761
Accumulates include statements to provide a precompiled header.