1839 lines
54 KiB
C++
Executable File
1839 lines
54 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Base Layout Widget with all Areas (Info, Main, Detail, Menu)
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#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 <LtsSession/lts_session_data.h>
|
|
#include <LtsUtilsSettings/settings.h>
|
|
#include <Common/ProjectConfig/project_defines.h>
|
|
#include <ngltools/ngltools_dtg.h>
|
|
|
|
#include <QAbstractItemView>
|
|
#include <QButtonGroup>
|
|
#include <QClipboard>
|
|
#include <QCloseEvent>
|
|
#include <QDebug>
|
|
#include <QImage>
|
|
#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 <QPropertyAnimation>
|
|
#include <QInputDialog>
|
|
|
|
|
|
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) /* First ever Session must be the Administrative Global Partition */
|
|
, 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) // at least 1 screen, always
|
|
, m_menuCollapsed(true)
|
|
, m_notiBox(nullptr)
|
|
{
|
|
m_ui->setupUi(this);
|
|
|
|
#ifndef LTS_DEBUG
|
|
m_ui->pbDebug->hide();
|
|
#endif
|
|
|
|
addDebugMenu();
|
|
|
|
|
|
{
|
|
// Current Time label's context menu
|
|
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)); });
|
|
}
|
|
|
|
|
|
{
|
|
// Exercise Time label's context menu
|
|
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); // only the detail tab widget has sub tabs !!
|
|
|
|
//Register
|
|
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();
|
|
|
|
// master splitter stretch
|
|
m_ui->masterSplitter->setStretchFactor(m_ui->masterSplitter->indexOf(m_ui->infoWidget), 0);
|
|
m_ui->masterSplitter->setStretchFactor(m_ui->masterSplitter->indexOf(m_ui->mainSplitter), 20);
|
|
|
|
// main splitter stretch
|
|
m_ui->mainSplitter->setStretchFactor(m_ui->mainSplitter->indexOf(m_ui->mainWidget), 20);
|
|
m_ui->mainSplitter->setStretchFactor(m_ui->mainSplitter->indexOf(m_ui->detailWidget), 0);
|
|
|
|
// right splitter stretch
|
|
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->lbExerciseTime->hide();
|
|
//m_ui->lbExercisePhase->hide();
|
|
//m_ui->lbExerciseStatus->hide();
|
|
//m_ui->lbExerciseName->hide();
|
|
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); // initially set labels to invalid values
|
|
|
|
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<int>::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()
|
|
{
|
|
// memleak .. x)
|
|
|
|
// qCritical() << "~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;
|
|
// do not delete m_progressDialogHelper because it is parented with this object (??!!)
|
|
}
|
|
|
|
|
|
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 /* INTENDED! */, 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);
|
|
// RDE SPLITTER LEFT
|
|
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);
|
|
}
|
|
|
|
{
|
|
// PROJECT LOGO
|
|
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; // copy
|
|
|
|
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()
|
|
{
|
|
// nothing...
|
|
|
|
// QMap<int,QString> fKeys;
|
|
// for(auto it = variantMap.cbegin(); it != variantMap.cend(); ++it)
|
|
// fKeys[it.key().toInt()] = it.value().toString();
|
|
|
|
// setToolBarActions(settings);
|
|
// setFunctionKeys(fKeys);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
// public
|
|
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 : qAsConst(m_mapButtons))
|
|
{
|
|
if (pd.identifier == QStringLiteral("_OpmShowOperatorSettings"))
|
|
{
|
|
hasOperatorSettings = true;
|
|
break;
|
|
}
|
|
}
|
|
operatorMenu->setOperatorSettingsButton(hasOperatorSettings); // available for Replay
|
|
|
|
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; // no unsaved changes
|
|
}
|
|
|
|
|
|
//LtsUtils::Promise *notifyUnsavedChangesAsync()
|
|
//{
|
|
// if (haveUnsavedChanges())
|
|
// {
|
|
// LtsMessageDialog::showMessage(this, tr("There are dialogs with unsaved changes.<br>Please save or discard their changes before closing."), tr("Unsaved changes"));
|
|
// 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() // TODO: rm, then signal on signal
|
|
{
|
|
emit signalLogout();
|
|
}
|
|
|
|
|
|
bool LtsBaseLayoutWidget::slotClose()
|
|
{
|
|
if (!notifyUnsavedChanges())
|
|
return false;
|
|
|
|
// // no unsaved changes? delete everything
|
|
// getTabFromLayoutArea(LayoutArea::eDialogTab)->clearAll();
|
|
// getTabFromLayoutArea(LayoutArea::eInfoTab)->clearAll();
|
|
// getTabFromLayoutArea(LayoutArea::eMainTab)->clearAll();
|
|
// getTabFromLayoutArea(LayoutArea::eSpecialTab)->clearAll();
|
|
|
|
// // save toolbar entries
|
|
// auto toolBarItems = m_ui->toolBar->getMenuEntries();
|
|
// Q_FOREACH(const QString &entry, toolBarItems)
|
|
// qCritical() << entry;
|
|
|
|
// clearMenuActions(); // delete all menu entries
|
|
|
|
// //delete m_ui; // now delete the ui, incl. widgets from any plugin, first !
|
|
// //m_ui = nullptr; // TODO: remove this !!
|
|
|
|
// if (!m_progressDialogHelper)
|
|
// m_progressDialogHelper = new LtsProgressDialogHelper(this);
|
|
|
|
// m_progressDialogHelper->slotShowWaitForReplyWindow(); // this will run, until the LtsSession closes the BaseLayout - this will also delete the pdh, as it's parented
|
|
|
|
hide();
|
|
|
|
emit signalClose(); //CloseRequest(m_domainId, m_partitionType, m_partitionId);
|
|
return true;
|
|
}
|
|
|
|
|
|
//void LtsBaseLayoutWidget::removeNotification(LtsNotificationIcon *noti)
|
|
//{
|
|
// ...
|
|
//}
|
|
|
|
|
|
void LtsBaseLayoutWidget::closeEvent(QCloseEvent *event)
|
|
{
|
|
event->ignore(); // do not close this BaseLayout, the Session will do this on signalCloseRequest !
|
|
|
|
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(); // bye bye existingWidget, may be deleteLater already has been called before
|
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling deleteLater multiple times is discuraged..
|
|
}
|
|
else
|
|
{
|
|
qWarning() << __FUNCTION__ << " : Remove existing widget from TabWidget failed.";
|
|
}
|
|
}
|
|
}
|
|
return addWidget(dialog, menuGroup, identifier, area, setClosable, focusNewTab);
|
|
} // bool LtsBaseLayoutWidget::addOrReplaceWidget(LtsDialog *dialog, const QString &menuGroup, const QString &identifier, LayoutArea area, bool setClosable, bool 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 /*LtsDialogHelper*/ *helper = dialog->getHelper();
|
|
if (!helper) // LtsDialog is in compatibility mode ! bcuz it's old
|
|
{
|
|
helper = dialog; // pretend that the helper exists
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose); // dialog must delete itself, as there is no Dialog Helper
|
|
}
|
|
|
|
if (!identifier.isEmpty()) // do not check for existing tabs, if ident is empty
|
|
{
|
|
QWidget *existingWidget = tab->getWidget(menuGroup, identifier);
|
|
if (existingWidget != nullptr) // check here also if widget is already there (as widgets can call addWidget when e.g. editing something)
|
|
{
|
|
helper->deleteLater(); // delete existing widget's helper!
|
|
|
|
if (focusNewTab) // "foxus existing tab"
|
|
tab->focusTab(menuGroup, identifier);
|
|
|
|
// animation tab is hidding?
|
|
int indexOfSplitter = getIndexOfTab(tab);
|
|
// animate if splitter is collapsed
|
|
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; // already exists, do nothing, as focus is done
|
|
}
|
|
}
|
|
|
|
dialog->setBaseLayoutWidget(this);
|
|
|
|
connect(dialog, &LtsDialog::startMainSelect,
|
|
this, &LtsBaseLayoutWidget::onHideAnimated);
|
|
connect(dialog, &LtsDialog::endMainSelect,
|
|
this, &LtsBaseLayoutWidget::onReShowAnimated);
|
|
|
|
// Lock :
|
|
emit signalStapleTopicLockHandler(dialog); // must be called before addTab, as addTab calls retranslate, which also might try a lock so the connection must be already made - this slot is called sync/directly - sequential
|
|
dialog->triggerTopicLock();
|
|
// : Lock
|
|
|
|
|
|
|
|
tab->addTab(menuGroup, identifier, helper, setClosable, focusNewTab); // tell the MAIN tab that he should add a new MAIN tab, when there is none, and to add a SUB tab on the MAIN tab, with the given widget
|
|
// animate if splitter is collapsed
|
|
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);
|
|
}
|
|
}
|
|
//#define ADJUST_SPLITTER_SIZES_DIALOGTAB
|
|
#ifdef ADJUST_SPLITTER_SIZES_DIALOGTAB
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* In layout area DialogTab dialogs are created and destroyed after use. The requested size of the tab widget changes every time.
|
|
* But the superordinate splitter doesn't adjust its geometry automatically. Do it here manually to get the PlanEditor working now.
|
|
*
|
|
* JT 2017/02/10
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
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 // ADJUST_SPLITTER_SIZES_DIALOGTAB
|
|
|
|
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()
|
|
{
|
|
// menu
|
|
while (m_ui->naviActionsPlanning->count()) // remove all items
|
|
m_ui->naviActionsPlanning->removeItem(0);
|
|
while (m_ui->naviActionsExecution->count()) // remove all items
|
|
m_ui->naviActionsExecution->removeItem(0);
|
|
while (m_ui->naviActionsAfterAction->count()) // remove all items
|
|
m_ui->naviActionsAfterAction->removeItem(0);
|
|
while (m_ui->naviActionsSpecial->count()) // remove all items
|
|
m_ui->naviActionsSpecial->removeItem(0);
|
|
|
|
checkExercisePartButtonVisibility();
|
|
|
|
// map buttons
|
|
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) // init and show every action, that goes must be created instantly
|
|
{
|
|
case CreateInstantType::CreateInstantAndAddAction:
|
|
{
|
|
executeCreateInstantFunctions(plData);
|
|
break;
|
|
}
|
|
|
|
case CreateInstantType::CreateInstantAndDiscardAction:
|
|
{
|
|
executeCreateInstantFunctions(plData);
|
|
return nullptr;
|
|
}
|
|
|
|
default: // case CreateInstantType::DontCreateInstant:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (plData.createInstant == CreateInstantType::CreateInstantAndDiscardAction) // discarded actions are not shown, ignore them
|
|
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) // refetch
|
|
{
|
|
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;
|
|
// rename group
|
|
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() /* the group entry */);
|
|
if (groupWidgetIndex >= 0)
|
|
{
|
|
tb->setItemText(groupWidgetIndex, plData.menuGroup);
|
|
groupFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!groupFound)
|
|
{
|
|
qWarning() << "group widget not found";
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
//qWarning() << "Could not find and replace the menu item" << plData.identifier << " - creating it!";
|
|
}
|
|
else
|
|
{
|
|
return nullptr; // only replace texts on re-adding actions
|
|
}
|
|
}
|
|
|
|
LtsWidgets::LtsToolBox *tb = getToolBox(m_bg ? plData.exercisePart : ExercisePart::eSpecial);
|
|
|
|
// otherwise create an action and add it to the menu
|
|
QWidget *tmpW = tb->findChild<QWidget *>(plData.menuGroup);
|
|
if (!tmpW)
|
|
{
|
|
// no separator on first place
|
|
if (plData.createWidgetFunc == nullptr && plData.directFunc == nullptr)
|
|
return nullptr;
|
|
|
|
// no tab for this menu group available -> create new one
|
|
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);
|
|
}
|
|
|
|
// layout should now already be here ...
|
|
QLayout *widgetLayout = tmpW->layout();
|
|
LtsGridLayout *ltsGridLayout = qobject_cast<LtsGridLayout *>(widgetLayout);
|
|
if (!ltsGridLayout)
|
|
{
|
|
//ERROR_LOG(m_logger) << "temp widget has no layout! cannot add action to menu!";
|
|
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;
|
|
}
|
|
|
|
// remove old spacer (a new one is created at the end)
|
|
if (widgetLayout->count() > 0)
|
|
{
|
|
QSpacerItem *spacer = dynamic_cast<QSpacerItem *>(widgetLayout->itemAt(widgetLayout->count() - 1));
|
|
if (spacer)
|
|
{
|
|
ltsGridLayout->removeItem(spacer);
|
|
delete spacer;
|
|
}
|
|
}
|
|
|
|
// create entry
|
|
LtsDragIcon *dragIcon = nullptr;
|
|
if (plData.createWidgetFunc == nullptr && plData.directFunc == nullptr)
|
|
{
|
|
QFrame *line = new QFrame(tmpW);
|
|
line->setLineWidth(2);
|
|
line->setFrameStyle(QFrame::HLine);
|
|
// add to layout
|
|
ltsGridLayout->add_widget(line);
|
|
}
|
|
else
|
|
{
|
|
if (isFirstRun || !found)
|
|
{
|
|
dragIcon = createButton(plData);
|
|
// add to layout
|
|
ltsGridLayout->add_widget(dragIcon);
|
|
m_mapButtons.insert(dragIcon, plData); // FIXME: rm destroyed buttons !!
|
|
|
|
auto it = std::find_if(m_notFoundYet.begin(), m_notFoundYet.end(), [plData](const QString &s)
|
|
{
|
|
return s == plData.identifier;
|
|
});
|
|
|
|
if (it != m_notFoundYet.end()) // found
|
|
{
|
|
m_ui->toolBar->addMenuEntry(dragIcon);
|
|
m_notFoundYet.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
checkExercisePartButtonVisibility();
|
|
// add spacer at end
|
|
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)) // focus widget - is there a widget to focus? no? add a new one! yes? focus and do nothing..
|
|
{
|
|
//qWarning() << "LtsBaseLayoutWidget::onMenuEntryClicked: cannot focus - creating new widget!";
|
|
|
|
if (plData.createWidgetFunc)
|
|
{
|
|
LtsDialog *w = plData.createWidgetFunc(this);
|
|
if (w)
|
|
{
|
|
//qWarning() << "LtsBaseLayoutWidget::onMenuEntryClicked: adding widget!";
|
|
addWidget(w, menuGroup, identifier, plData.layoutArea, plData.closable);
|
|
}
|
|
else
|
|
{
|
|
//qWarning() << "LtsBaseLayoutWidget::onMenuEntryClicked: no widget to add..";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (plData.directFunc)
|
|
plData.directFunc(plData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//qWarning() << "LtsBaseLayoutWidget::onMenuEntryClicked: focused!";
|
|
}
|
|
}
|
|
|
|
//SLOTS
|
|
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());
|
|
|
|
// hiding an invisible tab makes the splitter reduce the tab's size to 0 - only hide if visible
|
|
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 /* main, info, etc. */ << 0 /* menu */);
|
|
}
|
|
}
|
|
|
|
|
|
void LtsBaseLayoutWidget::onReShowAnimated()
|
|
{
|
|
QPropertyAnimation *animation = new QPropertyAnimation(m_ui->mainSplitter, "sizes", this);
|
|
animation->setDuration(500);
|
|
//Save Old Sizes
|
|
|
|
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);
|
|
//Save Old Sizes
|
|
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);
|
|
// etc.
|
|
}
|
|
|
|
|
|
void LtsBaseLayoutWidget::changeEvent(QEvent *e)
|
|
{
|
|
QWidget::changeEvent(e);
|
|
if (e->type() == QEvent::LanguageChange)
|
|
retranslate();
|
|
}
|
|
|
|
|
|
int LtsBaseLayoutWidget::getIndexOfTab(LtsTabWidget *tab)
|
|
{
|
|
int result = 0; // emergency value
|
|
|
|
result = m_ui->masterSplitter->indexOf(tab);
|
|
|
|
if (result > -1) // found?
|
|
return result;
|
|
|
|
|
|
// not found?
|
|
result = m_ui->mainSplitter->indexOf(tab);
|
|
|
|
if (result > -1) // now found?
|
|
return result;
|
|
|
|
|
|
// still not found?
|
|
result = m_ui->rightSplitter->indexOf(tab);
|
|
|
|
if (result > -1) // and now?
|
|
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; // should not happen
|
|
|
|
#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
|
|
|
|
// Something is wrong here! The printing shows an additional object besides the
|
|
// LtsDragIcons of the menuGroup.
|
|
// As workaround chnage condition
|
|
// if (tmpW->children().size() == 0) to
|
|
if (tmpW->children().size() <= 1) // JT 2016/08/03
|
|
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)
|
|
{
|
|
// TODO: really nullptr?
|
|
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: // better than returning a 0ptr
|
|
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()) // empty / unset identifiers can't be removed
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_messageQueue.erase(std::remove_if(m_messageQueue.begin(), m_messageQueue.end(), [messageIdentifier](const Message &m) // remove all queued messages with the same identifier
|
|
{
|
|
return (m.identifier == messageIdentifier);
|
|
}), m_messageQueue.end());
|
|
|
|
if (!m_currentMessage.isEmpty())
|
|
{
|
|
if (m_currentMessage.first().identifier == messageIdentifier)
|
|
{
|
|
// this is the current active message - hide it and call show next queued message (if any)
|
|
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)
|
|
{
|
|
// qWarning() << "link" << link;
|
|
|
|
auto *event = new LtsLinkEvent(QUrl(link), this);
|
|
event->setAccepted(false);
|
|
QApplication::postEvent(qApp, event); // receive link events by overriding eventFilter of your *parented* QObject class
|
|
|
|
if (clickedLinkCallback)
|
|
clickedLinkCallback(link);
|
|
|
|
if (closeOnLinkClicked)
|
|
{
|
|
m_notiBox->hide();
|
|
m_currentMessage.clear();
|
|
showNextQueuedMessage(); // show next message (if any) after closing current message
|
|
}
|
|
});
|
|
|
|
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(); // show next message (if any) after closing current message
|
|
});
|
|
|
|
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); // send link event to tell NotificationManagement to ack this notification
|
|
|
|
m_notiBox->hide();
|
|
m_currentMessage.clear();
|
|
showNextQueuedMessage(); // show next message (if any) after closing current message
|
|
});
|
|
|
|
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) // remove all queued messages with the same identifier (if not empty)
|
|
{
|
|
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) // replace current message with new message if identifier is same (and not empty)
|
|
{
|
|
m_messageQueue += m;
|
|
}
|
|
}
|
|
|
|
m_currentMessage += Message({ title, text, type, clickedLinkCallback, closeOnLinkClicked, identifier });
|
|
|
|
m_notiBox->message(title, text, type);
|
|
|
|
|
|
// TODO: ahtc set new x on resize
|
|
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()) // empty / unset identifiers never exist
|
|
{
|
|
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;
|
|
}
|
|
|
|
} // namespace LtsWidgets
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|