4#include "moc_Module.cpp"
12 InstancePtr->BlockUntilReadyToStart();
14 auto const Module =
static_cast<ModuleBase*
>(BaseObject);
16 bool IsExiting =
false;
17 std::chrono::time_point<std::chrono::system_clock> LastMainLoopExecution;
24 unsigned int NumSubsequentExceptions = 0;
25 constexpr unsigned int MaxAllowedSubsequentExceptions = 10;
27 auto& NewEventNotifier = Module->GetModuleData()->ModuleThreadOnly.GetNewEventNotifier();
33 if (Module->IsExiting() || Instance.IsExiting())
38 if (!Instance.CareAboutWrappers())
40 if (!Module->IsPaused())
42 Module->ModuleThreadOnly.OnPause(Instance);
43 Module->SetPaused(
true, Instance.GetNotReadyObjectNamesString());
46 Module->ModuleThreadOnly.SetReasonWhyPaused(Instance.GetNotReadyObjectNamesString());
48 std::this_thread::sleep_for(std::chrono::milliseconds(100));
51 else if (Module->IsPaused())
53 Module->SetPaused(
false);
54 Module->ModuleThreadOnly.OnResume(Instance);
58 while (Module->GetModuleData()->GetNumEnqueuedEvents())
59 Module->ModuleThreadOnly.HandleEvent(Instance);
63 auto MainLoopDelay = Module->GetMainLoopDelay();
64 auto Now = std::chrono::system_clock::now();
66 if (Now - LastMainLoopExecution >= MainLoopDelay || MainLoopDelay ==
decltype(MainLoopDelay)::max())
68 ReturnCode = Module->ModuleThreadOnly.ModuleMainLoop(Instance);
73 LastMainLoopExecution = Now;
76 if (MainLoopDelay ==
decltype(MainLoopDelay)::max())
77 NewEventNotifier.Wait();
78 else if (MainLoopDelay.count() == 0)
79 std::this_thread::yield();
81 NewEventNotifier.Wait(MainLoopDelay);
84 NumSubsequentExceptions = 0;
98 ++NumSubsequentExceptions;
100 if (Module->TreatModuleExceptionsAsWarnings() && NumSubsequentExceptions < MaxAllowedSubsequentExceptions)
101 Module->SetWarning(e);
105 catch (
const std::exception& e)
107 ++NumSubsequentExceptions;
109 if (Module->TreatModuleExceptionsAsWarnings() && NumSubsequentExceptions < MaxAllowedSubsequentExceptions)
123 Module->ModuleThreadOnly.SetException(std::current_exception());
124 Module->ModuleThreadOnly.OnError(Instance);
128 catch (
const std::exception& e)
132 Module->ModuleThreadOnly.SetException(std::current_exception());
133 Module->ModuleThreadOnly.OnError(Instance);
141 Module->ModuleThreadOnly.SetException(std::current_exception());
142 Module->ModuleThreadOnly.OnError(Instance);
195 ModuleException = Exception;
208 ModuleThreadOnly(*this), EventListenersOnly(*this),
249 if (!ModuleDataPtr->GetNumEnqueuedEvents())
252 EventPtr = ModuleDataPtr->PopEvent();
256 EventPtr->Invoke(Instance);
289 GetModuleData()->ModuleBaseOnly.SetException(Exception);
294 ModuleData->ModuleBaseOnly.IndicateException();
325 catch (
const std::exception& e)
357 GetModuleData()->ModuleBaseOnly.GetNewEventNotifier().Notify();
371 Util::EventLog().
Log(
"A module has been terminated whithout cleaning up since the error reported below has occurred while issuing an exit event.",
379 auto StartupDialog = std::make_unique<BusyDialog>(ParentWidget);
380 StartupDialog->SetDescriptionText(
"Starting module's dependencies...");
382 return StartupDialog;
387 using namespace std::chrono_literals;
397 using namespace std::chrono_literals;
412 for (
auto Event : Events)
413 Event->Deregister(*
this);
419 ModuleDataGetter(ModuleDataGetter)
424 :
RunnableInstance(std::move(Other)), ModuleDataGetter(Other.ModuleDataGetter)
441 return Qt::CustomizeWindowHint | Qt::WindowTitleHint |
442 Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
447 return Qt::CustomizeWindowHint | Qt::WindowTitleHint |
448 Qt::WindowCloseButtonHint;
452 : QWidget(Parent), Owner(Owner), DynExpMgr(nullptr),
453 DockWindowShortcut(new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_D), this)),
454 FocusMainWindowShortcut(new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_0), this))
477 DockWindowShortcut->setEnabled(Enable);
483 if (QMessageBox::question(
this,
"DynExp - Stop module?",
484 QString::fromStdString(
"Do you want to stop this module?"),
485 QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::No)
486 == QMessageBox::StandardButton::Yes)
512 : QDockWidget(Parent, Flags), Owner(Owner)
525 if (Event->modifiers().testFlag(Qt::ControlModifier))
526 if (Event->key() >= Qt::Key_1 && Event->key() <= Qt::Key_1 + 8)
534 QDockWidget::keyPressEvent(Event);
545 Widget.showMinimized();
550 if (!WindowSize.isEmpty())
552 Widget.move(WindowPos);
553 Widget.resize(WindowSize);
559 Widget.showMaximized();
568 if (Widget.isMinimized())
574 auto WindowPos = Widget.pos();
575 auto WindowSize = Widget.size();
592 :
ModuleBase(OwnerThreadID, std::move(Params)), Widget(nullptr), MdiArea(nullptr)
616 DockWidget->setAllowedAreas(Qt::DockWidgetArea::NoDockWidgetArea);
617 DockWidget->setFeatures(QDockWidget::DockWidgetFeature::DockWidgetClosable | QDockWidget::DockWidgetFeature::DockWidgetFloatable);
618 DockWidget->setLocale(QLocale(QLocale::Language::English, QLocale::Country::UnitedStates));
651 Widget->setEnabled(
false);
742 Widget->DynExpMgr->PostKeyPressEvent(Event);
770 auto ModuleParams = DynExp::dynamic_Params_cast<QModuleBase>(
GetParams());
775 ModuleParams->WindowStyleParams.ApplyTo(
IsWindowDocked() ?
static_cast<QWidget&
>(*
MdiSubWindow) :
static_cast<QWidget&
>(*DockWidget));
783 auto ModuleParams = DynExp::dynamic_Params_cast<QModuleBase>(
GetParams());
784 ModuleParams->WindowStyleParams.FromWidget(
IsWindowDocked() ?
static_cast<QWidget&
>(*
MdiSubWindow) :
static_cast<QWidget&
>(*DockWidget));
785 ModuleParams->WindowStyleParams.WindowDockingState =
IsWindowDocked() ?
795 WindowWidget->setWindowTitle(QString::fromStdString(
GetObjectName(std::chrono::seconds(1))));
799 WindowWidget->layout()->setSizeConstraint(QLayout::SetFixedSize);
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).
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.
Common base class for all managers of event listeners of type TypedEventListeners....
virtual ~InterModuleEventBase()=0
Library type that holds factory functions to all available inter-module events.
static InterModuleEventLibrary & Get()
Getter for the singleton instance of InterModuleEventLibrary.
Base class for modules. Modules implement programs on their own (e.g. measurement protocols or server...
void TerminateChild(const std::chrono::milliseconds Timeout) override final
Signals derived classes that terminating the RunnableObject instance's thread is about to be requeste...
ModuleDataTypeSyncPtrType GetModuleData(const std::chrono::milliseconds Timeout=GetModuleDataTimeoutDefault)
Locks the mutex of the module data class instance ModuleData assigned to this ModuleBase instance and...
virtual void OnErrorChild(ModuleInstance &Instance) const
This handler gets called just before the module thread terminates due to an exception....
void OnPause(ModuleInstance &Instance)
This handler gets called just after the module pauses due to e.g. an error in an instrument the modul...
void NotifyChild() override final
Notify derived classes that some state has changed (e.g. the termination of Thread is requested) and ...
void RunChild() override final
Refer to Run().
void OnDeregisterEvents(ModuleInstance *Instance) const
This event is triggered after the OnExit event. It calls EventListenersBase::Deregister() for all man...
static auto GetExceptionUnsafe(const ModuleDataTypeSyncPtrConstType &ModuleDataPtr)
Getter for ModuleDataBase::ModuleException assuming that the module data has already been locked.
virtual void OnInit(ModuleInstance *Instance) const
This event is triggered right before the module thread starts. Override it to lock instruments this m...
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
void ResetImpl(dispatch_tag< RunnableObject >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
virtual void OnResumeChild(ModuleInstance &Instance) const
This handler gets called just after the module resumed from a paused state. Override OnResumeChild() ...
void SetException(std::exception_ptr Exception) noexcept
Sets this module instance to an error state and tries to store the exception responsible for the erro...
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...
virtual void OnExit(ModuleInstance *Instance) const
This event is triggered right before the module thread terminates (not due to an exception,...
void EnqueueEvent(ModuleDataBase::EventPtrType &&Event) const
Enqueues Event at the module event queue's back. Takes ownership of the event. Notifies the module ow...
void RemoveRegisteredEvent(EventListenersBase &EventListeners)
Removes a manager of event listeners from RegisteredEvents if it was added before....
void HandleEvent(ModuleInstance &Instance)
Executes and removes the next pending event from the module's event queue.
ModuleBase(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs a ModuleBase instance.
Util::SynchronizedPointer< const ModuleDataType > ModuleDataTypeSyncPtrConstType
Alias for the return type of ModuleBase::GetModuleData() const. Data class instances wrapped into Uti...
void OnResume(ModuleInstance &Instance)
This handler gets called just after the module resumed from a paused state. Override OnResumeChild() ...
Util::SynchronizedPointer< ModuleDataType > ModuleDataTypeSyncPtrType
Alias for the return type of ModuleBase::GetModuleData(). Data class instances wrapped into Util::Syn...
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().
std::vector< EventListenersBase * > RegisteredEvents
Holds a list of pointers to managers of event listeners of the events this module has registered/subs...
void OnError(ModuleInstance &Instance)
This handler gets called just before the module thread terminates due to an exception....
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. Called indirectly by TypedEventListeners::Regi...
static constexpr auto GetModuleDataTimeoutDefault
Determines the default timeout for GetModuleData() to lock the mutex synchronizing the module's data ...
std::exception_ptr GetExceptionChild(const std::chrono::milliseconds Timeout) const override final
Returns a pointer to the exception which has caused this Object instance to fail.
bool IsReadyChild() const override final
Returns wheter this Object instance is ready (e.g. it is running or connected to a hardware device) a...
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...
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...
Util::DynExpErrorCodes::DynExpErrorCodes ExecModuleMainLoop(ModuleInstance &Instance)
Runs ModuleMainLoop().
virtual ~ModuleConfiguratorBase()=0
std::exception_ptr ModuleException
Used to transfer exceptions from the module thread to the main (user interface) thread....
Util::OneToOneNotifier NewEventNotifier
Notifies the thread of the module which owns the respective ModuleDataBase's instance when an event h...
std::queue< EventPtrType > EventQueueType
A module's event queue is a FIFO queue owning the enqueued events.
std::unique_ptr< EventBase > EventPtrType
Pointer owning an event.
void SetException(std::exception_ptr Exception) noexcept
Setter for ModuleException.
std::exception_ptr GetException() const noexcept
Getter for ModuleDataBase::ModuleException. If ModuleDataBase::ModuleException is nullptr and ModuleD...
void Reset()
Resets the ModuleDataBase's instance and calls ResetImpl(dispatch_tag<ModuleDataBase>) subsequently.
void EnqueueEvent(EventPtrType &&Event)
Enqueues Event at the module event queue's back. Takes ownership of the event. Notifies the module ow...
EventQueueType EventQueue
FIFO event queue of the module which owns the respective ModuleDataBase's instance.
std::atomic< bool > HasException
If set to true, indicates to the main (user interface) thread that an exception has happened in the m...
virtual void ResetImpl(dispatch_tag< ModuleDataBase >)
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
EventPtrType PopEvent()
Removes one event from the event queue's front and returns the event. Ownership of the event is trans...
Refer to ParamsBase::dispatch_tag.
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
ModuleInstance(ModuleBase &Owner, std::promise< void > &&ThreadExitedPromise, const ModuleBase::ModuleDataGetterType ModuleDataGetter)
Constructs a non-empty RunnableInstance instance.
virtual ~ModuleParamsBase()=0
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...
auto GetObjectName(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns the name of this Object instance.
Refer to ParamsBase::dispatch_tag.
Base class for modules with a Qt-based user interface. Derive from this class to implement modules wi...
void DockUndockWindow() noexcept
Toggles the docking state of Widget. Does nothing if any of Widget, MdiArea, MdiSubWindow,...
virtual void UpdateParamsFromWindowStatesChild() override
UpdateParamsFromWindowStates() only calls UpdateParamsFromWindowStatesChild(). Override UpdateParamsF...
QModuleWidget * Widget
User interface widget belonging to the module.
virtual void RestoreWindowStatesFromParamsChild() override
RestoreWindowStatesFromParams() only calls RestoreWindowStatesFromParamsChild(). Override RestoreWind...
bool IsActiveWindow()
Checks whether Widget is docked and active.
void FocusMainWindow() noexcept
Focuses/activates DynExp's main window calling DynExpManager::FocusMainWindow(). Does nothing if Widg...
void DisableUI()
Disables all user interface controls in Widget. Does nothing if Widget is nullptr.
bool IsWindowDocked() noexcept
Checks whether Widget is docked.
virtual void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter)
Use this function to update the module's user interface widget according to the module data obtained ...
QMdiArea * MdiArea
Pointer to DynExpManager's QMdiArea.
void UndockWindow() noexcept
Undocks Widget from MdiArea. Does nothing if any of Widget, MdiArea, MdiSubWindow,...
void SetWidgetProperties(QWidget *const WindowWidget) const
Used by InitUI() to set the widget properties (such as title, icon, size constraints) of MdiSubWindow...
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< QModuleDockWidget > DockWidget
Frame for Widget when the module window is undocked from MdiArea.
void SetFocus() noexcept
Focuses/activates Widget and moves it on top of other windows if possible. Does nothing if any of Wid...
void HideUI()
Removes MdiSubWindow, DockWidget, and ModuleWindowFocusAction setting them to nullptr.
void SendKeyPressEventToMainWindow(QKeyEvent *Event) noexcept
Sends a Qt key press event to DynExp's main window calling DynExpManager::PostKeyPressEvent()....
void UpdateUI()
Enables the user interface controls in Widget. Does nothing if Widget is nullptr. Calls UpdateUIChild...
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...
std::unique_ptr< QMdiSubWindow > MdiSubWindow
Frame for Widget when the module window is docked to MdiArea.
QModuleBase(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType &&Params)
Constructs a QModuleBase instance.
void UpdateModuleWindowFocusAction()
Updates the icon assigned to ModuleWindowFocusAction depending on whether Widget is docked to or undo...
void DockWindow() noexcept
Docks Widget to MdiArea. Does nothing if any of Widget, MdiArea, MdiSubWindow, or DockWidget are null...
std::unique_ptr< QAction > ModuleWindowFocusAction
Qt action to push module window into focus. When triggered, QModuleWidget::OnFocusWindow() in invoked...
void ResetImpl(dispatch_tag< ModuleBase >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
virtual ~QModuleConfiguratorBase()=0
void ResetImpl(dispatch_tag< ModuleDataBase >) override final
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
virtual ~QModuleParamsBase()=0
Defines data for a thread belonging to a RunnableObject instance. This data is only accessed by the R...
Defines an Object which possesses a thread it runs in. The RunnableObject can be started and stopped ...
std::promise< void > MakeThreadExitedPromise()
Helper function to be used by overridden RunChild() functions in derived classes to (re)initialize th...
void MakeThread(ThreadFuncType ThreadFunc, std::unique_ptr< RunnableInstance > &&InstancePtr)
Creates and runs the thread of the RunnableObject instance. Call this function in the derived class o...
static constexpr auto ShortTimeoutDefault
Default timeout e.g. used as a default for calls to InstrumentBase::GetInstrumentData or ModuleBase::...
bool IsExiting() const noexcept
Returns ShouldExit.
void EnsureCallFromRunnableThread() const
Asserts that the call to this function is performed from the RunnableObject instance's thread by call...
bool IsRunning() const noexcept
Returns Running.
ParamsBase::Param< unsigned int > WindowWidth
Window width.
ParamsBase::Param< int > WindowPosY
Window y coordinate.
ParamsBase::Param< int > WindowPosX
Window x coordinate.
ParamsBase::Param< WindowStateType > WindowState
Window show state.
void FromWidget(const QWidget &Widget)
Assigns styles applied to Widget to the bundled parameters.
void ApplyTo(QWidget &Widget, bool Show=true) const
Applies the bundled style parameters to Widget.
ParamsBase::Param< unsigned int > WindowHeight
Window height.
Wraps a member function of some object and stores its default arguments. Moving from CallableMemberWr...
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.
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
const int ErrorCode
DynExp error code from DynExpErrorCodes::DynExpErrorCodes
An invalid argument like a null pointer has been passed to a function.
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
Thrown when RunnableInstance cannot lock an object to be used by another object due to an invalid lin...
An operation cannot be performed currently since the related object is in an invalid state like an er...
Thrown when RunnableInstance::LockObject() has not been called on an object link parameter to establi...
void Notify()
Set notification to stop waiting (sets EventOccurred to true).
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
constexpr auto UndockedWindow
DynExp's main namespace contains the implementation of DynExp including classes to manage resources (...
int ModuleThreadMain(std::unique_ptr< RunnableInstance > &&InstancePtr, RunnableObject *BaseObject)
Modules run in their own thread. This is the module thread's main function.
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
T::ParamsType * dynamic_Params_cast(ParamsBasePtrType::element_type *Params)
Casts the parameter base class to a derived Object's parameter class.
DynExpErrorCodes
DynExp's error codes
void ForwardException(std::exception_ptr e)
Wraps the exception passed to the function in a ForwardedException and throws the ForwardedException....
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Accumulates include statements to provide a precompiled header.