#include "lts_dialog.h" #include "lts_progress_dialog_helper.h" #include "lts_message_dialog.h" #include "lts_dialog_helper.h" #include "lts_dialog_button_box.h" #include "lts_base_layout_widget.h" #include "lts_date_time_edit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace LtsWidgets { int LtsDialog::s_object_count = 0; class OverlayContainer : public QWidget { Q_OBJECT public: OverlayContainer(QWidget *parent); protected: void paintEvent(QPaintEvent *e) override; }; OverlayContainer::OverlayContainer(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_TranslucentBackground); } void OverlayContainer::paintEvent(QPaintEvent *e) { QPainter p(this); p.fillRect(rect(), { 80, 80, 80, 200 }); QWidget::paintEvent(e); } LtsDialog::LtsDialog(QWidget *parent, ButtonCombination buttonCombination, bool closeable) : QWidget() , m_changesMade(false) , m_firstShow(true) , m_baseLayoutWidget(nullptr) , m_isClosable(closeable) , m_noLockTopic(false) , m_unchangeableDialog(false) , m_dialogHelper(new LtsDialogHelper(nullptr)) , m_buttonBox(nullptr) , m_uiRequirements(new UiRequirementList()) , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("LtsWidget.LtsDialog")) { Q_UNUSED(parent); s_object_count++; m_dialogHelper->setDialog(this); m_buttonBox = m_dialogHelper->getButtonBox(); addDebugMenuButton(); connect(m_buttonBox->getButton(DialogButton::Close), &QPushButton::clicked, this, &LtsDialog::slotClose); switch(buttonCombination) { case ButtonCombination::OkCancel: { m_buttonBox->getButton(DialogButton::Close)->setText(tr("Cancel")); connect(m_buttonBox->getButton(DialogButton::Ok), &QPushButton::clicked, this, &LtsDialog::slotOkay); break; } case ButtonCombination::OkApplyCancel: { m_buttonBox->getButton(DialogButton::Close)->setText(tr("Cancel")); connect(m_buttonBox->getButton(DialogButton::Ok), &QPushButton::clicked, this, &LtsDialog::slotOkay); connect(m_buttonBox->getButton(DialogButton::Apply), &QPushButton::clicked, this, &LtsDialog::slotApply); m_buttonBox->getButton(DialogButton::Apply)->setVisible(true); break; } case ButtonCombination::CloseOnly: { m_buttonBox->getButton(DialogButton::Ok)->setVisible(false); setUnchangeable(); break; } default: case ButtonCombination::SeamlessDialog: { m_buttonBox->setVisible(false); setContentsMargins(0,0,0,0); m_dialogHelper->setContentsMargins(0,0,0,0); QLayout *l = m_dialogHelper->layout(); if (l) { l->setContentsMargins(0,0,0,0); l->setMargin(0); } else { qWarning() << "LtsDialog::c_tor: Dialog Helper has no layout to set margins"; } break; } } if (!closeable) { m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setVisible(false); m_buttonBox->getButton(LtsWidgets::DialogButton::Close)->setVisible(false); } } LtsDialog::~LtsDialog() { delete m_uiRequirements; if (m_overlayWidget) m_overlayWidget->setParent(nullptr); s_object_count--; } void LtsDialog::setOverlay(QWidget *widget) { if (m_overlayContainer) { if (m_overlayWidget) { m_overlayWidget->hide(); m_overlayWidget->setParent(nullptr); m_overlayWidget->hide(); m_overlayWidget = nullptr; } m_overlayContainer->hide(); m_overlayContainer->setParent(nullptr); m_overlayContainer->hide(); m_overlayContainer->deleteLater(); m_overlayContainer = nullptr; } OverlayContainer *overlayContainer = new OverlayContainer(m_dialogHelper); connect(m_dialogHelper.data(), &LtsDialogHelper::signalSizeChanged, overlayContainer, [overlayContainer](const QSize &size) { overlayContainer->setGeometry(QRect(QPoint(0, 0), size)); }); overlayContainer->setGeometry(QRect(QPoint(0, 0), m_dialogHelper->size())); m_overlayContainer = overlayContainer; QHBoxLayout *l = new QHBoxLayout; m_overlayContainer->setLayout(l); widget->setAutoFillBackground(true); l->addWidget(widget, 0, Qt::AlignCenter); widget->show(); connect(widget, &QWidget::destroyed, m_overlayContainer.data(), &QObject::deleteLater); m_overlayWidget = widget; m_overlayContainer->show(); m_overlayContainer->raise(); } void LtsDialog::unsetOverlay() { if (m_overlayWidget) m_overlayWidget->setParent(nullptr); if (!m_overlayContainer) return; m_overlayContainer->setParent(nullptr); m_overlayContainer->deleteLater(); } LtsDialogHelper *LtsDialog::getHelper() { return m_dialogHelper; } LtsBaseLayoutWidget* LtsDialog::baseLayoutWidget() { return m_baseLayoutWidget; } void LtsDialog::setOnlineHelpFilename(const QString &fileName) { m_onlineHelpFileName = fileName; QPushButton *btn = m_buttonBox->getButton(DialogButton::Help); if (btn == nullptr) return; if (LtsSessionData::LtsSessionData::getInstance()->isTablet() && strcmp(PROJECTBUILD, "guez") == 0) return; connect(btn, &QPushButton::clicked, this, [this]() { emit signalShowOnlineHelp(m_onlineHelpFileName); }); btn->setVisible(true); } void LtsDialog::addDebugMenuButton() { #ifdef LTS_DEBUG QMenu *menu = new QMenu(this); menu->addAction(QStringLiteral("simulate changes"), this, &LtsDialog::slotChangesMade); menu->addAction(QStringLiteral("unchange"), this, &LtsDialog::__unchange__); menu->addAction(QStringLiteral("retranslate"), this, &LtsDialog::retranslate); menu->addAction(QStringLiteral("force unlock"), this, [this]() { setUnchangeable(false); }); menu->addAction(QStringLiteral("set unchangeable"), this, [this]() { setUnchangeable(); }); menu->addAction(QStringLiteral("try lock"), this, &LtsDialog::tryLockTopic); menu->addAction(QStringLiteral("set closable"), this, [this]() { m_isClosable = true; }); menu->addAction(QStringLiteral("set unclosable"), this, [this]() { m_isClosable = false; }); menu->addAction(QStringLiteral("clear requirements"), this, [this] { m_uiRequirements->clear(); }); menu->addAction(QStringLiteral("enable all button box buttons"), this, [this]() { const auto children = m_buttonBox->findChildren(); for (QPushButton *pb : children) pb->setEnabled(true); }); menu->addAction(QStringLiteral("show button box button .."), this, [this]() { QString buttonObjectName = QInputDialog::getText(this, QString(), QStringLiteral("Enter button object name")); if (buttonObjectName.isEmpty()) return; const QList buttons = m_buttonBox->findChildren(buttonObjectName); int btnCount = buttons.count(); if (btnCount == 0) { LtsMessageDialog::showMessage(this, QStringLiteral("button not found")); return; } if (btnCount > 1) { QStringList buttonStringList; buttonStringList.reserve(buttons.size()); for (QPushButton *pb : buttons) buttonStringList += pb->objectName(); LtsMessageDialog::showMessage(this, QStringLiteral("button ambiguous: %1").arg(buttonStringList.join(QStringLiteral(", ")))); return; } buttons.at(0)->setVisible(true); }); QPushButton *debugBtn = m_buttonBox->getButton(DialogButton::_debug_); debugBtn->setMenu(menu); debugBtn->setVisible(true); #endif } void LtsDialog::updateWindowTitle() { QString completeTitle = m_title; if (m_changesMade) completeTitle.insert(0, QStringLiteral("\u2022")); if (!m_topicLockedBy.isEmpty()) completeTitle.push_back(QString(QStringLiteral(" - READ-ONLY (%1)")).arg(m_topicLockedBy)); QWidget::setWindowTitle(completeTitle); if (m_dialogHelper != nullptr) m_dialogHelper->setWindowTitle(completeTitle); } void LtsDialog::setWindowTitle(const QString &title) { m_title = title; updateWindowTitle(); } void LtsDialog::setBaseLayoutWidget(LtsBaseLayoutWidget *baseLayoutWidget) { m_baseLayoutWidget = baseLayoutWidget; } void LtsDialog::setIdentifier(const QString &identifier) { m_identifier = identifier; tableColumnOrganiserSetting(); } void LtsDialog::addConnections(QWidget *widget) { if (addChangesMadeSignal(widget, &QLineEdit::textChanged)) return; if (addChangesMadeSignal(widget, &QDateTimeEdit::dateTimeChanged)) return; if (addChangesMadeSignal(widget, &QComboBox::currentTextChanged)) return; if (addChangesMadeSignal(widget, &QCheckBox::stateChanged)) return; if (addChangesMadeSignal(widget, static_cast(&QSpinBox::valueChanged))) return; if (addChangesMadeSignal(widget, static_cast(&QDoubleSpinBox::valueChanged))) return; if (addChangesMadeSignal(widget, &QSlider::valueChanged)) return; if (addChangesMadeSignal(widget, &QPlainTextEdit::textChanged)) return; if (addChangesMadeSignal(widget, &QTextEdit::textChanged)) return; if (addChangesMadeSignal(widget, &QAbstractButton::toggled)) return; if (addChangesMadeSignal(widget, &LtsDateTimeEdit::dateTimeChanged)) return; } void LtsDialog::setUnchangeable(bool unchangeable) { m_unchangeableDialog = unchangeable; } bool LtsDialog::addDialogFixed(LtsDialog *dialog, const char *menuGroupUntranslated, const QString &identifier, const LayoutArea &layoutArea, bool setClosable, bool focusNewTab) { return addDialog(dialog, tr(menuGroupUntranslated) , identifier, layoutArea, setClosable, focusNewTab); } bool LtsDialog::addDialog(LtsDialog *dialog, const QString &menuGroup, const QString &identifier, const LayoutArea &layoutArea, bool setClosable, bool focusNewTab) { if (!m_baseLayoutWidget) { qCritical() << "LtsDialog: addDialog: no base layout set - cannot add Dialog !"; return false; } return m_baseLayoutWidget->addWidget(dialog, menuGroup, identifier, layoutArea, setClosable, focusNewTab); } bool LtsDialog::amIFocused() const { if (!m_baseLayoutWidget) { qCritical() << "LtsDialog: addDialog: no base layout set - cannot check for focus!"; return false; } return m_baseLayoutWidget->isDialogFocused(this); } bool LtsDialog::focusDialog(const QString &menuGroup, const QString &identifier, const LayoutArea &layoutArea) { if (!m_baseLayoutWidget) { qCritical() << "LtsDialog: addDialog: no base layout set - cannot focus Dialog !"; return false; } return m_baseLayoutWidget->focusTab(menuGroup, identifier, layoutArea); } void LtsDialog::showEvent(QShowEvent *event) { emit visibilityChanged(true); bool tmp = m_unchangeableDialog; if (!m_firstShow) { QWidget::showEvent(event); return; } m_unchangeableDialog = true; m_firstShow = false; QList listenWidgets = findChildren(); for (auto i = listenWidgets.begin(); i != listenWidgets.end(); ++i) { QWidget *widget = *i; QVariant isConst = widget->property("const"); if (isConst.isValid() && isConst.toBool()) continue; if (!tmp) addConnections(widget); #ifdef TABLET_MODE LtsWidgets::addTouchScroll(widget); #endif } QWidget::showEvent(event); m_unchangeableDialog = tmp; } void LtsDialog::tryLockTopic() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (!m_topicInfo.isValid()) return; if (m_topicInfo.isLocked()) { WARNING_LOG(m_logger) << LOGFUNCTION << " tried to lock with an already locked topic info, return"; return; } if (m_noLockTopic) return; bool bIsConnected = isSignalConnected(QMetaMethod::fromSignal(&LtsDialog::signalLockTopic)); DEBUG_LOG(m_logger) << LOGFUNCTION << " signalLockTopic(): " << ", TopicName =" << m_topicInfo.topicName() << ", entity =" << m_topicInfo.entityId() << ", signalLockTopic isConnected=" << bIsConnected; if (bIsConnected) { emit signalLockTopic(m_topicInfo); m_topicInfo.setLocked(); } TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void LtsDialog::initTopicLockHandler(const QString &topicName, int entityId) { m_topicInfo.setTopicName(topicName); m_topicInfo.setEntity(entityId); m_topicInfo.setValid(); } void LtsDialog::tryLockTopicNew() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; tryLockTopic(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void LtsDialog::tryLockTopicNew(const QString &topicName, int entityId) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", topicName='" << topicName << "'" << ", entityId=" << entityId; if (m_topicInfo.entityId() != entityId) { DEBUG_LOG(m_logger) << LOGFUNCTION << " topicName='" << topicName << "'" << " change from " << m_topicInfo.entityId() << " to " << entityId; m_topicInfo.setLocked(false); } m_topicInfo.setTopicName(topicName); m_topicInfo.setEntity(entityId); m_topicInfo.setValid(); tryLockTopic(); TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", topicName='" << topicName << "'" << ", entityId=" << entityId; } void LtsDialog::triggerTopicLock() { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " !!trigger!!"; tryLockTopic(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void LtsDialog::translate(const QString &title) { bool isAlreadyUnchangeable = unchangeable(); if (!isAlreadyUnchangeable) setUnchangeable(true); setWindowTitle(title); if (!isAlreadyUnchangeable) setUnchangeable(false); { bool isNowAlreadyUnchangeable = unchangeable(); QPushButton *b = m_buttonBox->getButton(DialogButton::ReadOnly); if (b) { connect(b, &QPushButton::clicked, this, &LtsDialog::onReadOnlyButtonClicked, Qt::UniqueConnection); b->setVisible(isNowAlreadyUnchangeable && !m_topicLockedBy.isEmpty()); if (b->isVisible()) b->setToolTip(tr("Locked by: %1").arg(m_topicLockedBy)); else b->setToolTip({}); } } } void LtsDialog::slotLock(const QString &lockedBy) { setUnchangeable(true); m_topicLockedBy = lockedBy; lock(); retranslate(); } void LtsDialog::slotUnlock() { setUnchangeable(false); m_topicLockedBy.clear(); unlock(); retranslate(); } void LtsDialog::lock() { setWidgetsReadonly(true); setWidgetsReadonly(true); setWidgetsReadonly(true); setWidgetsReadonly(true); setWidgetsReadonly(true); setWidgetsReadonly(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); setWidgetsDisabled(true); } void LtsDialog::unlock() { restoreReadonly(); restoreReadonly(); restoreReadonly(); restoreReadonly(); restoreReadonly(); restoreReadonly(); restoreEnabled(); restoreEnabled(); restoreEnabled(); restoreEnabled(); restoreEnabled(); restoreEnabled(); restoreEnabled(); restoreEnabled(); } void LtsDialog::slotChangesMade() { if (m_unchangeableDialog) return; m_changesMade = true; updateWindowTitle(); m_buttonBox->getButton(DialogButton::Ok)->setEnabled(true); m_buttonBox->getButton(DialogButton::Apply)->setEnabled(true); emit signalChangesMade(); } void LtsDialog::resetChanges() { m_changesMade = false; updateWindowTitle(); m_buttonBox->getButton(DialogButton::Ok)->setEnabled(false); m_buttonBox->getButton(DialogButton::Apply)->setEnabled(false); emit signalChangesReset(); } bool LtsDialog::_apply() { if (m_uiRequirements->checkRequirements(this) && apply()) { resetChanges(); return true; } return false; } Button LtsDialog::askApplyDiscardCancel() { return LtsMessageDialog::askApplyDiscardCancel(this); } void LtsDialog::slotApply() { _apply(); } void LtsDialog::slotOkay() { if (_apply()) _close(); } void LtsDialog::slotHide() { _hide(); } void LtsDialog::slotClose() { if ((m_changesMade) && (!m_unchangeableDialog)) { switch (askApplyDiscardCancel()) { case Button::Apply: slotOkay(); break; case Button::Discard: _discard(); break; default: break; } } else { _close(); } } void LtsDialog::onReadOnlyButtonClicked() { if (m_topicLockedBy.isEmpty()) return; LtsWidgets::LtsMessageDialog::showMessage(this, tr("Locked by: %1").arg(m_topicLockedBy)); } void LtsDialog::closeRequest() { slotClose(); } void LtsDialog::_hide() { if (m_dialogHelper != nullptr) { emit signalHide(m_dialogHelper); } } void LtsDialog::_close() { resetChanges(); aboutToClose(); if (m_dialogHelper != nullptr) m_dialogHelper->close(); } void LtsDialog::_discard() { dialogCanceled(); _close(); } } #include "lts_dialog.moc"