#include "lts_base_layout_widget.h" #include "ui_lts_base_layout.h" #include "lts_dialog.h" #include "lts_dialog_helper.h" #include "lts_drag_icon.h" #include "lts_grid_layout.h" #include "lts_message_dialog.h" #include "lts_operator_menu.h" #include "lts_tool_bar_area.h" #include "lts_splash.h" #include "lts_events.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 namespace LtsWidgets { static QVariant splitterInterpolator(const QList &start, const QList &end, qreal progress) { QList ret; ret = start; for (int i = 0; i < start.size(); i++) { ret[i] = start[i] + qRound((end[i] - start[i]) * progress); if (ret[i] <= 0) ret[i] = 1; } return QVariant::fromValue(ret); } LtsBaseLayoutWidget::LtsBaseLayoutWidget(QWidget *parent, bool splitMenu) : QWidget(parent) , m_currentAnimation(nullptr) , m_ui(new Ui::LtsBaseLayoutWidget) , m_partitionType(IDL::PartitionType::Global) , m_domainId(-1) , m_partitionId(-1) , m_firstShow(true) , m_showTerminalButton(false) , m_exerciseTime(0) , m_setCurrentTimeTimer(new QTimer(this)) , m_irreplaceableOnce(false) , m_bg(nullptr) , m_screenCount(1) , m_menuCollapsed(true) , m_notiBox(nullptr) { m_ui->setupUi(this); #ifndef LTS_DEBUG m_ui->pbDebug->hide(); #endif addDebugMenu(); { m_ui->lbCurrentTime->setContextMenuPolicy(Qt::CustomContextMenu); QMenu *currentTimeMenu = new QMenu(m_ui->lbCurrentTime); currentTimeMenu->addAction(tr("Copy"), this, [this]() { QGuiApplication::clipboard()->setText(m_ui->lbCurrentTime->text()); }); currentTimeMenu->addAction(tr("Copy in milliseconds"), this, []() { QGuiApplication::clipboard()->setText(QString::number(QDateTime::currentMSecsSinceEpoch())); }); connect(m_ui->lbCurrentTime, &QLabel::customContextMenuRequested, this, [this, currentTimeMenu](const QPoint &pos) { currentTimeMenu->popup(m_ui->lbCurrentTime->mapToGlobal(pos)); }); } { m_ui->lbExerciseTime->setContextMenuPolicy(Qt::CustomContextMenu); QMenu *exerciseTimeMenu = new QMenu(m_ui->lbExerciseTime); exerciseTimeMenu->addAction(tr("Copy"), this, [this]() { QGuiApplication::clipboard()->setText(m_ui->lbExerciseTime->text()); }); exerciseTimeMenu->addAction(tr("Copy in milliseconds"), this, [this]() { QGuiApplication::clipboard()->setText(QString::number(m_exerciseTime)); }); connect(m_ui->lbExerciseTime, &QLabel::customContextMenuRequested, this, [this, exerciseTimeMenu](const QPoint &pos) { exerciseTimeMenu->popup(m_ui->lbExerciseTime->mapToGlobal(pos)); }); } setMinimumSize(1280, 900); m_ui->detailWidget->setSubTabsVisible(true); qRegisterAnimationInterpolator >(splitterInterpolator); qRegisterMetaType("LayoutArea"); m_ui->mainWidget->setTabBarAutoHide(true); m_ui->infoWidget->setActuatorTabStyle(true); m_ui->infoWidget->setTabBarAutoHide(false); m_ui->infoWidget->setTabPosition(QTabWidget::West); if (m_ui->infoWidget->count() == 0) m_ui->infoWidget->hide(); if (m_ui->detailWidget->count() == 0) m_ui->detailWidget->hide(); if (m_ui->specialWidget->count() == 0) m_ui->specialWidget->hide(); m_ui->masterSplitter->setStretchFactor(m_ui->masterSplitter->indexOf(m_ui->infoWidget), 0); m_ui->masterSplitter->setStretchFactor(m_ui->masterSplitter->indexOf(m_ui->mainSplitter), 20); m_ui->mainSplitter->setStretchFactor(m_ui->mainSplitter->indexOf(m_ui->mainWidget), 20); m_ui->mainSplitter->setStretchFactor(m_ui->mainSplitter->indexOf(m_ui->detailWidget), 0); m_ui->rightSplitter->setStretchFactor(m_ui->rightSplitter->indexOf(m_ui->stackedWidget), 20); m_ui->rightSplitter->setStretchFactor(m_ui->rightSplitter->indexOf(m_ui->specialWidget), 0); m_isHidden = false; connect(m_ui->profileButton, &LtsProfileButton::signalClicked, this, &LtsBaseLayoutWidget::slotOperatorMenuClicked); m_ui->lbCustomTextBullet->hide(); m_ui->lbCustomText->hide(); m_ui->lbExerciseTime->setText(QStringLiteral(" # ")); m_ui->lbCurrentTime->setText(QStringLiteral(" # ")); connect(m_setCurrentTimeTimer, &QTimer::timeout, this, &LtsBaseLayoutWidget::setCurrentTime); m_setCurrentTimeTimer->start(200); setExerciseData(m_exerciseData); if (splitMenu) { m_bg = new QButtonGroup(m_ui->naviWidget); m_bg->addButton(m_ui->pbPlanning, (int) ExercisePart::ePlanning); m_bg->addButton(m_ui->pbExecution, (int) ExercisePart::eExecution); m_bg->addButton(m_ui->pbAfterAction, (int) ExercisePart::eAfterAction); m_bg->addButton(m_ui->pbSpecial, (int) ExercisePart::eSpecial); connect(m_bg, QOverload::of(&QButtonGroup::buttonClicked), m_ui->stackedWidget, [this](int id) { m_ui->stackedWidget->setCurrentWidget(getToolBox((ExercisePart) id)); }); m_ui->pbSpecial->click(); } else { m_ui->stackedWidget->setCurrentWidget(getToolBox(ExercisePart::eSpecial)); } checkExercisePartButtonVisibility(); } LtsBaseLayoutWidget::~LtsBaseLayoutWidget() { if (m_notiBox != nullptr) m_notiBox->setParent(nullptr); delete m_notiBox; delete m_currentAnimation; m_currentAnimation = nullptr; clearMenuActions(); delete m_ui; m_ui = nullptr; } void LtsBaseLayoutWidget::setCurrentTime() { m_ui->lbCurrentTime->setText(DTG::toString(QDateTime::currentDateTime())); if (m_exerciseTime > 0) m_ui->lbExerciseTime->setText(DTG::toStringMSec(m_exerciseTime)); else m_ui->lbExerciseTime->setText(QStringLiteral(" # ")); } void LtsBaseLayoutWidget::slotScreenCountChanged(int count) { m_screenCount = count; } const QString LtsBaseLayoutWidget::customText() const { return m_ui->lbCustomText->text(); } void LtsBaseLayoutWidget::setCustomText(const QString &text) { if (text.isEmpty()) { m_ui->lbCustomText->setText(QString()); m_ui->lbCustomText->hide(); m_ui->lbCustomTextBullet->hide(); return; } m_ui->lbCustomText->show(); m_ui->lbCustomTextBullet->show(); m_ui->lbCustomText->setText(text); } void LtsBaseLayoutWidget::addDebugMenu() { #ifdef LTS_DEBUG QMenu *menu = new QMenu(this); menu->addAction(QStringLiteral("NOTE: all actions are delayed by 1s"))->setEnabled(false); menu->addSeparator(); menu->addAction(QStringLiteral("logout"), this, [this]() { QTimer::singleShot(1000, this, &LtsBaseLayoutWidget::slotLogout); }); menu->addAction(QStringLiteral("forced logout"), this, [this]() { QTimer::singleShot(1000, this, &LtsBaseLayoutWidget::signalLogout); }); menu->addAction(QStringLiteral("app exit"), this, [this]() { QTimer::singleShot(1000, this, &LtsBaseLayoutWidget::signalClose); }); menu->addSeparator(); menu->addAction(QStringLiteral("show test message, unparented"), this, [this]() { QTimer::singleShot(1000, this, []() { LtsWidgets::LtsMessageDialog::showMessage(nullptr , QStringLiteral("test"), QStringLiteral("test")); } ); }); menu->addAction(QStringLiteral("show test message"), this, [this]() { QTimer::singleShot(1000, this, [this]() { LtsWidgets::LtsMessageDialog::showMessage(this, QStringLiteral("test"), QStringLiteral("test")); } ); }); menu->addSeparator(); menu->addAction(QStringLiteral("hide details tab"), this, [this]() { QTimer::singleShot(1000, this, [this]() { this->hideWidgets(); } ); }); menu->addAction(QStringLiteral("show details tab"), this, [this]() { QTimer::singleShot(1000, this, [this]() { this->showWidgets(); } ); }); menu->addAction(QStringLiteral("hide details tab, animated"), this, [this]() { QTimer::singleShot(1000, this, [this]() { this->onHideAnimated(); } ); }); menu->addAction(QStringLiteral("show details tab, animated"), this, [this]() { QTimer::singleShot(1000, this, [this]() { this->onReShowAnimated(); } ); }); menu->addSeparator(); menu->addAction(QStringLiteral("hide top bar"), this, [this]() { QTimer::singleShot(1000, this, [this]() { this->setTopBarVisible(false); } ); }); menu->addSeparator(); menu->addAction(QStringLiteral("test NotificationBox with error"), this, [this]() { QTimer::singleShot(1000, this, [this]() { showMessage(QStringLiteral("Test Title"), QStringLiteral("A long test text that notifies the user about something
that spreads over two lines to fit even more text."), LtsWidgets::LtsNotificationBox::MessageType::Error, [this](const QString &) { new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("You clicked the link!")); }, true, QInputDialog::getText(this, QStringLiteral("Identifier"), QStringLiteral("Identifier (keep empty to not set)"))); }); }); menu->addAction(QStringLiteral("test NotificationBox with success"), this, [this]() { QTimer::singleShot(1000, this, [this]() { showMessage(QStringLiteral("Test Title"), QStringLiteral("A long test text that notifies the user about something
that spreads over two lines to fit even more text."), LtsWidgets::LtsNotificationBox::MessageType::Success, [this](const QString &) { new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("You clicked the link!")); }, true, QInputDialog::getText(this, QStringLiteral("Identifier"), QStringLiteral("Identifier (keep empty to not set)"))); }); }); menu->addAction(QStringLiteral("test NotificationBox with info"), this, [this]() { QTimer::singleShot(1000, this, [this]() { showMessage(QStringLiteral("Test Title"), QStringLiteral("A long test text that notifies the user about something
that spreads over two lines to fit even more text."), LtsWidgets::LtsNotificationBox::MessageType::Info, [this](const QString &) { new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("You clicked the link!")); }, true, QInputDialog::getText(this, QStringLiteral("Identifier"), QStringLiteral("Identifier (keep empty to not set)"))); }); }); menu->addAction(QStringLiteral("test NotificationBox with warning"), this, [this]() { QTimer::singleShot(1000, this, [this]() { showMessage(QStringLiteral("Test Title"), QStringLiteral("A long test text that notifies the user about something
that spreads over two lines to fit even more text."), LtsWidgets::LtsNotificationBox::MessageType::Warning, [this](const QString &) { new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("You clicked the link!")); }, true, QInputDialog::getText(this, QStringLiteral("Identifier"), QStringLiteral("Identifier (keep empty to not set)"))); }); }); m_ui->pbDebug->setMenu(menu); #endif } void LtsBaseLayoutWidget::showEvent(QShowEvent *event) { QWidget::showEvent(event); if (!m_firstShow) return; m_firstShow = false; QSize rendererSizeHint = m_ui->topLayoutWidget->sizeHint(); rendererSizeHint.scale(rendererSizeHint.width() * 0.65, rendererSizeHint.height() * 0.65, Qt::IgnoreAspectRatio); const auto dpr = devicePixelRatioF(); { const QSize s(QSize(rendererSizeHint.height(), rendererSizeHint.height()) * dpr); QSvgRenderer svgRenderer; QPixmap pixmap(s); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); svgRenderer.load(QLatin1String(":rde_splitter_left.svg")); svgRenderer.render(&painter); painter.end(); pixmap.setDevicePixelRatio(dpr); m_ui->lbRdeSplitterLeft->setPixmap(pixmap); } { QString projectLogoFilename = QLatin1String(":project/logo.png"); QPixmap pixmap(projectLogoFilename); pixmap.setDevicePixelRatio(dpr); if (pixmap.isNull()) { qWarning() << "LoginWindow::c_tor: (PROJECT LOGO) file missing or is not an valid image '" << projectLogoFilename << "'"; } else { pixmap = pixmap.scaled(rendererSizeHint * dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_ui->lbProjectLogo->setPixmap(pixmap); } } #ifdef TABLET_MODE QList scrollWidgets = findChildren(); for (auto i = scrollWidgets.begin(); i != scrollWidgets.end(); ++i) { QWidget *widget = *i; QVariant isConst = widget->property("const"); if (isConst.isValid() && isConst.toBool()) continue; addTouchScroll(widget); } #endif Splash::getInstance()->done(); } void LtsBaseLayoutWidget::addTouchScroll(QWidget *widget) { if (!widget) return; widget->setAttribute(Qt::WA_AcceptTouchEvents); QScrollArea *sca = qobject_cast(widget); if (sca) { QScroller::grabGesture(sca->viewport(), QScroller::LeftMouseButtonGesture); return; } QAbstractItemView *aiv = qobject_cast(widget); if (aiv) { QScroller::grabGesture(aiv->viewport(), QScroller::LeftMouseButtonGesture); aiv->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); aiv->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); return; } } void LtsBaseLayoutWidget::setAppName(const QString &appName) { m_ui->lbAppName->setText(appName); } void LtsBaseLayoutWidget::setExerciseData(const ExerciseData &data) { m_exerciseData = data; m_ui->lbExerciseName->setText(data.exName.isEmpty() ? tr("no exercise") : data.exName); QString exerciseNameToolTip(tr("Exercise name")); if (!data.exName.isEmpty() && m_partitionId > 0) { exerciseNameToolTip += tr("\nPartition Id:"); exerciseNameToolTip += QStringLiteral(" %1").arg(m_partitionId); } if (!data.exDescription.isEmpty()) { exerciseNameToolTip += tr("\nDescription:"); exerciseNameToolTip += QStringLiteral(" %1").arg(data.exDescription); } m_ui->lbExerciseName->setToolTip(exerciseNameToolTip); LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance(); const bool enableEditPhases = ps->value(QStringLiteral("exm"), QStringLiteral("enableEditPhases")).toBool(); if (!enableEditPhases) { m_ui->lbExercisePhase->hide(); m_ui->bullet1->hide(); } m_ui->lbExercisePhase->setText(data.phName.isEmpty() ? tr("no phase") : data.phName); QString phaseNameToolTip(tr("Exercise phase")); if (!data.phDescription.isEmpty()) { phaseNameToolTip += tr("\nDescription:"); phaseNameToolTip += QStringLiteral(" %1").arg(data.phDescription); } m_ui->lbExercisePhase->setToolTip(phaseNameToolTip); m_ui->lbExerciseStatus->setText(data.exStateString.isEmpty() ? tr("no status") : data.exStateString); if (data.exStateCol.isValid() && data.exStateCol != QColor()) { QPalette p = m_ui->lbExerciseStatus->palette(); p.setColor(m_ui->lbExerciseStatus->backgroundRole(), data.exStateCol); p.setColor(m_ui->lbExerciseStatus->foregroundRole(), data.exStateCol); m_ui->lbExerciseStatus->setPalette(p); } m_ui->lbPartitionType->setText(data.partitionType); applyExerciseStateRestricition(); } void LtsBaseLayoutWidget::applyExerciseStateRestricition() { for (auto it = m_mapButtons.cbegin(); it != m_mapButtons.cend(); ++it) { bool visible = it.value().exerciseStates.testFlag(m_exerciseData.exState); it.key()->setButtonVisible(visible); } } void LtsBaseLayoutWidget::initilizationFinished() { } void LtsBaseLayoutWidget::setToolBarActions(const QStringList &actions) { QVector desiredActions; m_notFoundYet = actions; for (const QString &action : actions) { for (auto innerIt = m_mapButtons.cbegin(); innerIt != m_mapButtons.cend(); ++innerIt) { if (innerIt.value().identifier.compare(action) == 0) { desiredActions << innerIt.key(); m_notFoundYet.removeAll(action); } } } m_ui->toolBar->setMenuEntries(desiredActions); } QStringList LtsBaseLayoutWidget::toolBarActions() const { if (m_ui == nullptr || m_ui->toolBar == nullptr) return QStringList(); return m_ui->toolBar->menuEntries(); } void LtsBaseLayoutWidget::setFunctionKeys(const QMap &actions) { for (auto it = actions.cbegin(); it != actions.cend(); ++it) m_ui->toolBar->setFunctionKey(it.key(), it.value()); } QMap LtsBaseLayoutWidget::functionKeys() const { if (m_ui == nullptr) return QMap(); return m_ui->toolBar->functionKeys(); } void LtsBaseLayoutWidget::setSessionInfo(const int domainId, const IDL::PartitionType &partitionType, const int partitionId, const QString &workspaceId) { m_domainId = domainId; m_partitionType = partitionType; m_partitionId = partitionId; m_workspaceId = workspaceId; } void LtsBaseLayoutWidget::setOperatorName(const QString &operatorName, bool showTerminalButton) { m_operatorName = operatorName; if (m_operatorName.isEmpty()) m_operatorName = tr("Admin"); m_ui->profileButton->setToolTip(tr("Operator Name: %1").arg(m_operatorName)); m_showTerminalButton = showTerminalButton; } void LtsBaseLayoutWidget::setProfilePicture(const QPixmap &profilePicture) { m_ui->profileButton->setPixmap(profilePicture); } void LtsBaseLayoutWidget::slotOperatorMenuClicked() { bool debug = false; #ifndef LTS_DEBUG if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("DeveloperTools.Actions")) == QVariant(true)) #endif { debug = true; } LtsOperatorMenu *operatorMenu = new LtsOperatorMenu(m_operatorName, m_workspaceId, debug, m_screenCount, this); operatorMenu->setTerminalButton(m_showTerminalButton); bool hasOperatorSettings = false; for (const PluginData &pd : qAsConst(m_mapButtons)) { if (pd.identifier == QStringLiteral("_OpmShowOperatorSettings")) { hasOperatorSettings = true; break; } } operatorMenu->setOperatorSettingsButton(hasOperatorSettings); connect(operatorMenu, &LtsOperatorMenu::signalLogout, this, &LtsBaseLayoutWidget::slotLogout); connect(operatorMenu, &LtsOperatorMenu::signalExit, this, &LtsBaseLayoutWidget::slotClose); connect(operatorMenu, &LtsOperatorMenu::signalShowOperatorSettings, this, &LtsBaseLayoutWidget::signalShowOperatorSettings); connect(operatorMenu, &LtsOperatorMenu::signalSwap, this, &LtsBaseLayoutWidget::signalSwap); operatorMenu->show(); } bool LtsBaseLayoutWidget::haveUnsavedChanges() { if (LtsTabWidget::hasUnsavedChanges(getTabFromLayoutArea(LayoutArea::eDialogTab))) return true; if (LtsTabWidget::hasUnsavedChanges(getTabFromLayoutArea(LayoutArea::eInfoTab))) return true; if (LtsTabWidget::hasUnsavedChanges(getTabFromLayoutArea(LayoutArea::eMainTab))) return true; if (LtsTabWidget::hasUnsavedChanges(getTabFromLayoutArea(LayoutArea::eSpecialTab))) return true; return false; } bool LtsBaseLayoutWidget::notifyUnsavedChanges() { if (isSignalConnected(QMetaMethod::fromSignal(&LtsBaseLayoutWidget::signalNotifyUnsavedChanges))) { bool reject = false; emit signalNotifyUnsavedChanges(reject); return reject; } else { if (haveUnsavedChanges()) { LtsWidgets::Buttons buttons; buttons.setFlag(Button::Yes, true); buttons.setFlag(Button::Cancel, true); QHash buttonTexts; buttonTexts.insert(Button::Yes, tr("Discard All")); const auto ret = LtsMessageDialog::showMessage(this, tr("There are dialogs with unsaved changes.
Please save or discard their changes before closing"), tr("Unsaved changes"),Behaviour::Modal, buttons, buttonTexts); return ret == Button::Yes; } } return true; } void LtsBaseLayoutWidget::slotLogout() { emit signalLogout(); } bool LtsBaseLayoutWidget::slotClose() { if (!notifyUnsavedChanges()) return false; hide(); emit signalClose(); return true; } void LtsBaseLayoutWidget::closeEvent(QCloseEvent *event) { event->ignore(); slotClose(); } bool LtsBaseLayoutWidget::focusTab(const QString &menuGroup, const QString &identifier, LayoutArea area) { LtsTabWidget *tab = getTabFromLayoutArea(area); if (!tab) { qWarning() << "LtsBaseLayoutWidget::focusTab: tab, by enum type, not found!"; return false; } return tab->focusTab(menuGroup, identifier); } bool LtsBaseLayoutWidget::isDialogFocused(const LtsDialog *dialog, const LtsTabWidget *tab) const { QWidget *w = tab->widget(tab->currentIndex()); if (w == nullptr) return false; const LtsTabWidget *secondTab = qobject_cast(w); if (secondTab != nullptr) return isDialogFocused(dialog, secondTab); const LtsDialogHelper *helper = qobject_cast(w); if (helper != nullptr) return helper->compare(dialog); qWarning() << "LtsBaseLayoutWidget::isDialogFocused(LtsDialog *dialog, LtsTabWidget *tab): i found something weird.." << w->metaObject()->className(); return false; } bool LtsBaseLayoutWidget::isDialogFocused(const LtsDialog *dialog, const LayoutArea &layoutArea) const { const LtsTabWidget *tab = getTabFromLayoutArea(layoutArea); if (tab == nullptr) { qWarning() << "LtsBaseLayoutWidget::addWidget: tab, by enum type, not found!"; return false; } return isDialogFocused(dialog, tab); } bool LtsBaseLayoutWidget::isDialogFocused(const LtsDialog *dialog) const { return (isDialogFocused(dialog, LayoutArea::eDialogTab) || isDialogFocused(dialog, LayoutArea::eInfoTab) || isDialogFocused(dialog, LayoutArea::eSpecialTab) || isDialogFocused(dialog, LayoutArea::eMainTab)); } bool LtsBaseLayoutWidget::addOrReplaceWidget(LtsDialog *dialog, const QString &menuGroup, const QString &identifier, LayoutArea area, bool setClosable, bool focusNewTab) { LtsTabWidget *tab = getTabFromLayoutArea(area); if (tab && dialog && (!identifier.isEmpty())) { QWidget *existingWidget = tab->getWidget(menuGroup, identifier); if (nullptr != existingWidget) { if (tab->removeWidget(existingWidget)) { existingWidget->deleteLater(); } else { qWarning() << __FUNCTION__ << " : Remove existing widget from TabWidget failed."; } } } return addWidget(dialog, menuGroup, identifier, area, setClosable, focusNewTab); } bool LtsBaseLayoutWidget::addWidget(LtsDialog *dialog, const QString &menuGroup, const QString &identifier, LayoutArea area, bool setClosable, bool focusNewTab) { if (!dialog) { qWarning() << "LtsBaseLayoutWidget::addWidget: cannot add null-widget!"; return false; } LtsTabWidget *tab = getTabFromLayoutArea(area); if (!tab) { qWarning() << "LtsBaseLayoutWidget::addWidget: tab, by enum type, not found!"; return false; } dialog->setMenuGroup(menuGroup); dialog->setIdentifier(identifier); QWidget *helper = dialog->getHelper(); if (!helper) { helper = dialog; dialog->setAttribute(Qt::WA_DeleteOnClose); } if (!identifier.isEmpty()) { QWidget *existingWidget = tab->getWidget(menuGroup, identifier); if (existingWidget != nullptr) { helper->deleteLater(); if (focusNewTab) tab->focusTab(menuGroup, identifier); int indexOfSplitter = getIndexOfTab(tab); if (area == LayoutArea::eDialogTab && !(m_ui->mainSplitter->sizes().at(indexOfSplitter))) m_ui->mainSplitter->animate(1); else if (area == LayoutArea::eInfoTab && !(m_ui->masterSplitter->sizes().at(indexOfSplitter))) m_ui->masterSplitter->animate(1); return false; } } dialog->setBaseLayoutWidget(this); connect(dialog, &LtsDialog::startMainSelect, this, &LtsBaseLayoutWidget::onHideAnimated); connect(dialog, &LtsDialog::endMainSelect, this, &LtsBaseLayoutWidget::onReShowAnimated); emit signalStapleTopicLockHandler(dialog); dialog->triggerTopicLock(); tab->addTab(menuGroup, identifier, helper, setClosable, focusNewTab); if (tab->count() > 1) { int indexOfSplitter = getIndexOfTab(tab); if (area == LayoutArea::eDialogTab && !(m_ui->mainSplitter->sizes().at(indexOfSplitter))) { qDebug()<<"animate 1a: "; m_ui->mainSplitter->animate(1); } else if (area == LayoutArea::eInfoTab && !(m_ui->masterSplitter->sizes().at(indexOfSplitter))) { qDebug()<<"animate 1b: "; m_ui->masterSplitter->animate(1); } } #ifdef ADJUST_SPLITTER_SIZES_DIALOGTAB if (LayoutArea::eDialogTab == area) { const QList & sizes = m_ui->mainSplitter->sizes(); int requestedTabHeight = tab->sizeHint().height(); int mainHeight = sizes[0]+sizes[1]-requestedTabHeight; m_ui->mainSplitter->setSizes( QList() << mainHeight << requestedTabHeight ); } #endif return true; } LtsDialog *LtsBaseLayoutWidget::getWidget(const QString &menuGroup, const QString &identifier, LayoutArea area) { LtsTabWidget *tab = getTabFromLayoutArea(area); if (tab == nullptr) return nullptr; QWidget *w = tab->getWidget(menuGroup, identifier); if (w == nullptr) return nullptr; LtsDialogHelper *helper = qobject_cast(w); if (helper == nullptr) return nullptr; LtsDialog *dialog = qobject_cast(helper->getDialog()); return dialog; } void LtsBaseLayoutWidget::clearMenuActions() { while (m_ui->naviActionsPlanning->count()) m_ui->naviActionsPlanning->removeItem(0); while (m_ui->naviActionsExecution->count()) m_ui->naviActionsExecution->removeItem(0); while (m_ui->naviActionsAfterAction->count()) m_ui->naviActionsAfterAction->removeItem(0); while (m_ui->naviActionsSpecial->count()) m_ui->naviActionsSpecial->removeItem(0); checkExercisePartButtonVisibility(); for(auto it = m_mapButtons.begin(); it != m_mapButtons.end(); ++it) delete it.key(); m_mapButtons.clear(); } void LtsBaseLayoutWidget::executeCreateInstantFunctions(const PluginData &plData) { if (plData.createWidgetFunc) { LtsDialog *w = plData.createWidgetFunc(this); if (w) addWidget(w, plData.menuGroup, plData.identifier, plData.layoutArea, plData.closable); } if (plData.directFunc) { plData.directFunc(plData); } } void LtsBaseLayoutWidget::setExerciseTime(qint64 mSecsSinceEpoch) { m_exerciseTime = mSecsSinceEpoch; } LtsDragIcon *LtsBaseLayoutWidget::addMenuAction(const PluginData &plData, bool isFirstRun) { if (!LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(plData.operatorRight)) { qDebug() << " > Action" << plData.menuGroup << ":" << plData.menuText << "was not added due to missing operator right 0x" << QString::number(plData.operatorRight, 16); return nullptr; } if (isFirstRun) { switch (plData.createInstant) { case CreateInstantType::CreateInstantAndAddAction: { executeCreateInstantFunctions(plData); break; } case CreateInstantType::CreateInstantAndDiscardAction: { executeCreateInstantFunctions(plData); return nullptr; } default: { break; } } } else { if (plData.createInstant == CreateInstantType::CreateInstantAndDiscardAction) return nullptr; } bool err = false; if (plData.identifier.isEmpty()) { #ifdef LTS_DEBUG LtsWidgets::LtsMessageDialog::showMessage(this, QStringLiteral("STOP!\n" "Hier wurde ein Menu Entry hinzugefuegt, welcher ueber keinen Identifier verfuegt!\n" "Bitte aendern!\n" "Jetzt Debugger attachen und schauen woher der aufruf kommt.\n" "Da der Identifier fehlt kann ich Dir hier nicht sagen um welchen Menu Entry es sich handelt =)")); #endif err = true; } if (plData.menuGroup.isEmpty()) { #ifdef LTS_DEBUG LtsWidgets::LtsMessageDialog::showMessage(this, QStringLiteral("STOP!\n" "Hier wurde ein Menu Entry hinzugefuegt, welcher ueber keine Menu Group verfuegt!\n" "Bitte aendern!\n" "Jetzt Debugger attachen und schauen woher der aufruf kommt.\n" "Da der Identifier fehlt kann ich Dir hier nicht sagen um welchen Menu Entry es sich handelt =)")); #endif err = true; } if (err) return nullptr; bool found = false; if (!isFirstRun) { for (auto it = m_mapButtons.begin(); it != m_mapButtons.end(); ++it) { LtsDragIcon *thatIcon = it.key(); if (thatIcon->objectName() == plData.identifier) { thatIcon->setText(plData.menuText); thatIcon->setContext(plData.menuGroup); bool groupFound = false; for (int i = 0; i < m_ui->stackedWidget->count(); ++i) { LtsWidgets::LtsToolBox *tb = qobject_cast(m_ui->stackedWidget->widget(i)); int groupWidgetIndex = tb->indexOf(thatIcon->parentWidget() ); if (groupWidgetIndex >= 0) { tb->setItemText(groupWidgetIndex, plData.menuGroup); groupFound = true; break; } } if (!groupFound) { qWarning() << "group widget not found"; } found = true; break; } } if (!found) { } else { return nullptr; } } LtsWidgets::LtsToolBox *tb = getToolBox(m_bg ? plData.exercisePart : ExercisePart::eSpecial); QWidget *tmpW = tb->findChild(plData.menuGroup); if (!tmpW) { if (plData.createWidgetFunc == nullptr && plData.directFunc == nullptr) return nullptr; tmpW = new QWidget; tmpW->setObjectName(plData.menuGroup); LtsGridLayout *ltsGridLayout = new LtsGridLayout(LtsWidgets::ButtonSize::eDefault, tmpW); tmpW->setLayout(ltsGridLayout); tb->addItem(tmpW, plData.menuGroup); connect(tb, &LtsToolBox::resized, ltsGridLayout, &LtsGridLayout::onParentResize); } QLayout *widgetLayout = tmpW->layout(); LtsGridLayout *ltsGridLayout = qobject_cast(widgetLayout); if (!ltsGridLayout) { qWarning() << "temp widget has no layout! cannot add action" << plData.menuText << "to menu! (the bad widget was of type" << tmpW->metaObject()->className() << ") [did you forget to add the menuGroup to that action?]"; return nullptr; } if (widgetLayout->count() > 0) { QSpacerItem *spacer = dynamic_cast(widgetLayout->itemAt(widgetLayout->count() - 1)); if (spacer) { ltsGridLayout->removeItem(spacer); delete spacer; } } LtsDragIcon *dragIcon = nullptr; if (plData.createWidgetFunc == nullptr && plData.directFunc == nullptr) { QFrame *line = new QFrame(tmpW); line->setLineWidth(2); line->setFrameStyle(QFrame::HLine); ltsGridLayout->add_widget(line); } else { if (isFirstRun || !found) { dragIcon = createButton(plData); ltsGridLayout->add_widget(dragIcon); m_mapButtons.insert(dragIcon, plData); auto it = std::find_if(m_notFoundYet.begin(), m_notFoundYet.end(), [plData](const QString &s) { return s == plData.identifier; }); if (it != m_notFoundYet.end()) { m_ui->toolBar->addMenuEntry(dragIcon); m_notFoundYet.erase(it); } } } checkExercisePartButtonVisibility(); QSpacerItem *spacer = new QSpacerItem(10, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); ltsGridLayout->addItem(spacer, ltsGridLayout->rowCount(), 0); return dragIcon; } void LtsBaseLayoutWidget::addNotification(QToolButton *noti) { m_ui->notificationLayoutWidget->layout()->addWidget(noti); } bool LtsBaseLayoutWidget::notificationExists(const QString &identifier) const { return (m_ui->notificationLayoutWidget->findChild(identifier, Qt::FindDirectChildrenOnly) != nullptr); } bool LtsBaseLayoutWidget::removeMenuAction(const QString &byIdentifier) { for (auto it = m_mapButtons.begin(); it != m_mapButtons.end(); ++it) { if (it.value().identifier == byIdentifier) return removeMenuAction(it.key()); } return false; } bool LtsBaseLayoutWidget::removeMenuAction(const PluginData &plData) { for (auto it = m_mapButtons.begin(); it != m_mapButtons.end(); ++it) { if (it.value().identifier == plData.identifier) return removeMenuAction(it.key()); } return false; } bool LtsBaseLayoutWidget::removeMenuAction(LtsDragIcon *icon) { auto it = m_mapButtons.find(icon); if (it == m_mapButtons.end()) return false; const QString menuGroup = it->menuGroup; const ExercisePart ep = it->exercisePart; m_mapButtons.erase(it); icon->setParent(nullptr); icon->deleteLater(); checkMenuGroup(menuGroup, ep); return true; } void LtsBaseLayoutWidget::executeAction(const QString &actionIdentifier) { const QList plDatas(m_mapButtons.values()); auto it = std::find_if(plDatas.constBegin(), plDatas.constEnd(), [actionIdentifier](const PluginData &plData) { return (plData.identifier == actionIdentifier); }); if (it == plDatas.constEnd()) return; executePluginData(*it); } void LtsBaseLayoutWidget::executePluginData(const PluginData &plData) { const QString &identifier = plData.identifier; const QString &menuGroup = plData.menuGroup; LtsTabWidget *tab = getTabFromLayoutArea(plData.layoutArea); if (!tab->focusTab(menuGroup, identifier)) { if (plData.createWidgetFunc) { LtsDialog *w = plData.createWidgetFunc(this); if (w) { addWidget(w, menuGroup, identifier, plData.layoutArea, plData.closable); } else { } } else { if (plData.directFunc) plData.directFunc(plData); } } else { } } void LtsBaseLayoutWidget::onMenuEntryClicked() { LtsDragIcon *btn = qobject_cast(sender()); if (!btn) return; if (!m_mapButtons.contains(btn)) return; executePluginData(m_mapButtons.value(btn)); } void LtsBaseLayoutWidget::resetLayoutVisibility() { for (auto i = m_oldLayoutVisibilityStates.cbegin(); i != m_oldLayoutVisibilityStates.cend(); ++i) { const auto &tabPtr = i.key(); if (tabPtr) tabPtr->setVisible(i.value()); } m_oldLayoutVisibilityStates.clear(); } void LtsBaseLayoutWidget::hideVisibleLayouts() { if (!m_oldLayoutVisibilityStates.isEmpty()) { qWarning() << "LtsBaseLayoutWidget::hideVisibleLayouts: old states available - ignoring"; return; } LtsWidgets::LtsTabWidget *infoTab = getTabFromLayoutArea(LtsWidgets::LayoutArea::eInfoTab); LtsWidgets::LtsTabWidget *specialTab = getTabFromLayoutArea(LtsWidgets::LayoutArea::eSpecialTab); LtsWidgets::LtsTabWidget *dialogTab = getTabFromLayoutArea(LtsWidgets::LayoutArea::eDialogTab); m_oldLayoutVisibilityStates.insert(infoTab, infoTab->isVisible()); m_oldLayoutVisibilityStates.insert(specialTab, specialTab->isVisible()); m_oldLayoutVisibilityStates.insert(dialogTab, dialogTab->isVisible()); if (infoTab->isVisible()) infoTab->setVisible(false); if (specialTab->isVisible()) specialTab->setVisible(false); if (dialogTab->isVisible()) dialogTab->setVisible(false); } void LtsBaseLayoutWidget::setTopBarVisible(bool visible) { m_ui->topLayoutWidget->setVisible(visible); } bool LtsBaseLayoutWidget::isTopBarVisible() const { return m_ui->topLayoutWidget->isVisible(); } bool LtsBaseLayoutWidget::isMenuCollapsed() const { return m_menuCollapsed; } void LtsBaseLayoutWidget::setMenuVisible(bool visible) { m_ui->rightSplitter->setVisible(visible); } bool LtsBaseLayoutWidget::isMenuVisible() const { return m_ui->rightSplitter->isVisible(); } void LtsBaseLayoutWidget::collapseMenu(bool collapse) { m_menuCollapsed = collapse; if (collapse) { m_ui->masterSplitter->setSizes(m_menuSplitterSizes); } else { m_menuSplitterSizes = m_ui->masterSplitter->sizes(); m_ui->masterSplitter->setSizes(QList() << 1 << 0 ); } } void LtsBaseLayoutWidget::onReShowAnimated() { QPropertyAnimation *animation = new QPropertyAnimation(m_ui->mainSplitter, "sizes", this); animation->setDuration(500); QList start = m_mainSplitterSizes; start[getIndexOfTab(getTabFromLayoutArea(LayoutArea::eDialogTab))] = 0; QList end = m_mainSplitterSizes; animation->setStartValue(QVariant::fromValue(start)); animation->setEndValue(QVariant::fromValue(end)); connect(animation, &QPropertyAnimation::finished, this, [this]() { m_currentAnimation = nullptr; }); m_ui->detailWidget->show(); animation->start(QAbstractAnimation::DeleteWhenStopped); m_isHidden = false; delete m_currentAnimation; m_currentAnimation = animation; } void LtsBaseLayoutWidget::onHideAnimated() { if (m_currentAnimation) { delete m_currentAnimation; m_currentAnimation = nullptr; } QPropertyAnimation *animation = new QPropertyAnimation(m_ui->mainSplitter, "sizes", this); animation->setDuration(500); m_mainSplitterSizes = m_ui->mainSplitter->sizes(); QList start = m_ui->mainSplitter->sizes(); QList end = start; end[getIndexOfTab(getTabFromLayoutArea(LayoutArea::eDialogTab))] = 1; animation->setStartValue(QVariant::fromValue(start)); animation->setEndValue(QVariant::fromValue(end)); connect(animation, &QPropertyAnimation::finished, this, &LtsBaseLayoutWidget::hideWidgets); connect(animation, &QPropertyAnimation::finished, this, [this]() { m_currentAnimation = nullptr; }); animation->start(QAbstractAnimation::DeleteWhenStopped); m_isHidden = true; m_currentAnimation = animation; } void LtsBaseLayoutWidget::retranslate() { emit signalRetranslateActions(); setExerciseData(m_exerciseData); m_ui->retranslateUi(this); } void LtsBaseLayoutWidget::changeEvent(QEvent *e) { QWidget::changeEvent(e); if (e->type() == QEvent::LanguageChange) retranslate(); } int LtsBaseLayoutWidget::getIndexOfTab(LtsTabWidget *tab) { int result = 0; result = m_ui->masterSplitter->indexOf(tab); if (result > -1) return result; result = m_ui->mainSplitter->indexOf(tab); if (result > -1) return result; result = m_ui->rightSplitter->indexOf(tab); if (result > -1) return result; qWarning() << "LtsBaseLayoutWidget::getIndexOfTab: tab not found in any splitter.."; return result; } LtsToolBox* LtsBaseLayoutWidget::getToolBox(const ExercisePart &exercisePart) const { switch (exercisePart) { case ExercisePart::eAfterAction: return m_ui->naviActionsAfterAction; case ExercisePart::eExecution: return m_ui->naviActionsExecution; case ExercisePart::ePlanning: return m_ui->naviActionsPlanning; case ExercisePart::eSpecial: return m_ui->naviActionsSpecial; } Q_ASSERT(false); return nullptr; } QPushButton* LtsBaseLayoutWidget::getExercisePartButton(const ExercisePart &exercisePart) const { switch (exercisePart) { case ExercisePart::eAfterAction: return m_ui->pbAfterAction; case ExercisePart::eExecution: return m_ui->pbExecution; case ExercisePart::ePlanning: return m_ui->pbPlanning; case ExercisePart::eSpecial: return m_ui->pbSpecial; } Q_ASSERT(false); return nullptr; } void LtsBaseLayoutWidget::checkMenuGroup(const QString &menuGroup, const ExercisePart &exercisePart) { QWidget *tmpW = getToolBox(exercisePart)->findChild(menuGroup); if (!tmpW) return; #ifdef NEVER_PRINT_DEBUG for (int i = 0; i < tmpW->children().size(); i++) { QObject * whatEver = tmpW->children().at( i ); const QString & name = whatEver->objectName(); qCritical() << "MenuGroup child " << i << " : " << name; } #endif if (tmpW->children().size() <= 1) delete tmpW; checkExercisePartButtonVisibility(); } void LtsBaseLayoutWidget::checkExercisePartButtonVisibility() { if (nullptr == m_bg) { for (int ep = (int)ExercisePart::ePlanning; ep <= (int)ExercisePart::eSpecial; ++ep) { getExercisePartButton(static_cast(ep))->setVisible(false); } return; } int visibleButtons = 0; ExercisePart lastVisibleButton = ExercisePart::ePlanning; for (int ep = (int) ExercisePart::ePlanning; ep <= (int) ExercisePart::eSpecial; ++ep) { bool visible = getToolBox((ExercisePart) ep)->children().count() > 1; getExercisePartButton((ExercisePart) ep)->setVisible(visible); if (visible) { ++visibleButtons; lastVisibleButton = (ExercisePart) ep; } } if (visibleButtons == 0) lastVisibleButton = ExercisePart::eSpecial; getExercisePartButton(lastVisibleButton)->setChecked(true); getExercisePartButton(lastVisibleButton)->setVisible(visibleButtons > 1); } bool LtsBaseLayoutWidget::isWidgetsHidden() const { return m_ui->detailWidget->isVisible(); } void LtsBaseLayoutWidget::showWidgets() { m_ui->detailWidget->show(); } void LtsBaseLayoutWidget::hideWidgets() { m_ui->detailWidget->hide(); } LtsDragIcon *LtsBaseLayoutWidget::createButton(const PluginData &plData) { LtsDragIcon *tmpBtn = new LtsDragIcon(nullptr); tmpBtn->setObjectName(plData.identifier); tmpBtn->setButtonStyle(LtsWidgets::ButtonStyle::eTextNextToIcon); tmpBtn->setIcon(plData.menuIcon); tmpBtn->setContext(plData.menuGroup); tmpBtn->setText(plData.menuText); if (!plData.tooltip.isEmpty()) tmpBtn->setToolTip(plData.tooltip); tmpBtn->setDropHandlerKey(plData.dropHandlerKey); tmpBtn->setIdentifier(plData.identifier); connect(tmpBtn, &QWidget::destroyed, this, []() { qDebug() << "LtsDragIcon was destroyed"; }); connect(tmpBtn, &LtsDragIcon::clicked, this, &LtsBaseLayoutWidget::onMenuEntryClicked); return tmpBtn; } LtsToolBarArea * LtsBaseLayoutWidget::getToolbar() const { return m_ui->toolBar; } QWidget *LtsBaseLayoutWidget::getMenu() const { return m_ui->naviWidget; } LtsTabWidget *LtsBaseLayoutWidget::getTabFromLayoutArea(LayoutArea area) const { switch (area) { case LayoutArea::eDialogTab: return m_ui->detailWidget; case LayoutArea::eInfoTab: return m_ui->infoWidget; case LayoutArea::eSpecialTab: return m_ui->specialWidget; case LayoutArea::eMainTab: return m_ui->mainWidget; case LayoutArea::eUnknown: return m_ui->detailWidget; } return nullptr; } void LtsBaseLayoutWidget::showNextQueuedMessage() { if (m_messageQueue.isEmpty()) { return; } const Message m = m_messageQueue.takeLast(); showMessage(m.title, m.text, m.type, m.clickedLinkCallback, m.closeOnLinkClicked, m.identifier); } void LtsBaseLayoutWidget::removeQueuedMessage(const QString &messageIdentifier) { if (messageIdentifier.isEmpty()) { return; } m_messageQueue.erase(std::remove_if(m_messageQueue.begin(), m_messageQueue.end(), [messageIdentifier](const Message &m) { return (m.identifier == messageIdentifier); }), m_messageQueue.end()); if (!m_currentMessage.isEmpty()) { if (m_currentMessage.first().identifier == messageIdentifier) { m_currentMessage.clear(); m_notiBox->hide(); showNextQueuedMessage(); } } } void LtsBaseLayoutWidget::showMessage(const QString &title, const QString &text, LtsNotificationBox::MessageType type, const std::function &clickedLinkCallback, bool closeOnLinkClicked, const QString &identifier) { if (m_notiBox == nullptr) { m_notiBox = new LtsNotificationBox; connect(m_notiBox, &LtsNotificationBox::signalLinkClicked, this, [this, closeOnLinkClicked, clickedLinkCallback](const QString &link) { auto *event = new LtsLinkEvent(QUrl(link), this); event->setAccepted(false); QApplication::postEvent(qApp, event); if (clickedLinkCallback) clickedLinkCallback(link); if (closeOnLinkClicked) { m_notiBox->hide(); m_currentMessage.clear(); showNextQueuedMessage(); } }); connect(m_notiBox, &QObject::destroyed, this, [this]() { if (qobject_cast(sender()) == m_notiBox) m_notiBox = nullptr; }); connect(m_notiBox, &LtsNotificationBox::signalClose, this, [this]() { m_notiBox->hide(); m_currentMessage.clear(); showNextQueuedMessage(); }); connect(m_notiBox, &LtsNotificationBox::signalAck, this, [this]() { auto *event = new LtsLinkEvent(QUrl(QStringLiteral("lts://NotificationAck/%1").arg(m_currentMessage.first().identifier)), this); event->setAccepted(false); QApplication::postEvent(qApp, event); m_notiBox->hide(); m_currentMessage.clear(); showNextQueuedMessage(); }); m_notiBox->setParent(this); m_notiBox->setGeometry(0, 0, m_notiBox->width(), m_notiBox->height()); } m_messageQueue.erase(std::remove_if(m_messageQueue.begin(), m_messageQueue.end(), [identifier](const Message &m) { return (!identifier.isEmpty() && m.identifier == identifier); }), m_messageQueue.end()); if (!m_currentMessage.isEmpty()) { const auto m = m_currentMessage.takeFirst(); if (identifier.isEmpty() || m.identifier != identifier) { m_messageQueue += m; } } m_currentMessage += Message({ title, text, type, clickedLinkCallback, closeOnLinkClicked, identifier }); m_notiBox->message(title, text, type); auto *animation = new QPropertyAnimation(m_notiBox, "geometry"); connect(animation, &QPropertyAnimation::finished, animation, &QObject::deleteLater); animation->setDuration(700); animation->setStartValue(QRect(width() + 10, height() + 10, m_notiBox->width(), m_notiBox->height())); animation->setEndValue(QRect(width() - m_notiBox->width() - 15, height() - m_notiBox->height() - 15, m_notiBox->width(), m_notiBox->height())); animation->setEasingCurve(QEasingCurve::OutElastic); animation->start(QAbstractAnimation::DeleteWhenStopped); } bool LtsBaseLayoutWidget::messageIdentifierExists(const QString &identifier) const { if (identifier.isEmpty()) { return false; } if (!m_currentMessage.isEmpty() && m_currentMessage.first().identifier == identifier) { return true; } for (const Message &m : qAsConst(m_messageQueue)) { if (m.identifier == identifier) { return true; } } return false; } }