- LtsWidgets: Fixed Qt6 API compatibility issues - QWheelEvent::delta() → angleDelta().y() - QStyleOption::init() → initFrom() - QComboBox activated signal signature change - QTextCodec removal (UTF-8 default in Qt6) - Missing widget includes added - LtsWebSocket: Fixed m_logger reference initialization - Added NGLLoggerBootstrap includes - Proper initialization in constructor initializer lists - CMake: Added BUILD_LTSWEBSOCKET option for temporary exclusion - Docker: RTI Connext permanent installation script added - ci/install-rti-in-docker.sh for persistent RTI setup - Removes need for volume mounting RTI into container - BUILD options: FilterManagement, RTI, Codification, Grantlee, LtsWebSocket can be disabled for partial builds during migration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1631 lines
50 KiB
C++
1631 lines
50 KiB
C++
|
|
|
|
#include "lts_base_layout_widget.h"
|
|
|
|
#include "lts_dialog.h"
|
|
#include "lts_dialog_helper.h"
|
|
#include "lts_drag_icon.h"
|
|
#include "lts_events.h"
|
|
#include "lts_grid_layout.h"
|
|
#include "lts_message_dialog.h"
|
|
#include "lts_operator_menu.h"
|
|
#include "lts_splash.h"
|
|
#include "lts_tool_bar_area.h"
|
|
#include "ui_lts_base_layout.h"
|
|
|
|
#include <Lts/Common/ProjectConfig/project_defines.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <LtsUtilsSettings/settings.h>
|
|
#include <QAbstractItemView>
|
|
#include <QButtonGroup>
|
|
#include <QClipboard>
|
|
#include <QCloseEvent>
|
|
#include <QDebug>
|
|
#include <QImage>
|
|
#include <QInputDialog>
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
#include <QMetaMethod>
|
|
#include <QPainter>
|
|
#include <QPixmap>
|
|
#include <QPropertyAnimation>
|
|
#include <QPushButton>
|
|
#include <QScrollArea>
|
|
#include <QScroller>
|
|
#include <QSvgRenderer>
|
|
#include <QTimer>
|
|
#include <QToolButton>
|
|
#include <ngltools/ngltools_dtg.h>
|
|
#include <utility>
|
|
|
|
namespace LtsWidgets
|
|
{
|
|
|
|
static QVariant splitterInterpolator(const QList<int>& start, const QList<int>& end, qreal progress)
|
|
{
|
|
QList<int> 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<QList<int>>(splitterInterpolator);
|
|
qRegisterMetaType<LtsWidgets::LayoutArea>("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, &QButtonGroup::idClicked, 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 <a href='lts://ParticipantInfo/19'>something</a><br "
|
|
"/>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 <a href='lts://ParticipantInfo/19'>something</a><br "
|
|
"/>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 <a href='lts://ParticipantInfo/19'>something</a><br "
|
|
"/>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 <a href='lts://ParticipantInfo/19'>something</a><br "
|
|
"/>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<QWidget*> scrollWidgets = findChildren<QWidget*>();
|
|
|
|
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<QScrollArea*>(widget);
|
|
if (sca)
|
|
{
|
|
QScroller::grabGesture(sca->viewport(), QScroller::LeftMouseButtonGesture);
|
|
return;
|
|
}
|
|
|
|
QAbstractItemView* aiv = qobject_cast<QAbstractItemView*>(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<LtsDragIcon*> 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<int, QString>& actions)
|
|
{
|
|
for (auto it = actions.cbegin(); it != actions.cend(); ++it)
|
|
m_ui->toolBar->setFunctionKey(it.key(), it.value());
|
|
}
|
|
|
|
QMap<int, QString> LtsBaseLayoutWidget::functionKeys() const
|
|
{
|
|
if (m_ui == nullptr)
|
|
return QMap<int, QString>();
|
|
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: <b>%1</b>").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 : std::as_const(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<Button, QString> buttonTexts;
|
|
buttonTexts.insert(Button::Yes, tr("Discard All"));
|
|
const auto ret = LtsMessageDialog::showMessage(
|
|
this,
|
|
tr("There are dialogs with unsaved changes.<br>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<LtsTabWidget*>(w);
|
|
|
|
if (secondTab != nullptr)
|
|
return isDialogFocused(dialog, secondTab);
|
|
|
|
const LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(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<int>& sizes = m_ui->mainSplitter->sizes();
|
|
int requestedTabHeight = tab->sizeHint().height();
|
|
int mainHeight = sizes[0] + sizes[1] - requestedTabHeight;
|
|
|
|
m_ui->mainSplitter->setSizes(QList<int>() << 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<LtsDialogHelper*>(w);
|
|
|
|
if (helper == nullptr)
|
|
return nullptr;
|
|
|
|
LtsDialog* dialog = qobject_cast<LtsDialog*>(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<LtsWidgets::LtsToolBox*>(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<QWidget*>(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<LtsGridLayout*>(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<QSpacerItem*>(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<QToolButton*>(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<PluginData> 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<LtsDragIcon*>(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<int>() << 1 << 0);
|
|
}
|
|
}
|
|
|
|
void LtsBaseLayoutWidget::onReShowAnimated()
|
|
{
|
|
QPropertyAnimation* animation = new QPropertyAnimation(m_ui->mainSplitter, "sizes", this);
|
|
animation->setDuration(500);
|
|
|
|
QList<int> start = m_mainSplitterSizes;
|
|
start[getIndexOfTab(getTabFromLayoutArea(LayoutArea::eDialogTab))] = 0;
|
|
|
|
QList<int> 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<int> start = m_ui->mainSplitter->sizes();
|
|
|
|
QList<int> 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<QWidget*>(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<ExercisePart>(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<void(const QString& link)>& 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<LtsNotificationBox*>(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 : std::as_const(m_messageQueue))
|
|
{
|
|
if (m.identifier == identifier)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} // namespace LtsWidgets
|