Files
qt5-legatus-legacy/Lts/Common/LtsWidgets/lts_base_layout_widget.cpp
T
2026-08-13 18:33:10 +02:00

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
//