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 "ui_DynExpManager.h"
12#include "DynExpAbout.h"
13#include "DynExpCore.h"
14#include "CircuitDiagram.h"
15#include "ErrorListDialog.h"
16
20class DynExpManager : public QMainWindow
21{
22 Q_OBJECT
23
24public:
44
50 DynExpManager(DynExp::DynExpCore& DynExpCore, QWidget *parent = Q_NULLPTR);
51
52 ~DynExpManager() = default;
53
54private:
61 static std::string GetObjectNameSafe(DynExp::Object* Object);
62
73 template <typename LibraryVectorT>
74 void RegisterItemsFromLibrary(const LibraryVectorT& Lib, QMenu* const MenuBase,
75 const QString IconPath, void(DynExpManager::*Slot)());
76
89 template <typename LibraryVectorT, typename ManagerT>
90 void MakeItem(QAction* SenderAction, LibraryVectorT& Lib, ManagerT& ResourceManager);
91
102 template <typename LibraryVectorT, typename ManagerT>
103 bool UpdateItemConfig(DynExp::Object* Object, LibraryVectorT& Lib, ManagerT& ResourceManager);
104
110
115 void ResetItem(DynExp::Object* Object);
116
121 void UpdateLog();
122 void ResetLogColors();
123 void UpdateModulesUI() noexcept;
124 void UpdateTitleBar();
125 void UpdateStatusBar();
127 void UpdateItemTree();
128 void UpdateItemTreeItem(const DynExp::HardwareAdapterManager::ResourceType& Resource);
129 void UpdateItemTreeItem(const DynExp::InstrumentManager::ResourceType& Resource);
130 void UpdateItemTreeItem(const DynExp::ModuleManager::ResourceType& Resource);
132
138
149 template <typename ManagerT>
150 QTreeWidgetItem* UpdateItemTreeSection(QTreeWidgetItem* Section, ManagerT& ResourceManager);
151
158 void UpdateItemTreeItemObjectName(QTreeWidgetItem* Item, const DynExp::Object* Object);
159
165 void SelectItemTreeItem(QTreeWidgetItem* SelectedEntry);
166
167 void ChangeItemTreeItemToNormalState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
168 const QString& Description, const QString& StateTitle, const char* IconPath = DynExpUI::Icons::Stopped);
169 void ChangeItemTreeItemToRunningState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
170 const QString& Description);
171 void ChangeItemTreeItemToPausedState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
172 const QString& Description);
173 void ChangeItemTreeItemToWarningState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
174 const QString& Description);
175 void ChangeItemTreeItemToErrorState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
176 const std::exception_ptr& ExceptionPtr);
177 void ChangeItemTreeItemToNotConnectedState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
178 const QString& Description);
179 void ChangeItemTreeItemToNotRespondingState(QTreeWidgetItem& ItemTreeItem, const ItemTreeItemDataType& ItemTreeItemData,
180 const QString& Description);
182
189 QColor HTMLColorStringToThemeColor(const std::string& HTMLColor) const;
190
196 QColor AdjustColorToThemeColor(const QColor& Color) const;
197
201 void Reset(bool Force = false);
202
209 bool CloseProject() noexcept;
210
216 bool Shutdown() noexcept;
217
222 void SaveProject(std::string_view Filename) noexcept;
223
228 void DisableAllActions() noexcept;
229
235
239 void UpdateModuleWindowsActionIcons() noexcept;
240
246 DynExp::QModuleBase* GetModuleByActiveUIWindow() noexcept;
247
252 virtual void closeEvent(QCloseEvent* event) override;
254
256
257 Ui::DynExpManagerClass ui;
258
261
267
270 QActionGroup* UIThemeActionGroup;
276 QTreeWidgetItem* ItemTreeHardwareAdapters;
277 QTreeWidgetItem* ItemTreeInstruments;
278 QTreeWidgetItem* ItemTreeModules;
279
304
309
314
320
328
329public:
337 void RegisterModuleUI(DynExp::Object* const Object);
338
345 bool StopItem(DynExp::RunnableObject* Object, bool Force = false) noexcept;
346
350 void FocusMainWindow() noexcept;
351
357 void PostKeyPressEvent(QKeyEvent* Event) noexcept;
358
362 std::string GetDataSaveDirectory() const { return DynExpCore.GetDataSaveDirectory(); }
363
367 void SetDataSaveDirectory(std::string_view Directory) const { return DynExpCore.SetDataSaveDirectory(Directory); }
368
369private slots:
374 void OnUpdateUI();
375 void OnUIThemeChanged(QAction* ThemeAction);
376 void OnNewProject();
377 void OnOpenProject();
378 void OnSaveProject();
379 void OnSaveProjectAs();
380 void OnRunProject();
381 void OnStopProject();
382 void OnResetFailedItems();
385 void OnRunItem();
386 void OnStopItem(bool Force = false);
387 void OnForceStopItem();
388 void OnResetItem();
389 void OnConfigureItem();
390 void OnDeleteItem();
391 void OnWindowMenuOpened();
392 void OnWindowMenuClosed();
393 void OnDockUndockWindow();
395 void OnAboutClicked();
397 void OnLogContextMenuRequested(const QPoint& Position);
398 void OnItemTreeContextMenuRequested(const QPoint& Position);
399 void OnClearLog();
400 void OnClearWarning();
402 void OnAddInstrument();
403 void OnAddModule();
405 void OnItemDoubleClicked(QTreeWidgetItem* Item, int Column);
406 void OnModuleWindowActivated(QMdiSubWindow* Window);
408};
409
411
412template <typename LibraryVectorT>
413void DynExpManager::RegisterItemsFromLibrary(const LibraryVectorT& Lib, QMenu* const MenuBase,
414 const QString IconPath, void(DynExpManager::*Slot)())
415{
416 std::string LastCategoryString("");
417 QMenu* CurrentCategoryMenu = nullptr;
418
419 for (size_t i = 0; i < Lib.size(); ++i)
420 {
421 const auto& LibEntry = Lib[i];
422
423 std::string CategoryString(LibEntry.Category);
424 QMenu* MenuToAdd = CategoryString.empty() ? MenuBase : CurrentCategoryMenu;
425
426 if (!CategoryString.empty() && CategoryString != LastCategoryString)
427 {
428 // ...because one & only makes the next letter a shortcut (see QAction and QMenu)
429 CurrentCategoryMenu = MenuBase->addMenu(QString::fromStdString(CategoryString).replace("&", "&&"));
430 LastCategoryString = CategoryString;
431 MenuToAdd = CurrentCategoryMenu;
432 }
433
434 auto AddedAction = MenuToAdd->addAction(QIcon(IconPath),
435 QString::fromStdString(LibEntry.Name).replace("&", "&&"), this, Slot);
436 AddedAction->setData(QVariant::fromValue(i));
437 }
438}
439
440template <typename LibraryVectorT, typename ManagerT>
441void DynExpManager::MakeItem(QAction* SenderAction, LibraryVectorT& Lib, ManagerT& ResourceManager)
442{
443 if (!SenderAction)
444 {
445 Util::EventLog().Log("SenderAction cannot be nullptr.",
447 return;
448 }
449
450 auto Variant = SenderAction->data();
451 if (!Variant.canConvert<size_t>())
452 {
453 Util::EventLog().Log("No library entry has been assigned to this item.",
455 return;
456 }
457
458 const auto& LibEntry = Lib[Variant.value<size_t>()];
459
460 const std::string ObjectType = DynExp::Object::CategoryAndNameToStr(LibEntry.Category, LibEntry.Name);
461 std::string ObjectName = "";
462 std::string ErrorMessage = "";
463
465 try
466 {
467 auto Params = LibEntry.ConfigFactoryPtr()->MakeConfigFromDialog(ResourceManager.GetNextID(), DynExpCore, this);
468 if (!Params) // e.g. cancelled by user
469 return;
470
471 ObjectName = Params->ObjectName;
472
473 NewItemID = DynExpCore.MakeItem(LibEntry, std::move(Params));
474 }
475 catch (const Util::EmptyException& e)
476 {
477 ErrorMessage = e.what();
478 }
479 catch (const Util::Exception& e)
480 {
481 Util::EventLog().Log(e);
482 ErrorMessage = e.what();
483 }
484 catch (const std::exception& e)
485 {
486 ErrorMessage = e.what();
487 }
488 catch (...)
489 {
490 ErrorMessage = "Unknown Error";
491 }
492
493 if (!ErrorMessage.empty())
494 {
495 QMessageBox::warning(this, "DynExp - Error",
496 QString::fromStdString(
497 "Creating item " + (ObjectName.empty() ? "< Unnamed >" : ObjectName) +
498 + " (" + ObjectType + "), the following error occurred:\n\n"
499 + ErrorMessage
500 ));
501 }
502
503 if (NewItemID != DynExp::ItemIDNotSet)
504 {
505 const auto Object = ResourceManager.GetResource(NewItemID);
506
507 EnsureItemReadyState(Object);
508 RegisterModuleUI(Object);
509 }
510}
511
512template <typename LibraryVectorT, typename ManagerT>
513bool DynExpManager::UpdateItemConfig(DynExp::Object* Object, LibraryVectorT& Lib, ManagerT& ResourceManager)
514{
515 if (!Object)
516 throw Util::InvalidArgException("Object cannot be nullptr.");
517
518 auto LibEntry = DynExp::FindInLibraryVector(Lib, Object->GetCategory(), Object->GetName());
519 auto ResultState = LibEntry.ConfigFactoryPtr()->UpdateConfigFromDialog(Object, DynExpCore, this);
520
521 if (ResultState.IsAccepted())
522 ResourceManager.DeleteTreeWidgetItem(Object->GetID());
523
524 return ResultState.IsResetRequired();
525}
526
527template <typename ManagerT>
528QTreeWidgetItem* DynExpManager::UpdateItemTreeSection(QTreeWidgetItem* Section, ManagerT& ResourceManager)
529{
530 QTreeWidgetItem* LastAdded = nullptr;
531
532 for (auto Resource = ResourceManager.cbegin(); Resource != ResourceManager.cend(); ++Resource)
533 {
534 if (!Resource->second.TreeWidgetItem)
535 {
536 auto CategoryAndName = QString::fromStdString(Resource->second.ResourcePointer->GetCategoryAndName());
537 auto ID = Resource->second.ResourcePointer->GetID();
538
539 Resource->second.TreeWidgetItem = std::make_unique<QTreeWidgetItem>(Section,
540 QStringList{ "", CategoryAndName, "" });
541 UpdateItemTreeItemObjectName(Resource->second.TreeWidgetItem.get(), Resource->second.ResourcePointer.get());
542 Resource->second.TreeWidgetItem->setToolTip(1, CategoryAndName);
543 Resource->second.TreeWidgetItem->setData(1, Qt::ItemDataRole::UserRole, QVariant::fromValue(Resource->second.TreeWidgetItem.get()));
544 Resource->second.TreeWidgetItem->setData(2, Qt::ItemDataRole::UserRole, QVariant::fromValue(ItemTreeItemDataType(ID)));
545
546 // Show and sort by item name.
547 Section->setExpanded(true);
548 Section->sortChildren(0, Qt::SortOrder::AscendingOrder);
549
550 LastAdded = Resource->second.TreeWidgetItem.get();
551
553 }
554 else if (Resource->second.TreeWidgetItem->data(0, Qt::ItemDataRole::UserRole).template value<bool>())
555 {
556 UpdateItemTreeItemObjectName(Resource->second.TreeWidgetItem.get(), Resource->second.ResourcePointer.get());
557
559 }
560
561 UpdateItemTreeItem(Resource->second);
562 }
563
564 return LastAdded;
565}
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...
~DynExpManager()=default
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.
Ui::DynExpManagerClass ui
Qt widgets belonging to the main window's user interface.
QMenu * LogContextMenu
Context menu appearing when right-clicking on the message log widget.
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:224
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
An invalid argument like a null pointer has been passed to a function.
Definition Exception.h:137
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:509
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.