DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
DynExpManager.h
Go to the documentation of this file.
1// This file is part of DynExp.
2
8#pragma once
9
10#include <QtWidgets/QMainWindow>
11#include "DynExpAbout.h"
12#include "DynExpCore.h"
13#include "CircuitDiagram.h"
14#include "ErrorListDialog.h"
15
16namespace Ui
17{
18 class DynExpManagerClass;
19}
20
24class DynExpManager : public QMainWindow
25{
26 Q_OBJECT
27
28public:
48
54 DynExpManager(DynExp::DynExpCore& DynExpCore, QWidget *parent = Q_NULLPTR);
55
57
58private:
65 static std::string GetObjectNameSafe(DynExp::Object* Object);
66
77 template <typename LibraryVectorT>
78 void RegisterItemsFromLibrary(const LibraryVectorT& Lib, QMenu* const MenuBase,
79 const QString IconPath, void(DynExpManager::*Slot)());
80
93 template <typename LibraryVectorT, typename ManagerT>
94 void MakeItem(QAction* SenderAction, LibraryVectorT& Lib, ManagerT& ResourceManager);
95
106 template <typename LibraryVectorT, typename ManagerT>
107 bool UpdateItemConfig(DynExp::Object* Object, LibraryVectorT& Lib, ManagerT& ResourceManager);
108
114
119 void ResetItem(DynExp::Object* Object);
120
125 void UpdateLog();
126 void ResetLogColors();
127 void UpdateModulesUI() noexcept;
128 void UpdateTitleBar();
129 void UpdateStatusBar();
131 void UpdateItemTree();
132 void UpdateItemTreeItem(const DynExp::HardwareAdapterManager::ResourceType& Resource);
133 void UpdateItemTreeItem(const DynExp::InstrumentManager::ResourceType& Resource);
134 void UpdateItemTreeItem(const DynExp::ModuleManager::ResourceType& Resource);
136
142
153 template <typename ManagerT>
154 QTreeWidgetItem* UpdateItemTreeSection(QTreeWidgetItem* Section, ManagerT& ResourceManager);
155
162 void UpdateItemTreeItemObjectName(QTreeWidgetItem* Item, const DynExp::Object* Object);
163
169 void SelectItemTreeItem(QTreeWidgetItem* SelectedEntry);
170
171 void ChangeItemTreeItemToNormalState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
172 const QString& Description, const QString& StateTitle, const char* IconPath = DynExpUI::Icons::Stopped);
173 void ChangeItemTreeItemToRunningState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
174 const QString& Description);
175 void ChangeItemTreeItemToPausedState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
176 const QString& Description);
177 void ChangeItemTreeItemToWarningState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
178 const QString& Description);
179 void ChangeItemTreeItemToErrorState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
180 const std::exception_ptr& ExceptionPtr);
181 void ChangeItemTreeItemToNotConnectedState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
182 const QString& Description);
183 void ChangeItemTreeItemToNotRespondingState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
184 const QString& Description);
186
193 QColor HTMLColorStringToThemeColor(const std::string& HTMLColor) const;
194
200 QColor AdjustColorToThemeColor(const QColor& Color) const;
201
205 void Reset(bool Force = false);
206
213 bool CloseProject() noexcept;
214
220 bool Shutdown() noexcept;
221
226 void SaveProject(std::string_view Filename) noexcept;
227
232 void DisableAllActions() noexcept;
233
239
243 void UpdateModuleWindowsActionIcons() noexcept;
244
250 DynExp::QModuleBase* GetModuleByActiveUIWindow() noexcept;
251
256 virtual void closeEvent(QCloseEvent* event) override;
258
260
261 std::unique_ptr<Ui::DynExpManagerClass> ui;
262
265
271
274 QActionGroup* UIThemeActionGroup;
280 QTreeWidgetItem* ItemTreeHardwareAdapters;
281 QTreeWidgetItem* ItemTreeInstruments;
282 QTreeWidgetItem* ItemTreeModules;
283
308
313
318
324
332
333public:
341 void RegisterModuleUI(DynExp::Object* const Object);
342
349 bool StopItem(DynExp::RunnableObject* Object, bool Force = false) noexcept;
350
354 void FocusMainWindow() noexcept;
355
361 void PostKeyPressEvent(QKeyEvent* Event) noexcept;
362
366 std::string GetDataSaveDirectory() const { return DynExpCore.GetDataSaveDirectory(); }
367
371 void SetDataSaveDirectory(std::string_view Directory) const { return DynExpCore.SetDataSaveDirectory(Directory); }
372
373private slots:
378 void OnUpdateUI();
379 void OnUIThemeChanged(QAction* ThemeAction);
380 void OnNewProject();
381 void OnOpenProject();
382 void OnSaveProject();
383 void OnSaveProjectAs();
384 void OnRunProject();
385 void OnStopProject();
386 void OnResetFailedItems();
389 void OnRunItem();
390 void OnStopItem(bool Force = false);
391 void OnForceStopItem();
392 void OnResetItem();
393 void OnConfigureItem();
394 void OnDeleteItem();
395 void OnWindowMenuOpened();
396 void OnWindowMenuClosed();
397 void OnDockUndockWindow();
399 void OnAboutClicked();
401 void OnLogContextMenuRequested(const QPoint& Position);
402 void OnItemTreeContextMenuRequested(const QPoint& Position);
403 void OnClearLog();
404 void OnClearWarning();
406 void OnAddInstrument();
407 void OnAddModule();
409 void OnItemDoubleClicked(QTreeWidgetItem* Item, int Column);
410 void OnModuleWindowActivated(QMdiSubWindow* Window);
412};
413
415
416template <typename LibraryVectorT>
417void DynExpManager::RegisterItemsFromLibrary(const LibraryVectorT& Lib, QMenu* const MenuBase,
418 const QString IconPath, void(DynExpManager::*Slot)())
419{
420 std::string LastCategoryString("");
421 QMenu* CurrentCategoryMenu = nullptr;
422
423 for (size_t i = 0; i < Lib.size(); ++i)
424 {
425 const auto& LibEntry = Lib[i];
426
427 std::string CategoryString(LibEntry.Category);
428 QMenu* MenuToAdd = CategoryString.empty() ? MenuBase : CurrentCategoryMenu;
429
430 if (!CategoryString.empty() && CategoryString != LastCategoryString)
431 {
432 // ...because one & only makes the next letter a shortcut (see QAction and QMenu)
433 CurrentCategoryMenu = MenuBase->addMenu(QString::fromStdString(CategoryString).replace("&", "&&"));
434 LastCategoryString = CategoryString;
435 MenuToAdd = CurrentCategoryMenu;
436 }
437
438 auto AddedAction = MenuToAdd->addAction(QIcon(IconPath),
439 QString::fromStdString(LibEntry.Name).replace("&", "&&"), this, Slot);
440 AddedAction->setData(QVariant::fromValue(i));
441 }
442}
443
444template <typename LibraryVectorT, typename ManagerT>
445void DynExpManager::MakeItem(QAction* SenderAction, LibraryVectorT& Lib, ManagerT& ResourceManager)
446{
447 if (!SenderAction)
448 {
449 Util::EventLog().Log("SenderAction cannot be nullptr.",
451 return;
452 }
453
454 auto Variant = SenderAction->data();
455 if (!Variant.canConvert<size_t>())
456 {
457 Util::EventLog().Log("No library entry has been assigned to this item.",
459 return;
460 }
461
462 const auto& LibEntry = Lib[Variant.value<size_t>()];
463
464 const std::string ObjectType = DynExp::Object::CategoryAndNameToStr(LibEntry.Category, LibEntry.Name);
465 std::string ObjectName = "";
466 std::string ErrorMessage = "";
467
469 try
470 {
471 auto Params = LibEntry.ConfigFactoryPtr()->MakeConfigFromDialog(ResourceManager.GetNextID(), DynExpCore, this);
472 if (!Params) // e.g. cancelled by user
473 return;
474
475 ObjectName = Params->ObjectName;
476
477 NewItemID = DynExpCore.MakeItem(LibEntry, std::move(Params));
478 }
479 catch (const Util::EmptyException& e)
480 {
481 ErrorMessage = e.what();
482 }
483 catch (const Util::Exception& e)
484 {
485 Util::EventLog().Log(e);
486 ErrorMessage = e.what();
487 }
488 catch (const std::exception& e)
489 {
490 ErrorMessage = e.what();
491 }
492 catch (...)
493 {
494 ErrorMessage = "Unknown Error";
495 }
496
497 if (!ErrorMessage.empty())
498 {
499 QMessageBox::warning(this, "DynExp - Error",
500 QString::fromStdString(
501 "Creating item " + (ObjectName.empty() ? "< Unnamed >" : ObjectName) +
502 + " (" + ObjectType + "), the following error occurred:\n\n"
503 + ErrorMessage
504 ));
505 }
506
507 if (NewItemID != DynExp::ItemIDNotSet)
508 {
509 const auto Object = ResourceManager.GetResource(NewItemID);
510
511 EnsureItemReadyState(Object);
512 RegisterModuleUI(Object);
513 }
514}
515
516template <typename LibraryVectorT, typename ManagerT>
517bool DynExpManager::UpdateItemConfig(DynExp::Object* Object, LibraryVectorT& Lib, ManagerT& ResourceManager)
518{
519 if (!Object)
520 throw Util::InvalidArgException("Object cannot be nullptr.");
521
522 auto LibEntry = DynExp::FindInLibraryVector(Lib, Object->GetCategory(), Object->GetName());
523 auto ResultState = LibEntry.ConfigFactoryPtr()->UpdateConfigFromDialog(Object, DynExpCore, this);
524
525 if (ResultState.IsAccepted())
526 ResourceManager.DeleteTreeWidgetItem(Object->GetID());
527
528 return ResultState.IsResetRequired();
529}
530
531template <typename ManagerT>
532QTreeWidgetItem* DynExpManager::UpdateItemTreeSection(QTreeWidgetItem* Section, ManagerT& ResourceManager)
533{
534 QTreeWidgetItem* LastAdded = nullptr;
535
536 for (auto Resource = ResourceManager.cbegin(); Resource != ResourceManager.cend(); ++Resource)
537 {
538 if (!Resource->second.TreeWidgetItem)
539 {
540 auto CategoryAndName = QString::fromStdString(Resource->second.ResourcePointer->GetCategoryAndName());
541 auto ID = Resource->second.ResourcePointer->GetID();
542
543 Resource->second.TreeWidgetItem = std::make_unique<QTreeWidgetItem>(Section,
544 QStringList{ "", CategoryAndName, "" });
545 UpdateItemTreeItemObjectName(Resource->second.TreeWidgetItem.get(), Resource->second.ResourcePointer.get());
546 Resource->second.TreeWidgetItem->setToolTip(1, CategoryAndName);
547 Resource->second.TreeWidgetItem->setData(1, Qt::ItemDataRole::UserRole, QVariant::fromValue(Resource->second.TreeWidgetItem.get()));
548 Resource->second.TreeWidgetItem->setData(2, Qt::ItemDataRole::UserRole, QVariant::fromValue(ItemTreeItemDataType(ID)));
549
550 // Show and sort by item name.
551 Section->setExpanded(true);
552 Section->sortChildren(0, Qt::SortOrder::AscendingOrder);
553
554 LastAdded = Resource->second.TreeWidgetItem.get();
555
557 }
558 else if (Resource->second.TreeWidgetItem->data(0, Qt::ItemDataRole::UserRole).template value<bool>())
559 {
560 UpdateItemTreeItemObjectName(Resource->second.TreeWidgetItem.get(), Resource->second.ResourcePointer.get());
561
563 }
564
565 UpdateItemTreeItem(Resource->second);
566 }
567
568 return LastAdded;
569}
Implements a window drawing the relations between all DynExp::Object instances as a graph....
Implements a dialog to show license information about DynExp.
Defines DynExp's core module as an interface between the UI and DynExp objects.
Q_DECLARE_METATYPE(DynExpManager::ItemTreeItemDataType)
Implements a frame-less pop-up dialog to show errors and warning of DynExp::Object instances.
Implements DynExp's main window as a Qt-based user interface (UI).
void SelectItemTreeItem(QTreeWidgetItem *SelectedEntry)
Selects the given QTreeWidgetItem instance and brings this DynExpManager window to the front.
DynExpAbout * AboutDialog
Dialog showing license and copyright information.
void ChangeItemTreeItemToRunningState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description)
void OnProjectSettingsClicked()
QColor HTMLColorStringToThemeColor(const std::string &HTMLColor) const
Constructs a QColor instance from an HTML color string depending on the currently active UI theme.
void Reset(bool Force=false)
Resets the currently loaded project removing all resources from the resource managers....
void UpdateCircuitDiagram()
void OnAddHardwareAdapter()
void OnStatusBarStateClicked()
void OnItemDoubleClicked(QTreeWidgetItem *Item, int Column)
QMenu * ItemTreeContextMenu
Context menu appearing when right-clicking on the main tree widget showing DynExp::Object instances.
ErrorListDialog * ErrorListDlg
Dialog showing the list of currently active warnings and errors (ErrorEntries)
void MakeItem(QAction *SenderAction, LibraryVectorT &Lib, ManagerT &ResourceManager)
Creates a DynExp::Object instance according to a QAction instance SenderAction, which contains the in...
DynExp::DynExpCore & DynExpCore
Handle to DynExp's internal data.
void SetDataSaveDirectory(std::string_view Directory) const
Sets a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to st...
QTreeWidgetItem * ItemTreeHardwareAdapters
Item for the hardware adapters section within the main tree widget showing DynExp::Object instances.
QColor AdjustColorToThemeColor(const QColor &Color) const
Transforms a QColor instance depending on the currently active UI theme.
void OnItemSelectionChanged()
bool Shutdown() noexcept
Terminates DynExpCore::WorkerThread and waits until the thread has ended.
static std::string GetObjectNameSafe(DynExp::Object *Object)
Retrieves the name of a DynExp::Object instance from its parameter class instance.
void OnStopItem(bool Force=false)
void ChangeItemTreeItemToNotRespondingState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description)
void ResetItem(DynExp::Object *Object)
Calls DynExp::Object::Reset() on a DynExp::Object instance.
void OnRestoreWindowStatesFromParams()
void RegisterItemsFromLibrary(const LibraryVectorT &Lib, QMenu *const MenuBase, const QString IconPath, void(DynExpManager::*Slot)())
Adds the library entries from Lib to submenus below MenuBase and assigns actions to them invoking Slo...
void UpdateModuleWindowsActionShortcuts() noexcept
Establishes shortcuts to switch between module windows. Refer to ModuleWindowsActionGroup.
QTreeWidgetItem * ItemTreeModules
Item for the modules section within the main tree widget showing DynExp::Object instances.
virtual void closeEvent(QCloseEvent *event) override
bool UpdateItemConfig(DynExp::Object *Object, LibraryVectorT &Lib, ManagerT &ResourceManager)
Invokes a configuration dialog to let the user adjust the parameters of a DynExp::Object instance.
void OnLogContextMenuRequested(const QPoint &Position)
void ChangeItemTreeItemToNotConnectedState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description)
void OnModuleWindowActivated(QMdiSubWindow *Window)
void PostKeyPressEvent(QKeyEvent *Event) noexcept
Delegates a Qt key press event (e.g. the key sequences Ctrl+1 - Ctrl+9) from module widgets to the ma...
void FocusMainWindow() noexcept
Focuses/activates DynExp's main window and moves it on top of other windows if possible.
void DisableAllActions() noexcept
Disables all user interface actions such that item-specific ones can be reenabled upon a selection ch...
void OnShowCircuitDiagram()
struct DynExpManager::StatusBarType StatusBar
DynExp::QModuleBase * GetModuleByActiveUIWindow() noexcept
Determines the DynExp::QModuleBase instance of the current project whose UI window is active (has the...
std::string GetDataSaveDirectory() const
Recalls a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to...
void UpdateItemTreeItemObjectName(QTreeWidgetItem *Item, const DynExp::Object *Object)
Updates the text of a QTreeWidgetItem instance to match it to the related DynExp::Object instance.
QMenu * LogContextMenu
Context menu appearing when right-clicking on the message log widget.
std::unique_ptr< Ui::DynExpManagerClass > ui
Qt widgets belonging to the main window's user interface.
void UpdateModuleWindowsActionIcons() noexcept
Invokes DynExp::QModuleBase::UpdateModuleWindowFocusAction() on each module.
QActionGroup * UIThemeActionGroup
Actions to switch in between different UI themes.
std::unique_ptr< CircuitDiagram > CircuitDiagramDlg
Dialog showing the circuit diagram of the current project. It has no parent to not stay on top of the...
bool IsResetting
Indicates whether DynExpManager is currently deleting all resources to empty the project.
QActionGroup * ModuleWindowsActionGroup
Actions to switch between module windows with CTRL + < number key > shortcuts.
QAction * UIBrightThemeAction
Action for a bright UI theme.
void ChangeItemTreeItemToPausedState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description)
QTreeWidgetItem * ItemTreeInstruments
Item for the instruments section within the main tree widget showing DynExp::Object instances.
void UpdateModulesUI() noexcept
void OnUIThemeChanged(QAction *ThemeAction)
void UpdateItemTreeItem(const DynExp::HardwareAdapterManager::ResourceType &Resource)
void RegisterModuleUI(DynExp::Object *const Object)
Initializes the UI of the module Object (expecting that Object is a DynExp::QModuleBase instance....
void SaveProject(std::string_view Filename) noexcept
Saves the current DynExp project to an XML project file.
QAction * ClearWarningAction
Action to clear the warning of an item within the main tree widget showing DynExp::Object instances.
QTreeWidgetItem * UpdateItemTreeSection(QTreeWidgetItem *Section, ManagerT &ResourceManager)
Loops through resources managed by ResourceManager and adds respective QTreeWidgetItem instances as c...
void ChangeItemTreeItemToErrorState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const std::exception_ptr &ExceptionPtr)
bool StopItem(DynExp::RunnableObject *Object, bool Force=false) noexcept
Calls DynExp::RunnableObject::Terminate() on a DynExp::RunnableObject instance.
void ChangeItemTreeItemToNormalState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description, const QString &StateTitle, const char *IconPath=DynExpUI::Icons::Stopped)
bool ShouldRedrawCircuitDiagram
Indicates whether the circuit diagram has to be rebuilt. Particularly, this must be set to true direc...
void EnsureItemReadyState(DynExp::Object *Object)
Calls DynExp::Object::EnsureReadyState() on a DynExp::Object instance.
void OnItemTreeContextMenuRequested(const QPoint &Position)
void ChangeItemTreeItemToWarningState(QTreeWidgetItem &ItemTreeItem, const ItemTreeItemDataType &ItemTreeItemData, const QString &Description)
ErrorListDialog::ErrorEntriesType ErrorEntries
List of all currently active warnings and errors.
bool CloseProject() noexcept
Closes the current project and opens a new, empty one.
bool ShouldUpdateCircuitDiagram
Indicates whether any item state has changed. Set to true to update the circuit diagram....
QAction * UIDarkThemeAction
Action for a dark UI theme.
QTimer * UpdateUITimer
Timer for periodically updating the user interface.
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition DynExpCore.h:127
void SetDataSaveDirectory(const std::filesystem::path &Directory, const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault)
Sets a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to st...
ItemIDType MakeItem(const LibraryEntry< HardwareAdapterPtrType > &LibEntry, ParamsBasePtrType &&Params)
Creates a DynExp::HardwareAdapterBase instance from a LibraryEntry.
std::string GetDataSaveDirectory(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Recalls a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to...
Base class for all DynExp Objects like hardware adapters (DynExp::HardwareAdapterBase),...
Definition Object.h:1971
virtual std::string GetName() const =0
Returns the name of this Object type.
virtual std::string GetCategory() const =0
Returns the category of this Object type.
ItemIDType GetID() const noexcept
Returns the ID of this Object instance. Thread-safe since ID is const.
Definition Object.h:2143
static std::string CategoryAndNameToStr(const std::string &Category, const std::string &Name)
Builds a string from an Object's category and name to allow the user to identify an Object's type.
Definition Object.cpp:350
Defines an Object which possesses a thread it runs in. The RunnableObject can be started and stopped ...
Definition Object.h:2426
std::vector< ErrorEntryType > ErrorEntriesType
Thrown when a list is expected to contain entries and when a query results in an empty answer or an e...
Definition Exception.h:225
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:317
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
Definition Exception.h:51
An invalid argument like a null pointer has been passed to a function.
Definition Exception.h:138
DynExp's user interface namespace contains user interface style definitions.
DynExp's main namespace contains the implementation of DynExp including classes to manage resources (...
const LibraryVectorT::value_type & FindInLibraryVector(const LibraryVectorT &LibraryVector, const std::string &Category, const std::string &Name)
Finds an entry in a library vector by category and name.
Definition Libraries.h:258
size_t ItemIDType
ID type of objects/items managed by DynExp.
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Definition Util.cpp:517
Bundles data which is assigned to items of the main QTreeWidget. Each item refers to a DynExp::Object...
constexpr ItemTreeItemDataType() noexcept
const DynExp::ItemIDType ID
ID of the DynExp::Object instance assigned to this item.
ItemTreeItemStateType
States the QTreeWidgetItem instances can have.
ItemTreeItemStateType ItemTreeItemState
Current state derived from the related DynExp::Object instance.
constexpr ItemTreeItemDataType(const DynExp::ItemIDType ID, const ItemTreeItemStateType ItemTreeItemState=ItemTreeItemStateType::New) noexcept
Type bundling widgets to be displayed in the main window's status bar.