#pragma once #include "lts_base.h" #include "lts_dialog_button_box.h" #include "lts_widgets_export.h" #include "requirement_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace LtsWidgets { class TopicInfo { public: int entityId() const { return m_entityId; } const QString& topicName() const { return m_topicName; } bool isLocked() const { return m_locked; } bool isValid() const { return m_valid; } void setEntity(int entityId) { m_entityId = entityId; } void setTopicName(const QString& topicName) { m_topicName = topicName; } void setLocked(bool locked = true) { m_locked = locked; } void setValid() { m_valid = true; } private: QString m_topicName; int m_entityId{0}; bool m_locked{false}; bool m_valid{false}; }; class LtsBaseLayoutWidget; class LtsDialogHelper; class LtsProgressDialogHelper; class LtsDialogButtonBox; class LtsToolBarArea; class OverlayContainer; enum class ButtonCombination { OkApplyCancel, OkCancel, CloseOnly, SeamlessDialog, }; class LTSWIDGETS_EXPORT LtsDialog : public QWidget { Q_OBJECT Q_PROPERTY(bool unchangeable READ unchangeable WRITE setUnchangeable) public: static int s_object_count; explicit LtsDialog(QWidget* parent = nullptr, ButtonCombination buttonCombination = ButtonCombination::CloseOnly, bool closeable = true); ~LtsDialog(); LtsDialogHelper* getHelper(); bool hasUnsavedChanges() const { return m_changesMade || m_currentlyBlocking; } virtual void retranslate() = 0; void closeRequest(); void setUnchangeable(bool unchangeable = true); bool unchangeable() const { return m_unchangeableDialog; } bool addDialog(LtsDialog* dialog, const QString& menuGroup, const QString& identifier, const LayoutArea& layoutArea = LayoutArea::eDialogTab, bool setClosable = true, bool focusNewTab = true); Q_DECL_DEPRECATED bool addDialogFixed(LtsDialog* dialog, const char* menuGroupUntranslated, const QString& identifier, const LayoutArea& layoutArea = LayoutArea::eDialogTab, bool setClosable = true, bool focusNewTab = true); bool focusDialog(const QString& menuGroup, const QString& identifier, const LayoutArea& layoutArea); bool amIFocused() const; void setBaseLayoutWidget(LtsBaseLayoutWidget* baseLayoutWidget); void __unchange__() { resetChanges(); } void setClosable(bool closable) { m_isClosable = closable; } bool isClosable() const { return m_isClosable; } virtual void aboutToClose() {} void setMenuGroup(const QString& menuGroup) { m_menuGroup = menuGroup; } const QString& menuGroup() const { return m_menuGroup; } void setIdentifier(const QString& identifier); virtual void tableColumnOrganiserSetting(){}; const QString& identifier() const { return m_identifier; } void setOverlay(QWidget* widget); void unsetOverlay(); static inline void setMinWidthForWidgetHelper(QWidget* w) { int width = w->sizeHint().width(); w->setMinimumWidth(width); } QString windowTitle() const { return m_title; } void tryLockTopicNew(); virtual void tryLockTopicNew(const QString& topicName, int entityId = -1); void triggerTopicLock(); void setOnlineHelpFilename(const QString& fileName); void setCurrentlyBlocking(bool currentlyBlocking = true) { m_currentlyBlocking = currentlyBlocking; } signals: void startMainSelect(LtsWidgets::LayoutArea); void endMainSelect(LtsWidgets::LayoutArea); void signalChangesMade(); void signalHide(QObject* object); void signalChangesReset(); void signalFocused(); void visibilityChanged(bool visible); void signalLockTopic(const LtsWidgets::TopicInfo& topicInfo); void signalShowOnlineHelp(const QString& fileName); protected: void translate(const QString& title); template void translate(T* ui, const QString& title) { translate(title); if (ui) ui->retranslateUi(this); m_uiRequirements->retranslate(); } void hideEvent(QHideEvent* event) override { QWidget::hideEvent(event); emit visibilityChanged(false); } template void translate(T* ui, const QString& custom, bool isNew, const QString& title) { QString newTitle; if (!isNew) { if (unchangeable()) { if (custom.isEmpty()) newTitle = (tr("Show %1").arg(title)); else newTitle = (tr("Show %1: %2").arg(title, custom)); } else { if (custom.isEmpty()) newTitle = (tr("Edit %1").arg(title)); else newTitle = (tr("Edit %1: %2").arg(title, custom)); tryLockTopicNew(); } } else { newTitle = (tr("New %1").arg(title)); m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->hide(); m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setText(tr("Create")); } translate(ui, newTitle); } template void translate(T* ui, const QString& customUniqueTopicName, int topicId, const QString& custom, const QString& title) { Q_UNUSED(customUniqueTopicName); initTopicLockHandler(customUniqueTopicName, topicId); translate(ui, custom, (topicId < 1), title); } template void translate(T* ui, const S& data, const QString& custom, const QString& title) { translate(ui, QString::fromUtf8(typeid(data).name()), data.id(), custom, title); } template void translate(T* ui, const S& data, const QString& title) { translate(ui, data, QString::fromStdString(data.name()), title); } virtual void dialogCanceled() {} LtsBaseLayoutWidget* baseLayoutWidget(); void setNoTopicLock() { m_noLockTopic = true; } private: friend class LtsDialogHelper; bool m_changesMade; bool m_currentlyBlocking{false}; bool m_firstShow; QPointer m_baseLayoutWidget; bool m_isClosable; TopicInfo m_topicInfo; public: QString m_topicLockedBy; private: bool m_noLockTopic; bool m_unchangeableDialog; QPointer m_dialogHelper; NGL::INGLLogger& m_logger; QString m_title; QString m_onlineHelpFileName; QString m_menuGroup; QString m_identifier; QPointer m_overlayContainer; QPointer m_overlayWidget; bool _apply(); void _close(); void _discard(); void _hide(); void resetChanges(); void addDebugMenuButton(); void tryLockTopic(); void initTopicLockHandler(const QString& topicName, int entityId); void setWindowTitle(const QString& title); void updateWindowTitle(); void addConnections(QWidget* widget); template bool addChangesMadeSignal(QWidget* widget, SignalFunc signal) { WidgetType* concreteWidget = qobject_cast(widget); if (!concreteWidget) return false; connect(concreteWidget, signal, this, &LtsDialog::slotChangesMade); return true; } template void setWidgetsReadonly(bool readonly) { const auto children = findChildren(); for (WidgetType* widget : children) { widget->setProperty("lastReadOnlyState", widget->isReadOnly()); widget->setReadOnly(readonly); } } template void setWidgetsDisabled(bool disabled) { const auto children = findChildren(); for (WidgetType* widget : children) { widget->setProperty("lastEnabledState", widget->isEnabled()); widget->setEnabled(!disabled); } } template void restoreReadonly() { const auto children = findChildren(); for (WidgetType* widget : children) { QVariant lastState = widget->property("lastReadOnlyState"); if (lastState.isValid() && !lastState.isNull() && lastState.canConvert(QMetaType::Bool)) widget->setReadOnly(lastState.toBool()); } } template void restoreEnabled() { const auto children = findChildren(); for (WidgetType* widget : children) { QVariant lastState = widget->property("lastEnabledState"); if (lastState.isValid() && !lastState.isNull() && lastState.canConvert(QMetaType::Bool)) widget->setEnabled(lastState.toBool()); } } public slots: void slotChangesMade(); void slotHide(); void slotLock(const QString& lockedBy); void slotUnlock(); private slots: void slotApply(); void slotOkay(); void slotClose(); void onReadOnlyButtonClicked(); protected: virtual void lock(); virtual void unlock(); virtual bool apply() { return true; } void showEvent(QShowEvent* event) override; Button askApplyDiscardCancel(); LtsDialogButtonBox* m_buttonBox; UiRequirementList* m_uiRequirements; }; template T* initDialog(T* dialog) { if (!dialog->init()) { dialog->deleteLater(); return nullptr; } return dialog; } template T* initDialog(T* dialog, F&&... f) { if (!dialog->init(std::forward(f)...)) { dialog->deleteLater(); return nullptr; } return dialog; } template T* createThrowableDialog(F&&... f) { T* dlg = nullptr; try { dlg = new T(std::forward(f)...); } catch (const char* s) { fprintf(stderr, "Dialog could not be created: %s\n", s); return nullptr; } catch (const QString& msg) { fprintf(stderr, "Dialog could not be created: %s\n", msg.toStdString().c_str()); return nullptr; } catch (...) { fprintf(stderr, "Dialog could not be created: unknown error\n"); return nullptr; } return dlg; } } // namespace LtsWidgets