Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-08-24
#
ADD_SUBDIRECTORY(Data)
ADD_SUBDIRECTORY(Gui)
ADD_SUBDIRECTORY(Shared)
#
# Resource Management Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(
IsmResGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ism_resource_management_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
Qt5::Core
)
#
# Audio Video Config Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(
IsmAvcGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ism_audio_video_config_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
Qt5::Core
)
#
# Data Plugin Interface
#
# need top be shared due to signals/slots
NGL_ADD_LIBRARY(WS IsmDataPluginInterface SHARED ism_data_plugin_interface.h)
NGL_TARGET_LINK_LIBRARIES(IsmDataPluginInterface
Qt5::Core
svcIsmCommon
DataPluginInterface
)
NGL_INSTALL_TARGET(IsmDataPluginInterface)
#
# Combobox Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(IsmGuiComboboxPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ism_combobox_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
#
# Exercise Assignment Classic Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(IsmExerciseAssignmentClassicGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ism_exercise_assignment_classic_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
+45
View File
@@ -0,0 +1,45 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-09-06
#
#
# Data Plugin
#
NGL_ADD_LIBRARY(WS IsmDataPlugin MODULE
ism_data_plugin.cpp
ism_data_plugin.h
ism_foreign_data_plugin.cpp
ism_foreign_data_plugin.h
)
NGL_TARGET_LINK_LIBRARIES(IsmDataPlugin
IsmDataPluginInterface
IsmShared
LtsSessionDataDds
LtsUtilsCore
NGLLogger
Qt5::Core
Qt5::Concurrent
svcIsmClient
)
NGL_INSTALL_TARGET(IsmDataPlugin)
NGL_ADD_LIBRARY(WS IsmDataPluginThp STATIC
ism_foreign_data_plugin.cpp
ism_foreign_data_plugin.h
)
NGL_TARGET_LINK_LIBRARIES(IsmDataPluginThp
IsmDataPluginInterface
IsmShared
LtsUtilsCore
NGLLogger
Qt5::Core
Qt5::Concurrent
)
NGL_TARGET_INCLUDE_DIRECTORIES(IsmDataPluginThp
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../..
)
@@ -0,0 +1,80 @@
/**
* @RDE_HEADER@
* Data Plugin for InfrastructureManagement
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-08-24
*/
#include "ism_data_plugin.h"
#include "ism_foreign_data_plugin.h"
#include <LtsSession/lts_session_data_dds.h>
namespace InfrastructureManagement
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
std::shared_ptr<Interface::Dtc> dtc;
std::shared_ptr<Interface::Ftc> ftc;
// if (!session->createTopicClient(dtc, ftc, true))
// return std::shared_ptr<DataPluginBase::Interface>();
return std::make_shared<DataInterfaceImpl>(session, dtc, ftc);
}
DataInterfaceImpl::DataInterfaceImpl(LtsSession::LtsSessionDataDds *session,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc,
const std::shared_ptr<InfrastructureManagement::Interface::Ftc> &ftc)
: DataInterface()
, m_dtc(dtc)
, m_ftc(ftc)
, m_session(session)
//, m_foreignInterface(std::make_shared<ForeignInterfaceImpl>(dtc))
{}
std::shared_ptr<ForeignDataInterface> DataInterfaceImpl::getForeignDataInterface()
{
if (m_foreignInterface)
return m_foreignInterface;
if (!getDtc())
return {};
int exerciseId = -1;
if (m_session)
exerciseId = m_session->exerciseId();
m_foreignInterface = std::make_shared<ForeignInterfaceImpl>(m_dtc, exerciseId);
return m_foreignInterface;
}
std::shared_ptr<InfrastructureManagement::Interface::Dtc> DataInterfaceImpl::getDtc()
{
if (m_dtcEnabled)
return m_dtc;
if (!m_session->createTopicClient(m_dtc, false, true))
return {};
m_dtcEnabled = true;
return m_dtc;
}
std::shared_ptr<InfrastructureManagement::Interface::Ftc> DataInterfaceImpl::getFtc()
{
if (m_ftcEnabled)
return m_ftc;
if (!m_session->createTopicClient(m_ftc, true, true))
return {};
m_ftcEnabled = true;
return m_ftc;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,60 @@
/**
* @RDE_HEADER@
* Data Plugin for InfrastructureManagement
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-08-24
*/
#pragma once
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
namespace InfrastructureManagement
{
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:ism")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin() = default;
~DataPlugin() = default;
QString pluginName() const override { return QStringLiteral("InfrastructureManagement.Data"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Replay;
}
};
class DataInterfaceImpl final : public DataInterface
{
public:
DataInterfaceImpl(LtsSession::LtsSessionDataDds *session,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc,
const std::shared_ptr<InfrastructureManagement::Interface::Ftc> &ftc);
std::shared_ptr<InfrastructureManagement::Interface::Dtc> getDtc() override;// { return m_dtc; }
std::shared_ptr<InfrastructureManagement::Interface::Ftc> getFtc() override;// { return m_ftc; }
std::shared_ptr<ForeignDataInterface> getForeignDataInterface() override;// { return m_foreignInterface; }
private:
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_dtc;
std::shared_ptr<InfrastructureManagement::Interface::Ftc> m_ftc;
bool m_dtcEnabled { false };
bool m_ftcEnabled { false };
LtsSession::LtsSessionDataDds *m_session { nullptr };
std::shared_ptr<ForeignDataInterface> m_foreignInterface;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,446 @@
/**
* @RDE_HEADER@
* Data Plugin for InfrastructureManagement
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-08-24
*/
#include "ism_foreign_data_plugin.h"
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <InfrastructureManagement/logger.h>
#include <LtsUtilsCore/json_object.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSet>
#include <QtConcurrent>
#include <QMutexLocker>
// #ifdef LTS_DEBUG
# define BENCHMARK
// #endif // LTS_DEBUG
#ifdef BENCHMARK
# define BENCHMARK_SETUP_AND_START() QElapsedTimer elapsedTimer; elapsedTimer.start();
# define BENCHMARK_RUN
#else
# define BENCHMARK_SETUP_AND_START()
#endif
namespace InfrastructureManagement
{
ForeignInterfaceImpl::ForeignInterfaceImpl(const std::shared_ptr<Interface::Dtc> &dtc, int exerciseId)
: m_dtc(dtc)
, m_scheduleId(-1)
, m_exerciseId(exerciseId)
, m_logger(getLogger("ForeignDataInterface"))
{
// init() ; lazy-initialisation : moved to enableIsmForeignInterface.
}
ForeignInterfaceImpl::~ForeignInterfaceImpl()
{
}
void ForeignInterfaceImpl::enableIsmForeignInterface() const
{
BENCHMARK_SETUP_AND_START();
if (!m_mountingPoints.isEmpty())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, ismDataDtc, m_exerciseId = " << m_exerciseId
<< " already initialized -> return";
return;
}
// cast const away:
ForeignInterfaceImpl *NON_CONST_THIS = const_cast<ForeignInterfaceImpl*>(this);
NON_CONST_THIS->init();
#ifdef BENCHMARK_RUN
NOTICE_LOG(m_logger) << LOGFUNCTION << " ISM::StructureElementCache / ForeignInterfaceImpl::init took " << elapsedTimer.elapsed() << " [ms]"
<< " - m_exerciseId = " << m_exerciseId
<< " - m_mountingPoints.size()=" << m_mountingPoints.size()
<< ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")";
#endif // BENCHMARK_RUN
}
bool ForeignInterfaceImpl::mountingPoints(const std::function<void (const MountingPoint &)> &cb)
{
BENCHMARK_SETUP_AND_START();
enableIsmForeignInterface();
for (auto it = m_mountingPoints.constBegin(); it != m_mountingPoints.constEnd(); ++it)
cb(it.value());
#ifdef BENCHMARK_RUN
NOTICE_LOG(m_logger) << LOGFUNCTION
<< " - m_exerciseId = " << m_exerciseId
<< " - m_mountingPoints.size()=" << m_mountingPoints.size()
<< " took " << elapsedTimer.elapsed() << " [ms]";
#else
NOTICE_LOG(m_logger) << LOGFUNCTION
<< " - m_exerciseId = " << m_exerciseId
<< " - m_mountingPoints.size()=" << m_mountingPoints.size();
#endif // BENCHMARK_RUN
return true;
}
bool ForeignInterfaceImpl::mountingPoints(const std::function<bool (const MountingPoint &)> &cb)
{
enableIsmForeignInterface();
for (auto it = m_mountingPoints.constBegin(); it != m_mountingPoints.constEnd(); ++it)
if (cb(it.value()))
return true;
return false;
}
QHash<int32_t, MountingPoint> ForeignInterfaceImpl::mountingPoints() const
{
enableIsmForeignInterface();
return m_mountingPoints;
}
MountingPoint ForeignInterfaceImpl::mountingPoint(int32_t mountingPointId) const
{
enableIsmForeignInterface();
return m_mountingPoints.value(mountingPointId);
}
MainSchedule ForeignInterfaceImpl::mainSchedule(int32_t scheduleId)
{
enableIsmForeignInterface();
return m_dtc->mainSchedule(scheduleId);
}
void ForeignInterfaceImpl::setScheduleId(int32_t scheduleId)
{
DEBUG_LOG(m_logger) << "setScheduleId to: " << scheduleId
<< " (was " << m_scheduleId << ")";
enableIsmForeignInterface();
m_scheduleId = scheduleId;
onMainScheduleChanged(m_dtc->mainSchedule(scheduleId), DataModification::eModified);
emit scheduleIdChanged(m_scheduleId);
}
int32_t ForeignInterfaceImpl::scheduleId() const
{
return m_scheduleId;
}
QSet<int> ForeignInterfaceImpl::buildingsInCurrentExercise()
{
enableIsmForeignInterface();
return m_bldgsInExcersise;
}
const QSet<int>& ForeignInterfaceImpl::buildingsInCurrentExercise() const
{
enableIsmForeignInterface();
return m_bldgsInExcersise;
}
bool ForeignInterfaceImpl::isBuildingsInCurrentExercise(int buildingId) const
{
enableIsmForeignInterface();
return m_bldgsInExcersise.contains(buildingId);
}
void ForeignInterfaceImpl::onMainStructureElementChanged(const MainStructureElement &data, DataModification modType)
{
const int mseId = data.id();
switch (modType)
{
case DataModification::eRemoved:
{
QMutexLocker locker(&m_mutex);
const auto &structureElements = data.elements();
for (const StructureElement &currentStructEle : structureElements)
{
if (currentStructEle.structureElementTypeId() != StructureElementType::MountingPoint)
continue;
m_mountingPoints.remove(currentStructEle.id());
}
break;
}
case DataModification::eAdded:
case DataModification::eModified:
{
QVector<int> exeIds;
// read only once properties - available_in_exercise from MSE, only if exerciseId is relevant
if (m_exerciseId > 0)
{
QJsonParseError parserError;
const QByteArray &content = QByteArray::fromStdString(data.properties());
const QJsonDocument doc(QJsonDocument::fromJson(content, &parserError));
if (parserError.error != QJsonParseError::NoError)
WARNING_LOG(m_logger) << "Invalid properties for MSE " << data.id() << ", " << data.name();
else
{
const QJsonArray exercises(QJsonObject(doc.object()).value(QStringLiteral("available_in_exercise")).toArray());
exeIds.reserve(exercises.size());
for (const auto &exercise : exercises)
exeIds += exercise.toInt();
}
}
// update m_bldgsInExcersise
{
bool realChange = false;
{
QMutexLocker locker(&m_mutex);
if (exeIds.contains(m_exerciseId) ||
(m_exerciseId == 0) // global -> processAll
)
{
if (!m_bldgsInExcersise.contains(mseId))
{
m_bldgsInExcersise.insert(mseId);
realChange = true;
}
} else {
if (m_bldgsInExcersise.contains(mseId))
{
m_bldgsInExcersise.remove(mseId);
realChange = true;
}
}
} // scope for mutex
// Maybe an MSE/building is added/removed?
if (realChange)
{
// ensure map object will be created
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_bldgsInExcersise updated."
<< " (mseId=" << mseId << " name=" << data.name();
emit buildingsInCurrentExerciseChanged();
}
}
// N. Thoden, 11.01.2022:
// reduce amount of data by filtering m_exerciseId / available_in_exercise
// (may otherwise took up to ~10 seconds!!)
// m_exerciseId <= 0 -> process all
if (m_exerciseId == 0 || (m_exerciseId > 0 && exeIds.contains(m_exerciseId)))
{
const auto &structureElements = data.elements();
for (const StructureElement &currentStructEle : structureElements)
{
if (currentStructEle.structureElementTypeId() != StructureElementType::MountingPoint)
continue;
StructureElement seFloor;
const std::vector<int32_t> &curPath = currentStructEle.path();
if (curPath.size() == 4)
{
// GUEZE-3258: Performance-Untersuchung der OpApp : getStructureElementById is expensive
// 500 bldgs, ~25000 structure element -> init() can took 2500ms (CTCAP28)
if (!m_dtc->getStructureElementById(curPath[1], seFloor)) // getStructureElementById is expensive if many buildings/structure elements
WARNING_LOG(m_logger) << " getStructureElementById failed for " << curPath[1];
}
const int floorId = QString::fromStdString(seFloor.name()).split(QStringLiteral("_")).value(1, QStringLiteral("-10")).toInt();
{
QMutexLocker locker(&m_mutex);
// GUEZE-3258: Performance-Untersuchung der OpApp
const auto it = m_mountingPoints.find(currentStructEle.id());
if (it != m_mountingPoints.end())
{
MountingPoint &mountingPointRef = *it;
if (mountingPointRef.data() == currentStructEle)
continue;
mountingPointRef.updateData(currentStructEle, floorId);
emit mountingPointChanged(mountingPointRef, DataModification::eModified);
} else {
DEBUG_LOG(m_logger) << "New Mounting point with id " << currentStructEle.id()
<< " and type " << currentStructEle.mountingPointTypeId()
<< " (type " << currentStructEle.mountingPointTypeId().underlying() << ")"
<< " subid: " << currentStructEle.mountingPointId() << this;
MountingPoint newMountingPoint(currentStructEle, floorId);
const int assetId = m_mountingPointAssetMap.value(newMountingPoint.id(), -1);
newMountingPoint.setAssociatedAssetId(assetId);
// newMountingPoint->setHasAssociatedAssetDefect(); // TODO
m_mountingPoints.insert(newMountingPoint.id(), newMountingPoint);
emit mountingPointChanged(newMountingPoint, DataModification::eAdded);
} // if (it != m_mountingPoints.end())
}
}
}
break;
}
} // switch
}
void ForeignInterfaceImpl::onMountingPointAssetChanged(const MountingPointAsset &data, DataModification modType)
{
const int32_t structureElementId = data.structureElementId();
DEBUG_LOG(m_logger) << "onMountingPointAssetChanged se id: " << structureElementId << ", assetId: " << data.assetId();
// [GUEZE-3494] Ressourcenverwaltung ist fehlerhaft laut Kunden
// QHash:
// value() -> return const T
// operator[] -> return T &
// // MountingPoint mp = m_mountingPoints.value(structureElementId);
MountingPoint &mpRef = m_mountingPoints[structureElementId]; // default constructed value may okay
if (modType == DataModification::eRemoved)
{
m_mountingPointAssetMap.remove(structureElementId);
if (mpRef.id() > 0)
{
mpRef.setAssociatedAssetId(-1);
mpRef.setHasAssociatedAssetDefect(false);
}
}
else
{
m_mountingPointAssetMap.insert(structureElementId, data.assetId());
if (mpRef.id() > 0)
{
mpRef.setAssociatedAssetId(data.assetId());
mpRef.setHasAssociatedAssetDefect(m_dtc->instrumentationAsset(data.assetId()).assetStateId() == InstrumentationAssetState::Defect);
}
}
if (mpRef.id() > 0)
emit mountingPointChanged(mpRef, DataModification::eModified);
}
void ForeignInterfaceImpl::onMainScheduleChanged(const MainSchedule &data, DataModification modType)
{
if (m_scheduleId != data.id())
return;
Q_UNUSED(modType);
QHash<int, MountingPointPlan> mppMap;
for (const auto &elem : data.elements())
mppMap[elem.structureElementId()] = elem;
for (MountingPoint &mp : m_mountingPoints)
{
const MountingPointPlan &mpp = mppMap[mp.id()];
const MountingPointState &mps = mpp.mountingPointState();
// If there is no MPP for this Schedule
if(mpp.structureElementId() != mp.id())
{
// Do nothing if idle
if (mp.aimState() == MountingPointState_def::Idle)
continue;
mp.setAimState(MountingPointState::Idle);
emit mountingPointChanged(mp, DataModification::eModified);
continue;
}
// If AimState did not change, continue
if (mp.aimState() == mps)
continue;
mp.setAimState(mps);
emit mountingPointChanged(mp, DataModification::eModified);
}
}
void ForeignInterfaceImpl::init()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, ismDataDtc, m_exerciseId = " << m_exerciseId
<< " - m_mountingPoints.size()=" << m_mountingPoints.size()
<< ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")";
m_dtc->waitForHistoricalDataMainStructureElement(1000); // enable is implicit
m_dtc->waitForHistoricalDataMainSchedule(1000); // enable is implicit
m_dtc->waitForHistoricalDataMountingPointAsset(1000); // enable is implicit
connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged,
this, &ForeignInterfaceImpl::onMainStructureElementChanged, Qt::UniqueConnection);
connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged,
this, &ForeignInterfaceImpl::onMainScheduleChanged, Qt::UniqueConnection);
connect(m_dtc.get(), &Interface::Dtc::mountingPointAssetChanged,
this, &ForeignInterfaceImpl::onMountingPointAssetChanged, Qt::UniqueConnection);
// // #define PROCESS_MSE_SEQUENTIELL
#ifdef PROCESS_MSE_SEQUENTIELL
m_dtc->mainStructureElements([this](const MainStructureElement &data)
{
onMainStructureElementChanged(data, DataModification::eAdded);
});
#else
// 25.10.2022, Norbert Thoden:
// ForeignInterfaceImpl::init() benoetigt ca. 5sec at CTCAP15
// Durch Parallelisierung reduziert es sich auf knapp 2sec. :-)
// via std::bind:
// using namespace std::placeholders;
// std::function<void(const MainStructureElement &data)> functor =
// std::bind(&ForeignInterfaceImpl::onMseChangedForInitializing, this, _1);
// QtConcurrent::blockingMap(mseMap, functor);
// Es geht aber auch einfacher per lambda :-)
const QMap<qint32, InfrastructureManagement::MainStructureElement> &mseMap =
m_dtc->mainStructureElements();
m_mountingPoints.reserve(mseMap.size());
// blockingMap -> functor will be applied to every item:
QtConcurrent::blockingMap(mseMap, [this](const MainStructureElement &data) {
onMainStructureElementChanged(data, DataModification::eAdded);
});
#endif // PROCESS_MSE_SEQUENTIELL
m_dtc->mountingPointAssets([this](const MountingPointAsset &data)
{
onMountingPointAssetChanged(data, DataModification::eAdded);
});
m_dtc->mainSchedules([this](const MainSchedule &data)
{
onMainScheduleChanged(data, DataModification::eAdded);
});
int firstBldg = -1;
if (!m_bldgsInExcersise.isEmpty())
firstBldg = *m_bldgsInExcersise.begin();
DEBUG_LOG(m_logger) << LOGFUNCTION << ", exerciseId = " << m_exerciseId << ", bldgs in excersise = " << m_bldgsInExcersise.size()
<< ", firstBldg: " << firstBldg;
DEBUG_LOG(m_logger) << LOGFUNCTION << "XXXXX" << m_bldgsInExcersise.size();
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, ismDataDtc, m_exerciseId = " << m_exerciseId
<< " - m_mountingPoints.size()=" << m_mountingPoints.size()
<< ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")";
}
} // namespace InfrastructureManagement
@@ -0,0 +1,77 @@
/**
* @RDE_HEADER@
* Data Plugin for InfrastructureManagement
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-08-24
*/
#pragma once
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <QHash>
#include <QSet>
#include <QMutex>
namespace InfrastructureManagement
{
class ForeignInterfaceImpl final : public ForeignDataInterface
{
Q_OBJECT
public:
explicit ForeignInterfaceImpl(const std::shared_ptr<Interface::Dtc> &dtc, int exerciseId = -1);
~ForeignInterfaceImpl();
// lazy-initialisation: // is called at beginning of every access method
void enableIsmForeignInterface() const;
// mainStructureElements (buildings)
//@{
bool mountingPoints(const std::function<void (const MountingPoint &)> &cb) override final;
bool mountingPoints(const std::function<bool(const MountingPoint &data)> &cb) override final;
QHash<int32_t, MountingPoint> mountingPoints() const override final;
MountingPoint mountingPoint(int32_t mountingPointId) const override final;
//@}
// mainSchedule
//@{
MainSchedule mainSchedule(int32_t scheduleId) override final;
void setScheduleId(int32_t scheduleId) override final;
int32_t scheduleId() const override final;
//@}
// buildings in current exercise
//@{
QSet<int> buildingsInCurrentExercise() override final;
const QSet<int>& buildingsInCurrentExercise() const override final;
bool isBuildingsInCurrentExercise(int buildingId) const override final;
//@}
private Q_SLOTS:
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType);
void onMountingPointAssetChanged(const InfrastructureManagement::MountingPointAsset &data, DataModification modType);
void onMainScheduleChanged(const InfrastructureManagement::MainSchedule &data, DataModification modType);
private: // methods
void init();
private: // attributes
std::shared_ptr<Interface::Dtc> m_dtc;
QMutex m_mutex;
QHash<int32_t, MountingPoint> m_mountingPoints; // By SeId
QHash<int32_t, int32_t> m_mountingPointAssetMap; // key: structureElementId/mountingPointId - value: assetId
QSet<int> m_bldgsInExcersise; // All Buildings avaiable in this Exercise
int32_t m_scheduleId;
int32_t m_exerciseId{-1};
NGL::INGLLogger &m_logger;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,40 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Hannes Baeuerle, SLSE, 2017-06-29
# Refreshed by Mike Wille, SLTE, 2022-09-26
#
SET(src
ism_audio_video_config_gui_plugin.cpp
ism_audio_video_config_gui_plugin.h
SetRecording/ism_set_recording_dialog.cpp
SetRecording/ism_set_recording_dialog_model.cpp
SetRecording/ism_set_recording_dialog_requester.cpp
SetRecording/ism_set_recording_checkstate_proxy_model.cpp
)
NGL_WRAP_UI(src
SetRecording/ism_set_recording_dialog.ui
)
NGL_ADD_LIBRARY(WS IsmAvcGuiPlugin MODULE ${src})
NGL_TARGET_LINK_LIBRARIES(IsmAvcGuiPlugin
NGLLogger
nglwidgets
LtsPrinting
LtsSession
LtsSessionData
LtsWidgets
LtsDataView
IsmShared
IsmAvcGuiPluginInterface
ExmDataPluginInterface # TODO: rm
IsmDataPluginInterface
LtsUtilsGuiDds
LtsUtilsSettings
)
NGL_INSTALL_TARGET(IsmAvcGuiPlugin)
@@ -0,0 +1,110 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*
* Created by Steve Kemayou, SLTE, 2023-01-25
*/
#include "ism_set_recording_checkstate_proxy_model.h"
namespace InfrastructureManagement
{
Qt::ItemFlags SetRecordingCheckStateProxyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return sourceModel()->flags(index); // delegate to source model for further processing if necessary
// Sets only the checkbox nodes on user checkable,
// checkbox leaves must be handled in source model.
QModelIndex sourceIndex = mapToSource(index);
Qt::ItemFlags fl = sourceModel()->flags(sourceIndex);
if (index.column() == 0)
return fl | Qt::ItemIsUserCheckable;
return fl;
}
QVariant SetRecordingCheckStateProxyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
QModelIndex sourceIndex = mapToSource(index);
// delegate everything except CheckStateRole to source model
if (role != Qt::CheckStateRole)
return sourceModel()->data(sourceIndex, role);
// delegate a leaf too with CheckStateRole to source model
if (isLeaf(index))
{
return sourceModel()->data(sourceIndex, role);
}
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->data(sourceIndex, role);
int checkedCount = 0;
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
const QModelIndex childIndex(this->index(childRow, 0, index));
const QVariant value(data(childIndex, Qt::CheckStateRole));
if (value.isValid() && value.canConvert<Qt::CheckState>())
{
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (state == Qt::PartiallyChecked)
return Qt::PartiallyChecked;
if (state == Qt::Checked)
++checkedCount;
}
}
if (checkedCount == childCount)
return Qt::Checked;
else if (checkedCount == 0)
return Qt::Unchecked;
else
return Qt::PartiallyChecked;
}
bool SetRecordingCheckStateProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
const QModelIndex sourceIndex(mapToSource(index));
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->setData(sourceIndex, value, role);
// delegate everything except CheckStateRole to source mode
if (role != Qt::CheckStateRole)
return sourceModel()->setData(sourceIndex, value, role);
if (isLeaf(index))
{
// delegate a leaf to source model
sourceModel()->setData(sourceIndex, value, role);
}
else
{
// update underlying children recursively (Additional nodes with leaves may also exist)
const int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
const QModelIndex childIndex(this->index(childRow, 0, index));
setData(childIndex, value, (Qt::CheckStateRole));
}
}
return true;
}
bool SetRecordingCheckStateProxyModel::isLeaf(const QModelIndex &index) const
{
QModelIndex sourceIndex = mapToSource(index);
return sourceModel()->flags(sourceIndex).testFlag(Qt::ItemIsUserCheckable);
}
}// namespace InfrastructureManagement
@@ -0,0 +1,24 @@
#ifndef SETRECORDINGCHECKSTATEPROXYMODEL_H
#define SETRECORDINGCHECKSTATEPROXYMODEL_H
#include <QIdentityProxyModel>
namespace InfrastructureManagement
{
class SetRecordingCheckStateProxyModel : public QIdentityProxyModel
{
public:
using QIdentityProxyModel::QIdentityProxyModel;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
bool isLeaf(const QModelIndex &index) const;
};
}// namespace InfrastructureManagement
#endif // SETRECORDINGCHECKSTATEPROXYMODEL_H
@@ -0,0 +1,230 @@
/**
* @RDE_HEADER@
* The SetReportingDialog lists all known videostreams and offers the option wether to set them to be recorded or not
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-07-03
*/
#include "ism_set_recording_dialog.h"
#include "ui_ism_set_recording_dialog.h"
#include "ism_set_recording_dialog_model.h"
#include <LtsUtilsGuiDds/request_helper.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsWidgets/lts_overlay_loading.h>
#include "ism_set_recording_dialog_requester.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QTreeView>
#include <QTimer>
namespace
{
/**
* Helper function to find a given MountingPoint within a MainStructureElement (by id).
*/
static inline InfrastructureManagement::StructureElement findMountingPoint(const InfrastructureManagement::MainStructureElement &building,
const InfrastructureManagement::SimpleRecordingData &guiMountingPoint)
{
Q_ASSERT(guiMountingPoint.mainStructureElementId == building.id());
for (const auto &currentStructureElement : building.elements())
{
if (currentStructureElement.id() == guiMountingPoint.id)
return currentStructureElement;
}
Q_ASSERT(false);
return InfrastructureManagement::StructureElement();
}
} // anonymous namespace
namespace InfrastructureManagement
{
SetRecordingDialog::SetRecordingDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ui(new Ui::SetRecordingDialog)
, m_ismDtc(nullptr)
, m_ismFtc(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_model(nullptr)
, m_checkStateProxyModel(nullptr)
, m_timerUpdate(nullptr)
, m_logger(getLogger("SetRecordingDialog"))
{
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Exercise_Assignment"));
}
SetRecordingDialog::~SetRecordingDialog()
{
delete m_ui;
}
void SetRecordingDialog::retranslate()
{
translate(m_ui, tr("Set Recording"));
}
bool SetRecordingDialog::init(const std::shared_ptr<Interface::Dtc> &ismDtc, const std::shared_ptr<Interface::Ftc> &ismFtc, const std::shared_ptr<ForeignDataInterface> &dataInterface)
{
m_ismDtc = ismDtc;
m_ismFtc = ismFtc;
if (!(m_ismDtc->enableMainStructureElement() &&
m_ismFtc->enableMainStructureElementModify()))
{
ERROR_LOG(m_logger) << "Could not enable ISM topics";
return false;
}
m_timerUpdate = new QTimer(this);
m_timerUpdate->setSingleShot(true);
delete m_model;
m_model = new SetRecordingDialogModel(this);
if (!m_model->initModel(m_ismDtc, dataInterface))
{
delete m_model;
m_model = nullptr;
ERROR_LOG(m_logger) << "Could not init model";
return false;
}
delete m_checkStateProxyModel;
m_checkStateProxyModel = new SetRecordingCheckStateProxyModel(this);
m_checkStateProxyModel->setSourceModel(m_model);
m_ui->treeView->setModel(m_checkStateProxyModel);
connect(m_timerUpdate, &QTimer::timeout, this, [&]()
{
if (m_ui->treeView->proxyModel() != nullptr)
{
m_ui->treeView->proxyModel()->invalidate(); // update treeview
}
});
m_ui->treeView->treeView()->expandToDepth(0);
connect(m_model, &SetRecordingDialogModel::dataChanged, this, &SetRecordingDialog::onDataChanged);
return true;
}
void SetRecordingDialog::onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void SetRecordingDialog::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
Q_UNUSED(topLeft);
Q_UNUSED(bottomRight);
Q_UNUSED(roles);
m_timerUpdate->start(100);
slotChangesMade();
}
bool SetRecordingDialog::apply()
{
// XXX: HACK we don't know if user pressed ok or apply - apply() has to emidiately return, but the operation is async... so mimic ok/apply later, based on what was clicked
bool wasOkay = (sender() == static_cast<QObject *>(m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)));
QVector<SimpleRecordingData> vec;
QMap<int32_t, std::vector<StructureElement> > modifiedElements; // By Building ID (Elements in Building)
QMap<int32_t, MainStructureElement> affectedMainStructureElements; // By Building ID (Building itself)
m_model->getChangedCams(vec);
LtsWidgets::LtsOverlayLoading *lol = new LtsWidgets::LtsOverlayLoading;
setOverlay(lol);
SEModifyRequestCollector *collector = new SEModifyRequestCollector(m_ismFtc, this);
{
QPushButton *pbCancel = new QPushButton;
pbCancel->setText(tr("Cancel"));
connect(pbCancel, &QPushButton::clicked,
this, [pbCancel, collector, lol]()
{
collector->cancel();
lol->setText(tr("Canceling ..."));
pbCancel->setEnabled(false);
});
qobject_cast<QVBoxLayout *>(lol->layout())->addWidget(pbCancel, 0, Qt::AlignmentFlag::AlignCenter);
}
for (const SimpleRecordingData &affectedMountingPoint : qAsConst(vec))
{
const int buildingId = affectedMountingPoint.mainStructureElementId;
MainStructureElement mse = m_ismDtc->mainStructureElement(buildingId);
const MainStructureElement &building = mse;
StructureElement modifiedMountingPoint = findMountingPoint(building, affectedMountingPoint);
QJsonDocument propsDoc = QJsonDocument::fromJson(QByteArray::fromStdString(modifiedMountingPoint.properties()));
QJsonObject propsObj;
if (propsDoc.isObject()) // if the given properties are no valid JSON object, the properties will be made from scratch
propsObj = propsDoc.object();
propsObj.insert(QLatin1String("record"), affectedMountingPoint.shallHaveRecordingOn);
// add to list of elements to modify
modifiedMountingPoint.properties(QJsonDocument(propsObj).toJson(QJsonDocument::Compact).toStdString());
modifiedElements[buildingId].push_back(modifiedMountingPoint); // clazy:exclude=reserve-candidates
}
for(auto it = modifiedElements.cbegin(); it != modifiedElements.cend(); ++it)
{
StructureElementModifyRequest request(it.key(), it.value());
collector->addRequest(it.key(), request);
}
int initialCount = collector->count();
const QString leText(QStringLiteral("%1<br />%3 / %2").arg(tr("set Camera(s) recording...")).arg(initialCount));
lol->setText(leText.arg(0));
connect(collector, &SEModifyRequestCollector::requestComplete,
this, [collector, lol, leText, initialCount]()
{
lol->setText(leText.arg(initialCount - collector->count()));
});
connect(collector, &SEModifyRequestCollector::finished,
this, [this, collector, wasOkay, lol](bool canceled)
{
unsetOverlay();
lol->deleteLater();
collector->deleteLater();
int failedCount = collector->failedCount();
if (failedCount > 0)
{
new LtsWidgets::LtsMessageDialogNew(this, tr("Error: Couldn't set %1 camera(s) recording!").arg(failedCount));
return;
}
if (canceled)
return;
__unchange__(); // 'apply' behaviour
if (!wasOkay) // 'ok' behaviour
return;
closeRequest(); // we 'unchanged', so it will close directly
});
collector->go();
return false; // our request is async, say false, show a blocking dialog and do ok-/apply-button stuff later
}
} // namespace InfrastructureManagement
@@ -0,0 +1,67 @@
/**
* @RDE_HEADER@
* The SetReportingDialog lists all known videostreams and offers the option wether to set them to be recorded or not
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-07-03
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include "ism_set_recording_checkstate_proxy_model.h"
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <InfrastructureManagement/logger.h>
namespace Ui
{
class SetRecordingDialog;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace InfrastructureManagement
{
class SetRecordingDialogModel;
class SetRecordingCheckStateProxyModel;
class SetRecordingDialog
: public LtsWidgets::LtsDialog
, protected Interface::Ftc::StructureElementModifyReplyHandler
{
Q_OBJECT
public:
explicit SetRecordingDialog(QWidget *parent = nullptr);
~SetRecordingDialog();
bool init(const std::shared_ptr<Interface::Dtc> &ismDtc, const std::shared_ptr<Interface::Ftc> &ismFtc, const std::shared_ptr<ForeignDataInterface> &dataInterface);
void onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override;
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
private: // methods
void retranslate() override;
bool apply() override final;
private: // attributes
Ui::SetRecordingDialog *m_ui;
std::shared_ptr<Interface::Dtc> m_ismDtc;
std::shared_ptr<Interface::Ftc> m_ismFtc;
LtsUtils::RequestHelper *m_requestHelper;
SetRecordingDialogModel *m_model;
SetRecordingCheckStateProxyModel *m_checkStateProxyModel;
QTimer *m_timerUpdate;
bool update = false;
LOGGER_T m_logger;
}; // class SetRecordingDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SetRecordingDialog</class>
<widget class="QWidget" name="SetRecordingDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>751</width>
<height>457</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="LtsDataView::LtsDataView" name="treeView" native="true">
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
<property name="toolButtonsVisible" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,338 @@
/**
* @RDE_HEADER@
* The SetRecordingDialogModel provices data for SetRecordingDialog
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-07-04
*/
#include "ism_set_recording_dialog_model.h"
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <InfrastructureManagement/ism_translation.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QCheckBox>
namespace InfrastructureManagement
{
SetRecordingDialogModel::SetRecordingDialogModel(QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), { tr("Name") })
, m_dtc(nullptr)
, m_logger(getLogger("InfrastructureManagement"))
{
}
QVariant SetRecordingDialogModel::data(const QModelIndex &index, int role) const
{
if (!(index.isValid() && (role == Qt::DisplayRole || role == Qt::UserRole || role == (Qt::UserRole + 1) || role == Qt::CheckStateRole)))
return QVariant();
NGLTreeItem *item = privateData(index);
if (role == Qt::DisplayRole)
{
//no switch() necessary because we have only one column here
if (item->data().canConvert<SimpleRecordingData>())
return item->data().value<SimpleRecordingData>().name;
if (item->data().canConvert<QString>())
return item->data().toString();
return QVariant();
}
else if (role == Qt::CheckStateRole)
{
if (item->data().canConvert<SimpleRecordingData>())
return item->data().value<SimpleRecordingData>().shallHaveRecordingOn ? Qt::Checked : Qt::Unchecked;
}
else if (role == Qt::UserRole && item->data().canConvert<SimpleRecordingData>())
return item->data().value<SimpleRecordingData>().id;
return QVariant();
}
bool SetRecordingDialogModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ForeignDataInterface> &dataInterface)
{
m_dtc = dtc;
if (!(m_dtc->enableMainStructureElement() &&
m_dtc->enableMountingPointAsset()))
{
ERROR_LOG(m_logger) << "Could not enable Datatopics";
return false;
}
m_dataInterface = dataInterface;
connect(m_dataInterface.get(), &ForeignDataInterface::mountingPointChanged,
this, &SetRecordingDialogModel::onMountingPointChanged);
INFO_LOG(m_logger) << "initModel successfull";
initData();
return true;
}
void SetRecordingDialogModel::initData()
{
NGLTreeModel::resetModel();
QMap<int32_t, StructureElement> allStructureElements;
QMap<qint32, InfrastructureManagement::MainStructureElement> mainStructEles = m_dtc->mainStructureElements();
QMap<qint32, qint32> mapMse2groupId;
for (auto it = mainStructEles.constBegin(); it != mainStructEles.constEnd(); ++it)
{
mapMse2groupId.insert(it.value().id(), it.value().groupId());
for (const StructureElement &currentElement : it.value().elements())
{
allStructureElements.insert(currentElement.id(), currentElement);
}
}
QMap<int32_t, NGLTreeItem *> structEleIdToItem;
// create all ngl treeitems
for (auto it = allStructureElements.constBegin(); it != allStructureElements.constEnd(); ++it)
{
NGLTreeItem *item = nullptr;
if (it.value().structureElementTypeId() == StructureElementType::MountingPoint)
{
if (it.value().mountingPointTypeId() != MountingPointType::IndoorCamera &&
it.value().mountingPointTypeId() != MountingPointType::OutdoorCamera)
continue;
item = new NGLTreeItem(QVariant::fromValue(toSimpleRecordingData(it.value())));
}
else
item = new NGLTreeItem(QString::fromStdString(it.value().displayName()));
structEleIdToItem.insert(it.key(), item);
}
const QList<int> sections = m_dtc->getSections();
QMap<int, NGLTreeItem*> mapGroup;
//adding default group
const int defaultSectionId = static_cast<int>(InfrastructureManagement::BuildingGroup_def::UnknownGroup);
NGLTreeItem *defaultSectionRoot = new NGLTreeItem(InfrastructureManagement::toString(static_cast<InfrastructureManagement::BuildingGroup_def::type>(defaultSectionId)));
mapGroup.insert(defaultSectionId, defaultSectionRoot);
m_rootItem->appendChild(mapGroup.value(defaultSectionId));
// append to root availables sections by groupId
for(auto const &groupId : sections)
{
if(mapGroup.contains(groupId))
continue;
const QString sectionText = InfrastructureManagement::toString(static_cast<InfrastructureManagement::BuildingGroup_def::type>(groupId));
DEBUG_LOG(m_logger)<<" >> Adding section >> "<<sectionText;
NGLTreeItem *sectionRoot = new NGLTreeItem(sectionText);
mapGroup.insert(groupId, sectionRoot);
m_rootItem->appendChild(mapGroup.value(groupId));
}
for (auto it = structEleIdToItem.begin(); it != structEleIdToItem.end(); ++it)
{
StructureElement structureElement = allStructureElements.value(it.key());
int32_t pathSize = structureElement.path().size();
NGLTreeItem *parent = mapGroup.value(defaultSectionId); // default section parent index
if (pathSize > 1)
{
parent = structEleIdToItem.value(structureElement.path().at(pathSize - 2));
}
else
{
const int sectionId = mapMse2groupId.value(structureElement.mainStructureElementId(), -1);
if(sectionId != -1)
{
parent = mapGroup.value(sectionId);
}
}
parent->appendChild(it.value());
}
for(auto sectionRoot : mapGroup.values())
{
clearFromEmptyStructures(sectionRoot);
}
// remove empty sections
for (int i = m_rootItem->childCount() - 1; i >= 0; --i)
{
NGLTreeItem *currentChild = m_rootItem->child(i);
if (currentChild->childCount() == 0)
{
const QModelIndex parentIdx = indexFromItem(m_rootItem);
beginRemoveRows(parentIdx, i, i);
m_rootItem->removeChild(currentChild);
endRemoveRows();
}
}
}
Qt::ItemFlags SetRecordingDialogModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags fl = NGLTreeModel::flags(index);
if (!index.isValid())
return fl;
NGLTreeItem *item = privateData(index);
bool isLeaf = item->data().canConvert<SimpleRecordingData>();
if (isLeaf && index.column() == 0)
return fl | Qt::ItemIsUserCheckable;
return fl;
}
bool SetRecordingDialogModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::CheckStateRole || index.column() != NAME || !index.isValid())
return NGLTreeModel::setData(index, value, role);
if (!value.canConvert<bool>())
return false;
NGLTreeItem *item = privateData(index);
if (item->data().canConvert<SimpleRecordingData>())
{
// Blatt
SimpleRecordingData srd = item->data().value<SimpleRecordingData>();
if (srd.shallHaveRecordingOn == value.toBool())
return true;
srd.shallHaveRecordingOn = value.toBool();
item->setData(QVariant::fromValue(srd));
emit dataChanged(index, index, {role});
}
return true;
}
void SetRecordingDialogModel::onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType)
{
if (modType != DataModification::eModified || !hasCorrectType(mountingPoint))
return;
QModelIndexList indices = match(index(0, 0), Qt::UserRole, QVariant::fromValue(mountingPoint.id()), 1, Qt::MatchRecursive);
if (indices.isEmpty())
return;
QModelIndex index = indices.first();
NGLTreeItem *item = privateData(index);
if (!(item && item->data().canConvert<SimpleRecordingData>()))
return;
item->setData(QVariant::fromValue(toSimpleRecordingData(mountingPoint)));
emit dataChanged(index, index, QVector<int>() << Qt::DisplayRole);
}
SimpleRecordingData SetRecordingDialogModel::toSimpleRecordingData(const MountingPoint &mountingPoint)
{
SimpleRecordingData result;
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(mountingPoint.properties(), &parseError);
if (parseError.error != QJsonParseError::NoError)
result.hasRecordingOn = false;
else
result.hasRecordingOn = doc.object().value(QLatin1String("record")).toBool();
result.mainStructureElementId = mountingPoint.buildingId();
result.name = mountingPoint.name();
result.id = mountingPoint.id();
result.shallHaveRecordingOn = result.hasRecordingOn;
return result;
}
SimpleRecordingData SetRecordingDialogModel::toSimpleRecordingData(const StructureElement &mountingPoint)
{
SimpleRecordingData result;
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(mountingPoint.properties()), &parseError);
if (parseError.error != QJsonParseError::NoError)
result.hasRecordingOn = false;
else
result.hasRecordingOn = doc.object().value(QLatin1String("record")).toBool();
result.mainStructureElementId = mountingPoint.mainStructureElementId();
if (mountingPoint.displayName().size())
result.name = QString::fromStdString(mountingPoint.displayName());
else if (mountingPoint.name().size())
result.name = QString::fromStdString(mountingPoint.name());
else
result.name = QStringLiteral("MP_%1").arg(mountingPoint.id());
result.id = mountingPoint.id();
result.shallHaveRecordingOn = result.hasRecordingOn;
return result;
}
bool SetRecordingDialogModel::hasCorrectType(const MountingPoint &mountingPoint)
{
return mountingPoint.type() == MountingPointType::IndoorCamera ||
mountingPoint.type() == MountingPointType::OutdoorCamera;
}
void SetRecordingDialogModel::clearFromEmptyStructures(NGLTreeItem *treeItem)
{
if (!treeItem)
return;
for (int i = treeItem->childCount() - 1; i >= 0; --i)
{
NGLTreeItem *currentChild = treeItem->child(i);
if (!hasCam(currentChild))
{
const QModelIndex parentIdx = indexFromItem(treeItem);
beginRemoveRows(parentIdx, i, i);
treeItem->removeChild(currentChild);
endRemoveRows();
}
else
clearFromEmptyStructures(currentChild);
}
}
bool SetRecordingDialogModel::hasCam(const NGLTreeItem *treeItem)
{
if (treeItem->data().canConvert<SimpleRecordingData>())
return true;
const auto children = treeItem->children();
for (NGLTreeItem *currentChild : children)
if (hasCam(currentChild))
return true;
return false;
}
void SetRecordingDialogModel::getChangedCams(QVector<SimpleRecordingData> &set, NGLTreeItem *treeItem) const
{
if (treeItem == nullptr)
treeItem = m_rootItem;
const auto children = treeItem->children();
for (NGLTreeItem *child : children)
{
if (!child->data().canConvert<SimpleRecordingData>())
{
getChangedCams(set, child);
continue;
}
SimpleRecordingData srd = child->data().value<SimpleRecordingData>();
if (srd.hasRecordingOn == srd.shallHaveRecordingOn)
continue;
set << srd;
}
}
} // namespace InfrastructureManagement
@@ -0,0 +1,95 @@
/**
* @RDE_HEADER@
* The SetRecordingDialogModel provices data for SetRecordingDialog
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-07-04
*/
#pragma once
#include <InfrastructureManagement/logger.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <nglwidgets/ngltreemodel.h>
#include <nglwidgets/ngltreeitem.h>
#include <QModelIndex>
namespace InfrastructureManagement
{
struct SimpleRecordingData
{
QString name;
int32_t id = 0;
int32_t mainStructureElementId = 0;
bool hasRecordingOn = false;
bool shallHaveRecordingOn = false;
};
class SetRecordingDialogModel
: public NGLTreeModel
{
Q_OBJECT
public:
enum Columns
{
NAME
};
explicit SetRecordingDialogModel(QObject *parent = nullptr);
/**
* Handles the representation of data.
* In case of CheckStateRole only leafs will be handled.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] role role to which the data relates
*
*/
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override final;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ForeignDataInterface> &dataInterface);
void initData();
/**
* Sets only the leafs of the tree view to Qt::ItemIsUserCheckable.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
*
*/
Qt::ItemFlags flags(const QModelIndex &index) const override final;
/**
* Sets the check state data according to their check box in the internal model.
* CheckState data can be set for leafs only.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] value value to be set
* @param[in] role role to which the data relates (here especially Qt::CheckStateRole)
*
*/
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
void getChangedCams(QVector<SimpleRecordingData> &set, NGLTreeItem *treeItem = nullptr) const;
public Q_SLOTS:
void onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType);
private: // methods
static SimpleRecordingData toSimpleRecordingData(const MountingPoint &mountingPoint);
static SimpleRecordingData toSimpleRecordingData(const StructureElement &mountingPoint);
static bool hasCorrectType(const MountingPoint &mountingPoint);
void clearFromEmptyStructures(NGLTreeItem *treeItem);
static bool hasCam(const NGLTreeItem *treeItem);
private: // attributes
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_dataInterface;
LOGGER_T m_logger;
}; // class SetRecordingDialogModel
} // namespace InfrastructureManagement
Q_DECLARE_METATYPE(InfrastructureManagement::SimpleRecordingData)
@@ -0,0 +1,102 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author: kemayou_s$
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#include "ism_set_recording_dialog_requester.h"
#include <QGuiApplication>
#include <QMimeData>
#include <QTimer>
namespace InfrastructureManagement
{
/// SEModifyRequestCollector
SEModifyRequestCollector::SEModifyRequestCollector(std::shared_ptr<Interface::Ftc> &ftc, QObject *parent)
: QObject(parent)
, m_ftc(ftc)
{}
void SEModifyRequestCollector::addRequest(const int &buildingId, const StructureElementModifyRequest &request)
{
m_requests += QPair<int, InfrastructureManagement::StructureElementModifyRequest>(buildingId, request);
}
void SEModifyRequestCollector::cancel()
{
m_canceled = true;
}
void SEModifyRequestCollector::go()
{
next();
}
int SEModifyRequestCollector::count() const
{
return m_requests.count();
}
int SEModifyRequestCollector::failedCount() const
{
return m_failedCount;
}
void SEModifyRequestCollector::next()
{
if (m_requests.isEmpty())
{
emit finished(m_canceled);
return;
}
SEModifyRequester *requester = new SEModifyRequester;
const QPair<int, StructureElementModifyRequest> request(m_requests.takeFirst());
const int ri = request.first;
connect(requester, &SEModifyRequester::finished,
this, [this, ri](const QString &msg)
{
bool failed = (!msg.isEmpty());
if (failed)
{
m_failedCount++;
}
else
{
// ri.model->unchange(ri.rowId);
}
emit requestComplete(failed);
if (m_canceled)
m_requests.clear();
next();
});
auto go = [this, request, requester]()
{
m_ftc->structureElementModifyRequest(request.second, requester);
};
#ifdef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
{
QTimer::singleShot(3000, this, go);
return;
}
#endif
go();
}
}
@@ -0,0 +1,64 @@
#ifndef SEMODIFYREQUESTER_H
#define SEMODIFYREQUESTER_H
#include "ism_set_recording_dialog_model.h"
#include <InfrastructureManagement/ism_ftc.h>
#include <QObject>
#include <QVector>
#include <QPair>
namespace InfrastructureManagement
{
/// SEModifyRequester
class SEModifyRequester : public QObject,
public Interface::Ftc::StructureElementModifyReplyHandler
{
Q_OBJECT
public:
SEModifyRequester(): QObject() {} // do NOT parent!
void onStructureElementModifyReply(const Core::FunctionReplyObject &reply) override
{
if (reply.error())
emit finished(reply.translated());
else
emit finished({});
deleteLater();
}
signals:
void finished(const QString &msg);
};
/// SEModifyRequestCollector
class SEModifyRequestCollector : public QObject
{
Q_OBJECT
public:
SEModifyRequestCollector(std::shared_ptr<Interface::Ftc> &ftc, QObject *parent);
void addRequest(const int &buildingId, const InfrastructureManagement::StructureElementModifyRequest &request);
void cancel();
void go();
int count() const;
int failedCount() const;
private slots:
void next();
signals:
void finished(bool canceled);
void requestComplete(bool failed);
private:
QVector<QPair<int, InfrastructureManagement::StructureElementModifyRequest> > m_requests;
std::shared_ptr<Interface::Ftc> m_ftc;
bool m_canceled = false;
int m_failedCount = 0;
};
}// namespace InfrastructureManagement
#endif // SEMODIFYREQUESTER_H
@@ -0,0 +1,74 @@
/**
* @RDE_HEADER@
* GUI Plugin for AudioVideoConfig
* $Id$
* $HeadURL$
* $Author$
*
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#include "ism_audio_video_config_gui_plugin.h"
#include "SetRecording/ism_set_recording_dialog.h"
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_background_widget.h>
#include <LtsUtilsSettings/settings.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <InfrastructureManagement/logger.h>
#include <memory>
namespace InfrastructureManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("AudioVideoConfigPlugin"))
{}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsWidgets::PluginData plugin;
plugin.menuGroup = tr("Exercise Assignment");
plugin.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableSetRecordingDialog = ps->value(QStringLiteral("ism"),
QStringLiteral("enableSetRecordingDialog")).toBool();
if (enableSetRecordingDialog)
{
// Set Recording Dialog
plugin.menuText = tr("Set Recording");
plugin.identifier = QLatin1String("IsmAvcSetRecordingDialog");
plugin.menuIcon = QIcon(QLatin1String("icon:media-record.svg"));
plugin.createWidgetFunc = [this](QWidget * parent) -> LtsWidgets::LtsDialog *
{
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
std::shared_ptr<InfrastructureManagement::Interface::Ftc> ismFtc;
std::shared_ptr<ForeignDataInterface> ismDataIfc;
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc)
|| !m_session->getFtc<InfrastructureManagement::DataInterface>(ismFtc)
|| !m_session->getForeignDataInterface<DataInterface>(ismDataIfc))
{
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayoutWidget(), tr("The Infrastructure Management is not available!"), tr("Cannot open Set Recording"));
return nullptr;
}
return LtsWidgets::initDialog(new SetRecordingDialog(parent),
ismDtc, ismFtc, ismDataIfc);
};
ret.append(plugin);
}
return ret;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,70 @@
/**
* @RDE_HEADER@
* GUI Plugin for AudioVideoConfig
* $Id$
* $HeadURL$
* $Author$
*
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_audio_video_config_gui_plugin_interface.h>
namespace ExerciseManagement
{
namespace Interface
{
class Dtc;
}
}
namespace LtsUtils
{
class RequestHelper;
}
namespace InfrastructureManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ism.avc")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return ForeignAudioVideoConfigGuiInterface::pluginName(); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final
: public QObject
, public ForeignAudioVideoConfigGuiInterface
, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
QString menuGroup() const override { return tr("Training Voice Communication"); }
QVector<LtsWidgets::PluginData> getActions() override;
signals:
void signalSuccess();
};
} // namespace InfrastructureManagement
+12
View File
@@ -0,0 +1,12 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-10-28
#
add_subdirectory(ResourceManagement)
add_subdirectory(AudioVideoConfig)
add_subdirectory(IsmComboBox)
add_subdirectory(ExerciseAssignmentClassic)
@@ -0,0 +1,39 @@
#
# $Id: CMakeLists.txt 49595 2020-01-24 13:28:42Z hjl $
# $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/CMakeLists.txt $
# $Author: hjl $
#
# Created by Hannes Baeuerle, SLSE, 2017-06-29
#
SET(src
ism_exercise_assignment_classic_gui_plugin.cpp
#ism_exercise_assignment_dialog.h
ism_exercise_assignment_dialog.cpp
#ism_exercise_assignment_dialog_model.h
ism_exercise_assignment_dialog_model.cpp
)
NGL_WRAP_UI(src
ism_exercise_assignment_dialog.ui
)
NGL_ADD_LIBRARY(WS IsmExerciseAssignmentClassicGuiPlugin MODULE ${src})
NGL_TARGET_LINK_LIBRARIES(IsmExerciseAssignmentClassicGuiPlugin
NGLLogger
nglwidgets
LtsPrinting
LtsSession
LtsSessionData
LtsWidgets
LtsDataView
IsmDataPluginInterface
IsmShared
IsmExerciseAssignmentClassicGuiPluginInterface
ExmDataPluginInterface
LtsUtilsGuiDds
LtsUtilsSettings
)
NGL_INSTALL_TARGET(IsmExerciseAssignmentClassicGuiPlugin)
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* GUI Plugin for AudioVideoConfig
* $Id: ism_audio_video_config_gui_plugin.cpp 52254 2020-10-06 11:50:47Z wille_m $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ism_audio_video_config_gui_plugin.cpp $
* $Author: wille_m $
*
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#include "ism_exercise_assignment_classic_gui_plugin.h"
#include "ism_exercise_assignment_dialog.h"
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_background_widget.h>
#include <LtsUtilsSettings/settings.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <ExerciseManagement/exm_data_plugin_interface.h>
#include <InfrastructureManagement/logger.h>
#include <memory>
namespace InfrastructureManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("AudioVideoConfigPlugin"))
// , m_ismDtc(nullptr)
// , m_ismFtc(nullptr)
, m_exmDtc(nullptr)
// , m_ismDataInterface(nullptr)
{}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
LtsWidgets::PluginData plugin;
plugin.menuGroup = tr("Exercise Assignment");
plugin.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
plugin.menuText = tr("Exercise Assignment");
plugin.identifier = QLatin1String("IsmAvcExerciseAssignmentDialog_CLASSIC");
plugin.menuIcon = QIcon(QLatin1String("icon:set_exercise_process.svg"));
plugin.createWidgetFunc = [this](QWidget * parent) -> LtsWidgets::LtsDialog *
{
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
std::shared_ptr<InfrastructureManagement::Interface::Ftc> ismFtc;
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc)
|| !m_session->getFtc<InfrastructureManagement::DataInterface>(ismFtc))
{
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayoutWidget(), tr("The Infrastructure Management is not available!"), tr("Cannot open Exercise Assignment"));
return nullptr;
}
return LtsWidgets::initDialog(new ExerciseAssignmentDialog(m_session, parent),
ismDtc, ismFtc, m_exmDtc);
};
return {plugin};
}
bool InterfaceImpl::fetchInterfaces()
{
return /*m_session->getDtc<DataInterface>(m_ismDtc) &&
m_session->getFtc<DataInterface>(m_ismFtc) &&*/
m_session->getDtc<ExerciseManagement::DataInterface>(m_exmDtc)/* &&
m_session->getForeignDataInterface<DataInterface>(m_ismDataInterface)*/;
}
void InterfaceImpl::clearInterfaces()
{
//m_ismDataInterface = nullptr;
m_exmDtc = nullptr;
}
//void InterfaceImpl::executePayload(LtsWidgets::LtsBackgroundWidget *)
//{
// DEBUG_LOG(m_logger) << "executePayload";
// connect(this, &InterfaceImpl::signalSuccess,
// m_session, &LtsSession::LtsSession::slotExecuteNextPayload, Qt::QueuedConnection);
// emit signalSuccess();
//}
} // namespace InfrastructureManagement
@@ -0,0 +1,82 @@
/**
* @RDE_HEADER@
* GUI Plugin for AudioVideoConfig
* $Id: ism_audio_video_config_gui_plugin.h 58505 2022-11-28 15:41:44Z wille_m $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ism_audio_video_config_gui_plugin.h $
* $Author: wille_m $
*
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <InfrastructureManagement/ism_exercise_assignment_classic_gui_plugin_interface.h>
namespace ExerciseManagement
{
namespace Interface
{
class Dtc;
}
}
namespace LtsUtils
{
class RequestHelper;
}
namespace InfrastructureManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ism.eac")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return ForeignExerciseAssignmentClassicGuiInterface::pluginName(); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final
: public QObject
, public ForeignExerciseAssignmentClassicGuiInterface
, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
QString menuGroup() const override { return tr("Training Voice Communication"); }
bool fetchInterfaces() override;
void clearInterfaces() override;
QVector<LtsWidgets::PluginData> getActions() override;
// // be able to show exercise chooser
// int executionPriority() const override { return 9999; }
// void executePayload(LtsWidgets::LtsBackgroundWidget *mainBackground) override;
private: // attributes
// std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
// std::shared_ptr<InfrastructureManagement::Interface::Ftc> m_ismFtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
//std::shared_ptr<ForeignDataInterface> m_ismDataInterface;
signals:
void signalSuccess();
};
} // namespace InfrastructureManagement
@@ -0,0 +1,158 @@
/**
* @RDE_HEADER@
* The ExerciseAssignmentDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id: ism_exercise_assignment_dialog.cpp 57779 2022-08-03 08:07:45Z ojog_i $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog.cpp $
* $Author: ojog_i $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#include "ism_exercise_assignment_dialog.h"
#include "ui_ism_exercise_assignment_dialog.h"
#include "ism_exercise_assignment_dialog_model.h"
#include <LtsUtilsGuiDds/request_helper.h>
#include <LtsSession/lts_session.h>
#include <LtsPrinting/printing.h>
#include <QTreeView>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
namespace InfrastructureManagement
{
ExerciseAssignmentDialog::ExerciseAssignmentDialog(LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_session(session)
, m_ui(new Ui::ExerciseAssignmentDialog)
, m_ismDtc(nullptr)
, m_ismFtc(nullptr)
, m_exmDtc(nullptr)
, m_model(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("ExerciseAssignmentDialog"))
{
m_ui->setupUi(this);
m_ui->assetListView->setSelectionMode(QAbstractItemView::MultiSelection);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ExerciseAssignmentDialog::onPrint);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Exercise_Assignment"));
}
ExerciseAssignmentDialog::~ExerciseAssignmentDialog()
{
delete m_ui;
}
void ExerciseAssignmentDialog::retranslate()
{
translate(m_ui, tr("Exercise Assignment"));
}
bool ExerciseAssignmentDialog::init(const std::shared_ptr<Interface::Dtc> &ismDtc,
const std::shared_ptr<Interface::Ftc> &ismFtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc)
{
m_ismDtc = ismDtc;
m_ismFtc = ismFtc;
m_exmDtc = exmDtc;
delete m_model;
if (!m_ismFtc->enableInstrumentationAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT InstrumentationAssetModify of ISM";
return false;
}
if (!m_ismFtc->enableMainStructureElementModify())
{
ERROR_LOG(m_logger) << "Could not enable FT MainStructureElementModify of ISM";
return false;
}
if (!m_exmDtc->enableExercise())
{
ERROR_LOG(m_logger) << "Could not enable DT Exercise of EXM";
return false;
}
// Add all available exercises to comboBox
const QMap<qint32, ExerciseManagement::Exercise> exercises = m_exmDtc->exercises();
m_ui->cbExercises->addItem(QStringLiteral("-"), 0);
for (const auto &exercise : exercises)
m_ui->cbExercises->addItem(QString::fromStdString(exercise.name()), exercise.id());
m_ui->pbAssigned->setEnabled(false);
m_model = new ExerciseAssignmentDialogModel(this);
if (!m_model->initModel(m_ismDtc, m_exmDtc))
{
ERROR_LOG(m_logger) << "Could not init model";
delete m_model;
m_model = nullptr;
return false;
}
m_ui->assetListView->setModel(m_model);
connect(m_ui->assetListView, &LtsDataView::LtsDataView::selectionChanged,
this, &ExerciseAssignmentDialog::onSelectionChanged);
connect(m_ui->pbAssigned, &QPushButton::clicked,
this, &ExerciseAssignmentDialog::onAssignedClicked);
return true;
}
void ExerciseAssignmentDialog::onMainStructureElementModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void ExerciseAssignmentDialog::onAssignedClicked()
{
const QModelIndexList selectedIndexs = m_ui->assetListView->selectedRows();
if (selectedIndexs.size() < 1)
return;
for (const auto &index : selectedIndexs)
{
m_requestHelper->addRequest([this, index]()
{
MainStructureElementModifyRequest request;
MainStructureElement &req = request;
req = m_model->getRowData(index.row());
QJsonObject obj = QJsonDocument::fromJson(QByteArray::fromStdString(request.properties())).object();
// Exercise choose?
QJsonArray array;
if (m_ui->cbExercises->currentIndex() != 0)
array.push_back(m_ui->cbExercises->currentData().toInt());
obj.insert(QStringLiteral("available_in_exercise"), array);
request.properties(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
return m_ismFtc->mainStructureElementModifyRequest(request, this);
});
}
m_requestHelper->startRequests();
//m_requestHelper->startSingleRequest([this, request]() {return m_ismFtc->mainStructureElementModifyRequest(request, this);});
}
void ExerciseAssignmentDialog::onSelectionChanged()
{
const auto selectedIndexes = m_ui->assetListView->selectedRows();
m_ui->pbAssigned->setEnabled(!selectedIndexes.isEmpty());
m_ui->cbExercises->setCurrentIndex(0);
}
void ExerciseAssignmentDialog::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->assetListView->treeView());
}
} // namespace InfrastructureManagement
@@ -0,0 +1,68 @@
/**
* @RDE_HEADER@
* The AssetListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id: ism_exercise_assignment_dialog.h 45935 2019-03-08 08:36:11Z ehrlicher $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog.h $
* $Author: ehrlicher $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <ExerciseManagement/exm_dtc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/logger.h>
namespace Ui
{
class ExerciseAssignmentDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace InfrastructureManagement
{
class ExerciseAssignmentDialogModel;
class ExerciseAssignmentDialog
: public LtsWidgets::LtsDialog
, protected InfrastructureManagement::Interface::Ftc::MainStructureElementModifyReplyHandler
{
Q_OBJECT
public:
explicit ExerciseAssignmentDialog(LtsSession::LtsSession *session, QWidget *parent = nullptr);
~ExerciseAssignmentDialog();
bool init(const std::shared_ptr<Interface::Dtc> &ismDtc, const std::shared_ptr<Interface::Ftc> &ismFtc, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc);
void onMainStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override final;
private Q_SLOTS:
void onAssignedClicked();
void onSelectionChanged();
void onPrint();
private: // methods
void retranslate() override;
private: // attributes
LtsSession::LtsSession *m_session;
Ui::ExerciseAssignmentDialog *m_ui;
std::shared_ptr<Interface::Dtc> m_ismDtc;
std::shared_ptr<Interface::Ftc> m_ismFtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
ExerciseAssignmentDialogModel *m_model;
LtsUtils::RequestHelper *m_requestHelper;
LOGGER_T m_logger;
}; // class AssetListDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExerciseAssignmentDialog</class>
<widget class="QWidget" name="ExerciseAssignmentDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="assetListView"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbExercises">
<property name="text">
<string>Exercises:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbExercises">
<property name="currentText">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbAssigned">
<property name="text">
<string>Assign to selection</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,123 @@
/**
* @RDE_HEADER@
* The ExerciseAssignmentDialogModel provices data for AssetListDialog
* $Id: ism_exercise_assignment_dialog_model.cpp 49203 2019-12-17 09:50:35Z rudolphus_g $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog_model.cpp $
* $Author: rudolphus_g $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#include "ism_exercise_assignment_dialog_model.h"
#include <QtCore/QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
using namespace InfrastructureManagement;
ExerciseAssignmentDialogModel::ExerciseAssignmentDialogModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<MainStructureElement>(
{
tr("Name"),
tr("Assigned Exercise")
},
parent)
, m_dtc(nullptr)
, m_exmDtc(nullptr)
, m_logger(getLogger("ExerciseAssignmentDialogModel"))
{
}
ExerciseAssignmentDialogModel::~ExerciseAssignmentDialogModel()
{
}
QVariant ExerciseAssignmentDialogModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const MainStructureElement &currentMainStructureElement = m_vecData.at(index.row());
switch (index.column())
{
case NAME:
return m_dtc->getBuildingDisplayName(currentMainStructureElement.id());
case ASSIGNED_EXERCISES:
{
if (!currentMainStructureElement.properties().size())
return QChar(QLatin1Char('-'));
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(currentMainStructureElement.properties()), &parseError);
if (parseError.error != QJsonParseError::NoError)
{
INFO_LOG(m_logger) << "Could not parse JSON props of building with ID "
<< currentMainStructureElement.id()
<< ". Reason: "
<< parseError.errorString()
<< "; JSON: "
<< doc.toJson(QJsonDocument::Compact);
return QChar(QLatin1Char('-'));
}
QJsonArray arr = doc.object().value(QLatin1String("available_in_exercise")).toArray();
if (arr.isEmpty())
return QChar(QLatin1Char('-'));
QString exercise = QString::fromUtf8(QJsonDocument(arr).toJson(QJsonDocument::Compact));
exercise.remove(QLatin1Char('['));
exercise.remove(QLatin1Char(']'));
if (exercise.size())
{
int exId = exercise.toInt();
return QString::fromStdString(m_exmDtc->exercise(exId).name());
}
return QChar(QLatin1Char('-'));
}
}
return QVariant();
}
bool ExerciseAssignmentDialogModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc)
{
m_dtc = dtc;
m_exmDtc = exmDtc;
if (!m_dtc->enableInstrumentationAsset())
{
ERROR_LOG(m_logger) << "Could not enable Datatopic InstrumentationAsset of the Data Topic Client";
return false;
}
if (!m_exmDtc->enableExercise())
{
ERROR_LOG(m_logger) << "Could not enable Topic Exercise from Exercise Management DTC";
return false;
}
connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged,
this, &ExerciseAssignmentDialogModel::onDataChanged);
auto cb = [this](const InfrastructureManagement::MainStructureElement &mse)
{
onDataChanged(mse, DataModification::eAdded);
};
m_dtc->mainStructureElements(cb);
INFO_LOG(m_logger) << "initModel successful";
return true;
}
bool ExerciseAssignmentDialogModel::isFiltered(const InfrastructureManagement::MainStructureElement &data, DataModification modType) const
{
Q_UNUSED(modType);
return (data.structureElementTypeId() != InfrastructureManagement::StructureElementType::Building &&
data.structureElementTypeId() != InfrastructureManagement::StructureElementType::Announcement);
}
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* The ExerciseAssignmentDialogModel provices data for AssetListDialog
* $Id: ism_exercise_assignment_dialog_model.h 41411 2018-04-24 14:51:44Z ojog_i $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/iterations/22_01_homer/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog_model.h $
* $Author: ojog_i $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
*/
#pragma once
#include <ExerciseManagement/exm_dtc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <LtsWidgets/lts_abstract_table_model.h>
namespace InfrastructureManagement
{
class ExerciseAssignmentDialogModel final : public LtsWidgets::LtsAbstractTableModel<MainStructureElement>
{
Q_OBJECT
public:
explicit ExerciseAssignmentDialogModel(QObject *parent = nullptr);
~ExerciseAssignmentDialogModel();
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc);
protected:
bool isFiltered(const InfrastructureManagement::MainStructureElement &data, DataModification modType) const override;
private: // other
enum Columns
{
NAME,
ASSIGNED_EXERCISES
};
private: // attributes
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
LOGGER_T m_logger;
}; // class ExerciseAssignmentDialogModel
} // namespace InfrastructureManagement
Q_DECLARE_METATYPE(InfrastructureManagement::MainStructureElement)
@@ -0,0 +1,30 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-05-05
#
SET(ism_combobox_gui_SRCS
ism_combobox_gui_plugin.cpp
ism_combobox_gui_plugin.h
ism_combobox.cpp
ism_combobox.h
)
NGL_WRAP_UI(ism_combobox_gui_SRCS
)
NGL_ADD_LIBRARY(WS IsmComboBoxGuiPlugin MODULE ${ism_combobox_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(IsmComboBoxGuiPlugin
NGLLogger
IsmGuiComboboxPluginInterface
IsmDataPluginInterface
Qt5::Widgets
LtsWidgets
LtsSession
)
NGL_INSTALL_TARGET(IsmComboBoxGuiPlugin)
@@ -0,0 +1,99 @@
/**
* @RDE_HEADER@
* InfrastructureManagement - IsmComboBox Gui Plugin
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-16
*/
#include "ism_combobox.h"
#include <InfrastructureManagement/ism_translation.h>
#include <LtsUtilsCore/json_object.h>
namespace InfrastructureManagement
{
bool IsmComboBox::fill(LtsWidgets::LtsComboBox *cbx, IsmComboBoxType type, LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc, int filter)
{
Q_UNUSED(session);
cbx->clear();
switch (type)
{
case IsmComboBoxType::CbRadioStations:
{
auto cb = [cbx,filter](const InfrastructureManagement::MainStructureElement &mse)
{
if (mse.structureElementTypeId() == InfrastructureManagement::StructureElementType::RadioStation && !mse.isDeleted() && mse.id() > 0 )
{
const RadioStation &rs = RadioStation::fromMSE(mse);
if (((filter >= 0) && rs.radios.contains(static_cast<FrequencyBand>(filter))) ||
(filter < 0))
{
cbx->addItem(QString::fromStdString(mse.name()), mse.id());
cbx->setItemData(cbx->findData(mse.id()), rs.radioStationId, Qt::UserRole + 1);
}
}
};
dtc->mainStructureElements(cb);
break;
}
case IsmComboBoxType::CbApproachingPoints:
{
auto cb = [cbx](const InfrastructureManagement::MainStructureElement &mse)
{
if ((mse.structureElementTypeId() == InfrastructureManagement::StructureElementType::ApproachingPoint) && !mse.isDeleted() && (mse.id() > 0))
{
cbx->addItem(QString::fromStdString(mse.name()), mse.id());
cbx->setItemData(cbx->findData(mse.id()), mse.angle(), Qt::UserRole + 1);
}
};
dtc->mainStructureElements(cb);
break;
}
case IsmComboBoxType::CbScheduleStatus:
{
cbx->addItem(toString(ScheduleStatus::Active), ScheduleStatus::Active);
cbx->addItem(toString(ScheduleStatus::Inactive), ScheduleStatus::Inactive);
break;
}
case IsmComboBoxType::CbBridgeStatus:
{
cbx->addItem(toString(BridgeStatus::Intact), BridgeStatus::Intact);
cbx->addItem(toString(BridgeStatus::Broken), BridgeStatus::Broken);
}
case IsmComboBoxType::CbUnknown:
default:
break;
}
return cbx->count() > 0;
}
RadioStation RadioStation::fromMSE(const MainStructureElement &mse)
{
RadioStation rs;
rs.mse_id = mse.id();
rs.name = QString::fromStdString(mse.name());
LtsUtils::JsonObject jo = LtsUtils::JsonObject::fromJson(mse.properties());
LtsUtils::JsonArray radios = jo.valueOr<LtsUtils::JsonArray>("radios", {});
// The best and easiest solution is to iterate over the JsonArray right!?
// for (const QJsonValue &radioValues : qAsConst(radios))
// for (const JsonObject &radioObject : qAsConst(radios))
const QVector<LtsUtils::JsonObject> &radiosAsVector = radios.toVector<LtsUtils::JsonObject>();
for (const LtsUtils::JsonObject &radio : qAsConst(radiosAsVector))
{
FrequencyBand fb = static_cast<FrequencyBand>(radio.valueOr<int>("frequencyBand", -1));
int count = radio.valueOr<int>("count", 0);
if (fb != FrequencyBand::INVALID)
rs.radios.insert(fb,count);
}
rs.radioStationId = jo.valueOr<int>("stationId", 0);
return rs;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,61 @@
/**
* @RDE_HEADER@
* InfrastructureManagement - IsmComboBox Gui Plugin
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-16
*/
#pragma once
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_combo_box.h>
#include <InfrastructureManagement/logger.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <QMap>
#include <QString>
namespace InfrastructureManagement
{
enum IsmComboBoxType
{
CbUnknown = 0,
CbRadioStations,
CbApproachingPoints,
CbScheduleStatus,
CbBridgeStatus
};
// Keep in sync with avm_enums.h!
enum FrequencyBand
{
INVALID = -1,
VHF = 0,
UHF = 1,
HF = 2,
REL = 3
};
struct RadioStation
{
int mse_id;
int radioStationId;
QString name;
QMap<FrequencyBand, int> radios; // How many radios are there per type?
static RadioStation fromMSE(const MainStructureElement &mse);
};
// --------------------------------------------------------
// ComboBox
// --------------------------------------------------------
class IsmComboBox
{
public:
Q_REQUIRED_RESULT static bool fill(LtsWidgets::LtsComboBox *cbx,
IsmComboBoxType type,
LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc, int filter = -1);
};
} // namespace InfrastructureManagement
@@ -0,0 +1,70 @@
/**
* @RDE_HEADER@
* GUI Plugin for InfrastructureManagement - IsmComboBox
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-16
*/
#include "ism_combobox_gui_plugin.h"
namespace InfrastructureManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.IsmCombobox"))
, m_dtc(nullptr)
{}
bool InterfaceImpl::fetchInterfaces()
{
// if (!m_session->getDtc<InfrastructureManagement::DataInterface>(m_dtc))
// {
// DEBUG_LOG(m_logger) << "Failed to fetch Dtc InfrastructureManagement interface!";
// return false;
// }
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
}
bool InterfaceImpl::fillRadioStationsComboBox(LtsWidgets::LtsComboBox *cbx, int filter)
{
return fillIsmComboBox(cbx, IsmComboBoxType::CbRadioStations, filter);
}
bool InterfaceImpl::fillApproachingPointsComboBox(LtsWidgets::LtsComboBox *cbx)
{
return fillIsmComboBox(cbx, IsmComboBoxType::CbApproachingPoints);
}
bool InterfaceImpl::fillScheduleStatusComboBox(LtsWidgets::LtsComboBox *cbx)
{
return fillIsmComboBox(cbx, IsmComboBoxType::CbScheduleStatus);
}
bool InterfaceImpl::fillBridgeStatusComboBox(LtsWidgets::LtsComboBox *cbx)
{
return fillIsmComboBox(cbx, IsmComboBoxType::CbBridgeStatus);
}
//private
bool InterfaceImpl::fillIsmComboBox(LtsWidgets::LtsComboBox *cbx, IsmComboBoxType type, int filter)
{
if (!m_dtc && !m_session->getDtc<InfrastructureManagement::DataInterface>(m_dtc))
return false;
return IsmComboBox::fill(cbx, type, m_session, m_dtc, filter);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* Gui Plugin for InfrastructureManagement - IsmComboBox
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-16
*/
#pragma once
#include "ism_combobox.h"
#include <LtsSession/lts_session.h>
#include <InfrastructureManagement/logger.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_combobox_gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <QComboBox>
namespace InfrastructureManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ism.combobox")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("InfrastructureManagement.GuiPlugin.ComboBox"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Replay);
}
};
class InterfaceImpl final : public QObject, public ForeignGuiComboboxInterface, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override { return QString(); }
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise; }
// ForeignDataInterface
bool fillRadioStationsComboBox(LtsWidgets::LtsComboBox *cbx, int filter) override;
bool fillApproachingPointsComboBox(LtsWidgets::LtsComboBox *cbx) override;
bool fillScheduleStatusComboBox(LtsWidgets::LtsComboBox *cbx) override;
bool fillBridgeStatusComboBox(LtsWidgets::LtsComboBox *cbx) override;
private:
bool fillIsmComboBox(LtsWidgets::LtsComboBox *cbx, IsmComboBoxType type, int filter = -1);
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_dtc;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,126 @@
/**
* @RDE_HEADER@
* The ApproachingPointsDialog shows a list of approaching points
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#include "ism_approaching_point_list_dialog.h"
#include "ui_ism_approaching_point_list_dialog.h"
#include "ism_approaching_point_list_dialog_model.h"
#include "ism_edit_approaching_point_dialog.h"
#include <LtsSession/lts_session_data.h>
#include <LtsPrinting/printing.h>
#include <QTreeView>
namespace InfrastructureManagement
{
ApproachingPointsDialog::ApproachingPointsDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_session(session)
, m_ui(new Ui::ApproachingPointsDialog)
, m_model(nullptr)
, m_menuGroup(menuGroup)
, m_logger(getLogger("ApproachingPointsDialog"))
{
m_ui->setupUi(this);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ApproachingPointsDialog::onPrint);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Approach_Points"));
}
ApproachingPointsDialog::~ApproachingPointsDialog()
{
delete m_ui;
}
void ApproachingPointsDialog::retranslate()
{
translate(m_ui, tr("Approaching Points"));
}
void ApproachingPointsDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->approachingPointsView->setColumnsOrganiserEnabled(identifier(), true);
}
bool ApproachingPointsDialog::init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMap)
{
m_ftc = ftc;
m_sitMapIfc = sitMap;
delete m_model;
m_model = new ApproachingPointsDialogModel(this);
if (!m_model->initModel(dtc))
{
ERROR_LOG(m_logger) << "Could not init model";
delete m_model;
m_model = nullptr;
return false;
}
m_ui->approachingPointsView->setModel(m_model);
connect(m_ui->approachingPointsView, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &ApproachingPointsDialog::onItemDoubleClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &ApproachingPointsDialog::onItemDoubleClicked);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, true);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &ApproachingPointsDialog::onAddApproachingPoint);
#ifndef LTS_DEBUG
m_ui->approachingPointsView->hideColumn(ApproachingPointsDialogModel::Columns::Id);
#endif
return true;
}
void ApproachingPointsDialog::onItemDoubleClicked()
{
QModelIndex currentIndex = m_ui->approachingPointsView->currentIndex();
if (!currentIndex.isValid())
return;
EditApproachingPointDialog *dialog = new EditApproachingPointDialog(this);
MainStructureElement approachingPoint = m_model->getRowData(currentIndex.row());
if (!dialog->init(m_ftc, m_sitMapIfc, approachingPoint))
{
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("EditApproachingPoint%1").arg(approachingPoint.id()), LtsWidgets::LayoutArea::eDialogTab);
}
void ApproachingPointsDialog::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->approachingPointsView->treeView() );
}
void ApproachingPointsDialog::onAddApproachingPoint()
{
QModelIndex currentIndex = m_ui->approachingPointsView->currentIndex();
EditApproachingPointDialog *dialog = new EditApproachingPointDialog(this);
MainStructureElement approachingPoint = m_model->getRowData(currentIndex.row());
approachingPoint.id(0);
if (!dialog->init(m_ftc, m_sitMapIfc, approachingPoint))
{
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("AddApproachingPoint"), LtsWidgets::LayoutArea::eDialogTab);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,72 @@
/**
* @RDE_HEADER@
* The ApproachingPointsDialog shows a list of approaching points
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/logger.h>
#include <memory>
namespace Ui
{
class ApproachingPointsDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace SituationMap
{
class ForeignGuiInterface;
}
namespace InfrastructureManagement
{
namespace Interface
{
class Dtc;
class Ftc;
}
class ApproachingPointsDialogModel;
class ApproachingPointsDialog
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit ApproachingPointsDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~ApproachingPointsDialog();
bool init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMap);
private Q_SLOTS:
void onItemDoubleClicked();
void onPrint();
void onAddApproachingPoint();
private:
void retranslate() override;
void tableColumnOrganiserSetting() override;
LtsSession::LtsSession *m_session;
Ui::ApproachingPointsDialog *m_ui;
ApproachingPointsDialogModel *m_model;
QString m_menuGroup;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapIfc;
LOGGER_T m_logger;
}; // class ApproachingPointsDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ApproachingPointsDialog</class>
<widget class="QWidget" name="ApproachingPointsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string>Approaching Points</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="LtsDataView::LtsDataView" name="approachingPointsView"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,114 @@
/**
* @RDE_HEADER@
* The ApproachingPointsDialogModel provides data for ApproachingPointsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#include "ism_approaching_point_list_dialog_model.h"
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <InfrastructureManagement/ism_translation.h>
#include <LtsSession/lts_session.h>
#include <QDateTime>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QJsonObject>
#include <QJsonDocument>
namespace InfrastructureManagement
{
ApproachingPointsDialogModel::ApproachingPointsDialogModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<MainStructureElement>({tr("Id"),
tr("Name"),
tr("Description"),
tr("Position"),
tr("Departure Direction"),
tr("Special Type"),
tr("Properties")},
parent)
, m_logger(getLogger("ApproachingPointsDialogModel"))
{
}
QVariant ApproachingPointsDialogModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const MainStructureElement &currentPoint = m_vecData.at(index.row());
switch (index.column())
{
case Id:
return currentPoint.id();
case Name:
return QString::fromStdString(currentPoint.name());
case Description:
{
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(currentPoint.description()));
const QString jsonKey = QLatin1String("description");
if (!doc.isObject())
return QVariant();
return doc.object().value(jsonKey).toString();
}
case Position:
return LtsCoordTrans::mgrsFromGeographic(currentPoint.geoPosition().lon(), currentPoint.geoPosition().lat());
case Orientation:
return calculateCardinalDirection(currentPoint.angle());
}
return QVariant();
}
bool ApproachingPointsDialogModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc)
{
connect(dtc.get(), &Interface::Dtc::mainStructureElementChanged,
this, &ApproachingPointsDialogModel::onDataChanged);
auto cb = [this](const InfrastructureManagement::MainStructureElement &mse)
{
onDataChanged(mse, DataModification::eAdded);
};
dtc->mainStructureElements(cb);
INFO_LOG(m_logger) << "initModel successful";
return true;
}
QString ApproachingPointsDialogModel::calculateCardinalDirection(double degree, bool longVersion) const
{
int value = (int) ((degree / 45) + 0.5) % 8;
switch (value)
{
case 0:
return longVersion ? tr("North") : tr("N");
case 1:
return longVersion ? tr("North-East") : tr("NE");
case 2:
return longVersion ? tr("East") : tr("E");
case 3:
return longVersion ? tr("South-East") : tr("SE");
case 4:
return longVersion ? tr("South") : tr("S");
case 5:
return longVersion ? tr("South-West") : tr("SW");
case 6:
return longVersion ? tr("West") : tr("W");
case 7:
return longVersion ? tr("North-West") : tr("NW");
}
return QString();
}
bool ApproachingPointsDialogModel::isFiltered(const InfrastructureManagement::MainStructureElement &data, DataModification modType) const
{
Q_UNUSED(modType);
return (data.structureElementTypeId() != InfrastructureManagement::StructureElementType::ApproachingPoint);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* The ApproachingPointsDialogModel provides data for ApproachingPointsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <LtsWidgets/lts_abstract_table_model.h>
namespace InfrastructureManagement
{
class ApproachingPointsDialogModel : public LtsWidgets::LtsAbstractTableModel<MainStructureElement>
{
Q_OBJECT
public:
explicit ApproachingPointsDialogModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc);
QString calculateCardinalDirection(double degree, bool longVersion = true) const;
enum Columns
{
Id,
Name,
Description,
Position,
Orientation
};
protected:
bool isFiltered(const InfrastructureManagement::MainStructureElement &data, DataModification modType) const override;
private: // attributes
LOGGER_T m_logger;
}; // class ApproachingPointsDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,142 @@
/**
* @RDE_HEADER@
* The EditApproachingPointDialog offers an UI to edit an Approaching Point
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#include "ism_edit_approaching_point_dialog.h"
#include "ui_ism_edit_approaching_point_dialog.h"
#include <LtsSession/lts_session.h>
#include <InfrastructureManagement/ism_translation.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <QJsonDocument>
namespace InfrastructureManagement
{
EditApproachingPointDialog::EditApproachingPointDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ui(new Ui::EditApproachingPointDialog)
, m_ftc(nullptr)
, m_sitMapGuiIfc(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("EditApproachingPointDialog"))
{
m_ui->setupUi(this);
fillCbDepartureDirection();
m_uiRequirements->addRequirement({m_ui->lblPosition, [this]() { return !m_ui->positionEdit->coordinate().isNull(); }});
m_uiRequirements->addRequirement({m_ui->lblName, [this]() { return !m_ui->leName->text().isEmpty(); }});
connect(m_ui->pbClear, &QPushButton::clicked,
m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Approach_Points"));
}
EditApproachingPointDialog::~EditApproachingPointDialog()
{
delete m_ui;
}
void EditApproachingPointDialog::retranslate()
{
translate(m_ui, m_approachingPoint, tr("Approaching Point"));
}
bool EditApproachingPointDialog::init(const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMap,
const MainStructureElement &approachingPoint)
{
m_ftc = ftc;
m_sitMapGuiIfc = sitMap;
if (m_sitMapGuiIfc)
connect(m_ui->pbPosition, &QPushButton::clicked, this, &EditApproachingPointDialog::getPosition);
else
m_ui->pbPosition->setEnabled(false);
setData(approachingPoint);
return true;
}
bool EditApproachingPointDialog::apply()
{
return m_requestHelper->startSingleRequest([this]()
{
MainStructureElementModifyRequest request;
request.id(m_approachingPoint.id());
request.name(m_ui->leName->text().toStdString());
request.angle(m_ui->cbDepartureDirection->currentData().toDouble());
request.properties("{}");
request.structureElementId(m_approachingPoint.structureElementId());
request.structureElementTypeId(InfrastructureManagement::StructureElementType::ApproachingPoint);
QJsonObject objDescription;
objDescription.insert(QLatin1String("description"), m_ui->leDescription->text());
request.description(QJsonDocument(objDescription).toJson(QJsonDocument::Compact).toStdString());
const Core::GeoPosition pos(m_ui->positionEdit->coordinate().x(),m_ui->positionEdit->coordinate().y(), 0);
request.geoPosition(pos);
// fill in structure element (only one, needed for mse/se relationsships)
if (m_approachingPoint.id() == 0)
{
StructureElement seData;
seData.name(request.name());
seData.displayName(request.name());
seData.structureElementTypeId(InfrastructureManagement::StructureElementType::ApproachingPoint);
seData.mountingPointTypeId(InfrastructureManagement::MountingPointType::Unknown);
seData.properties("{}");
request.elements().resize(1, seData);
request.childParentRelations().resize(1, -1);
}
return m_ftc->mainStructureElementModifyRequest(request, this);
});
}
void EditApproachingPointDialog::fillCbDepartureDirection()
{
m_ui->cbDepartureDirection->insertItem(0,tr("North"),0);
m_ui->cbDepartureDirection->insertItem(1,tr("North-East"),45);
m_ui->cbDepartureDirection->insertItem(2,tr("East"),90);
m_ui->cbDepartureDirection->insertItem(3,tr("South-East"),135);
m_ui->cbDepartureDirection->insertItem(4,tr("South"),180);
m_ui->cbDepartureDirection->insertItem(5,tr("South-West"),225);
m_ui->cbDepartureDirection->insertItem(6,tr("West"),270);
m_ui->cbDepartureDirection->insertItem(7,tr("North-West"),315);
}
void EditApproachingPointDialog::setData(const MainStructureElement &approachingPoint)
{
m_approachingPoint = approachingPoint;
m_ui->leName->setText(QString::fromStdString(m_approachingPoint.name()));
QJsonObject objDescription = QJsonDocument::fromJson(QByteArray::fromStdString(m_approachingPoint.description())).object();
QString strDescription = objDescription.value(QLatin1String("description")).toString();
m_ui->leDescription->setText(strDescription);
QPointF pos(m_approachingPoint.geoPosition().lon(), m_approachingPoint.geoPosition().lat());
if (!pos.isNull())
m_ui->positionEdit->setCoordinate(pos);
m_ui->cbDepartureDirection->setCurrentIndex( (int) ((approachingPoint.angle() / 45) + 0.5) % 8);
}
void EditApproachingPointDialog::getPosition()
{
if (!m_sitMapGuiIfc) //sanity
return;
m_sitMapGuiIfc->getCoordinate(m_ui->positionEdit, SLOT(setCoordinate(QPointF)), nullptr);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,72 @@
/**
* @RDE_HEADER@
* The EditApproachingPointDialog offers an UI to edit an Approaching Point
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2018-01-17
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/logger.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace LtsWidgets
{
class LtsProgressDialogHelper;
}
namespace Ui
{
class EditApproachingPointDialog;
}
namespace SituationMap
{
class ForeignGuiInterface;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class EditApproachingPointDialog
: public LtsWidgets::LtsDialog
, protected Interface::Ftc::MainStructureElementModifyReplyHandler
{
Q_OBJECT
public:
explicit EditApproachingPointDialog(QWidget *parent = nullptr);
~EditApproachingPointDialog();
bool init(const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMap,
const MainStructureElement &approachingPoint = MainStructureElement());
void onMainStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
private slots:
void getPosition();
private:
void retranslate() override;
void fillCbDepartureDirection();
void setData(const MainStructureElement &approachingPoint);
bool apply() override final;
Ui::EditApproachingPointDialog *m_ui;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
MainStructureElement m_approachingPoint;
LtsUtils::RequestHelper *m_requestHelper;
LOGGER_T m_logger;
}; // class EditApproachingPointDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditApproachingPointDialog</class>
<widget class="QWidget" name="EditApproachingPointDialog">
<property name="windowTitle">
<string notr="true">Edit Approaching Point</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="lblDescription">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="leDescription"/>
</item>
<item row="3" column="2" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="cbDepartureDirection"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblPosition">
<property name="text">
<string>Position:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="LtsCoordWidget::LtsCoordWidget" name="positionEdit"/>
</item>
<item>
<widget class="QPushButton" name="pbPosition">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/position.svg</normaloff>:/style/position.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClear">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/remove.svg</normaloff>:/style/remove.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="lblOrientation">
<property name="text">
<string>Departure Direction:</string>
</property>
</widget>
</item>
<item row="2" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLineEdit" name="leName"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsCoordWidget::LtsCoordWidget</class>
<extends>QWidget</extends>
<header>LtsCoordTrans/lts_coord_widget.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leName</tabstop>
<tabstop>leDescription</tabstop>
<tabstop>positionEdit</tabstop>
<tabstop>pbPosition</tabstop>
<tabstop>pbClear</tabstop>
<tabstop>cbDepartureDirection</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,866 @@
/**
* @RDE_HEADER@
* The AssetListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_asset_list_dialog.h"
#include "ui_ism_asset_list_dialog.h"
#include "ism_asset_list_dialog_model.h"
#include <InfrastructureManagement/ism_operator_rights.h>
#include <InfrastructureManagement/ism_translation.h>
#include <ComponentMonitor/cmo.hpp>
#include <LtsSession/lts_session_data.h>
#include <LtsPrinting/printing.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFileDialog>
#include <QTreeView>
#include <QTextStream>
#include <QMenu>
#include <QAction>
#include <QTimer>
#include <vector>
namespace InfrastructureManagement
{
static QHash<int, QString> &INSTRUMENTATION_ASSET_STATES()
{
static QHash<int, QString> s_ret
{
{InstrumentationAssetState_def::Unmounted, QLatin1String("Unmounted")},
{InstrumentationAssetState_def::Mounted, QLatin1String("Mounted")},
{InstrumentationAssetState_def::Defect, QLatin1String("Defect")}
};
return s_ret;
}
AssetListDialog::AssetListDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_session(session)
, m_model(nullptr)
, m_menuGroup(menuGroup)
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper())
, m_ui(new Ui::AssetListDialog)
, m_logger(getLogger("AssetListDialog"))
{
m_ui->setupUi(this);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &AssetListDialog::onPrint);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Asset_List"));
}
AssetListDialog::~AssetListDialog()
{
if (m_hostsForUpdateNotifiy)
m_hostsForUpdateNotifiy->stop();
if(m_editAssetDialog!=nullptr)
{
m_editAssetDialog->deleteLater();
}
delete m_ui;
delete m_model;
}
void AssetListDialog::retranslate()
{
translate(m_ui, tr("Asset List"));
}
bool AssetListDialog::apply()
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Export)->setEnabled(true);
bool enabled = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SystemConfiguration);
m_buttonBox->getButton(LtsWidgets::DialogButton::Import)->setEnabled(enabled);
InstrumentationAsset asset;
for (int i = 0; i < m_model->rowCount(); ++i)
{
if (!rowContainsAlteredData(m_model->alteredRows().at(i)))
continue;
asset = m_model->getRowData(i);
InstrumentationAssetModifyRequest request(asset.id(),
asset.name(),
asset.mountingPointTypeId(),
asset.barcode(),
asset.hostname(),
asset.properties(),
asset.assetStateId(),
asset.lastUpdated(),
asset.availableInExercise());
m_requestHelper->addRequest([request, this]()
{
return m_ftc->instrumentationAssetModifyRequest(request, this);
});
}
m_model->removeBackgroundHighlighting();
bool ret = m_requestHelper->startRequests();
if(ret)
{
m_hasImportedAsset = false;
}
return ret;
}
void AssetListDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->assetListView->setColumnsOrganiserEnabled(identifier(), true);
}
/**
* @brief AssetListDialog::getExportString
* @param exp enum class, that informs about the selected filtering option.
* @param type gives the selected type in case of filtering by specific type, otherwise it is empty and unused.
* @return a vector containing all filtered rows as string
*/
QVector<QString> AssetListDialog::getExportString(const AssetFilterDialog::Export &exp, const QString &type) const
{
QVector<QString> vecOut;
switch (exp)
{
// ----- CASE ALL -----
case AssetFilterDialog::Export::eAll:
{
vecOut.reserve(m_model->rowCount());
for (int i = 0; i < m_model->rowCount(); ++i)
vecOut << exportData(m_model->getRowData(i));
break;
}// all end
// ----- CASE SELECTED -----
case AssetFilterDialog::Export::eSelected:
{
const auto idxList = m_ui->assetListView->selectedRows();
vecOut.reserve(idxList.size());
for (const QModelIndex &idx : idxList)
vecOut << exportData(m_model->getRowData(idx.row()));
break;
} // selected end
// ----- CASE SPECIFIC TYPE -----
case AssetFilterDialog::Export::eSpecificType:
{
vecOut.reserve(m_model->rowCount() / 10);
for (int i = 0; i < m_model->rowCount(); ++i)
{
const InstrumentationAsset &ia = m_model->getRowData(i);
if (toString(ia.mountingPointTypeId()) == type)
vecOut << exportData(ia);
}
break;
} // specific type end
} // switch end
return vecOut;
}
/**
* @brief AssetListDialog::exportData
* creates a string from the given InstrumentationAsset.
* @param ia InstrumentationAsset contains several propertys.
* @param separator the separator that is going to separate several items in the string.
* @return contains every property of the given InstrumentationAsset, separated by the given separator.
* @see importData()
*/
QString AssetListDialog::exportData(const InstrumentationAsset &ia, const QString &separator)
{
const QByteArray &properties = QByteArray::fromRawData(ia.properties().c_str(), ia.properties().size());
const QJsonDocument doc(QJsonDocument::fromJson(properties));
const QJsonObject obj(doc.object());
const QString &name = QString::fromStdString(ia.name());
const int nameSep = name.lastIndexOf(QLatin1Char('_'));
const QString &dmc = QString::fromStdString(ia.barcode());
const QString &tkz = name.mid(0, nameSep);
const QString &snr = nameSep >= 0 ? name.mid(nameSep + 1) : QString();
const QString &mac = obj.value(QStringLiteral("mac")).toString();
const QString &status = INSTRUMENTATION_ASSET_STATES().value(ia.assetStateId().underlying());
const QString &bz = ia.isUsed() ? QStringLiteral("Mounted") : QStringLiteral("Unmounted");
const QString &oc = QString::number(obj.value(QStringLiteral("opticalCode")).toInt());
const QString &ls = obj.value(QStringLiteral("hasSpeaker")).toBool() ? QStringLiteral("1") : QStringLiteral("0");
const QString &mf = obj.value(QStringLiteral("hasMicrophone")).toBool() ? QStringLiteral("1") : QStringLiteral("0");
const QString &vapix = obj.value(QStringLiteral("type")).toString() == QStringLiteral("vapix") ? QStringLiteral("1") : QStringLiteral("0");
const QString &user = obj.value(QStringLiteral("username")).toString();
const QString &pass = obj.value(QStringLiteral("password")).toString();
const QString &props = QString::fromUtf8(properties);
const QString &lastMod = QDateTime::fromMSecsSinceEpoch(ia.lastUpdated()).toString();
return QStringList({dmc, tkz, snr, mac, status, bz, oc, ls, mf, vapix, user, pass, props, lastMod}).join(separator);
}
static std::string unquote(const QStringRef &in)
{
if (!in.startsWith(QLatin1Char('"')) && !in.endsWith(QLatin1Char('"')))
return in.toString().toStdString();
QString out = in.mid(1, in.length() - 2).toString();
out.replace(QStringLiteral("\"\""), QStringLiteral("\""));
return out.toStdString();
}
/**
* @brief AssetListDialog::importData
* creates an InstrumentationAsset from the given stringlist.
* @param segments list of all segments of an InstrumentationAsset.
* @return InstrumentationAsset.
* @see exportData()
*/
static inline void setJson(QJsonObject &obj, const QString &key, bool bVal)
{
if (!bVal)
obj.remove(key);
else
obj[key] = bVal;
}
static inline void setJson(QJsonObject &obj, const QString &key, const QStringRef &val)
{
if (val.isEmpty())
obj.remove(key);
else
obj[key] = val.toString();
}
static inline void setJson(QJsonObject &obj, const QString &key, const QString &val)
{
setJson(obj, key, QStringRef(&val));
}
InstrumentationAsset AssetListDialog::importData(const QVector<QStringRef> &segments, bool *bOk) const
{
if (bOk)
*bOk = true;
const int len = segments.size();
const QStringRef &dmc = segments.at(0);
const QStringRef &tkz = segments.at(1);
const QStringRef &snr = segments.at(2);
const QStringRef &mac = segments.at(3);
const QStringRef &status = segments.at(4);
//const QString &bz = segments.at(5);
const QStringRef &oc = segments.at(6);
const QStringRef &ls = segments.at(7);
const QStringRef &mf = segments.at(8);
const QStringRef &vapix = segments.at(9);
const QStringRef &user = len > 10 ? segments.at(10) : QStringRef();
const QStringRef &pass = len > 11 ? segments.at(11) : QStringRef();
const QStringRef &props = len > 12 ? segments.at(12) : QStringRef();
//const QString &lastMod = len > 13 ? segments.at(13) : QStringRef();
const QJsonDocument doc(QJsonDocument::fromJson(props.toUtf8()));
QJsonObject obj(doc.object());
setJson(obj, QStringLiteral("mac"), mac);
setJson(obj, QStringLiteral("opticalCode"), oc);
setJson(obj, QStringLiteral("hasSpeaker"), (ls.isEmpty() || ls == QLatin1String("0")) ? false : true);
setJson(obj, QStringLiteral("hasMicrophone"), (mf.isEmpty() || mf == QLatin1String("0")) ? false : true);
setJson(obj, QStringLiteral("type"), (vapix.isEmpty() || vapix == QLatin1String("0")) ? QString() : QStringLiteral("vapix"));
setJson(obj, QStringLiteral("username"), user);
setJson(obj, QStringLiteral("password"), pass);
const std::string snrStd = unquote(snr);
const std::string tkzStd = unquote(tkz);
InstrumentationAsset asset;
asset.barcode() = unquote(dmc);
asset.name() = snrStd.empty() ? tkzStd : std::string(tkzStd + '_' + snrStd);
asset.assetStateId(static_cast<InstrumentationAssetState_def::type>(INSTRUMENTATION_ASSET_STATES().key(status.toString())));
asset.properties() = QJsonDocument(obj).toJson(QJsonDocument::Compact).constData();
// mountingPointTypeId is in DataMatrixCode
if (dmc.startsWith(QLatin1String("GSM")))
asset.mountingPointTypeId(MountingPointType::BuildingSensorModule);
else if (dmc.startsWith(QLatin1String("KAA")))
asset.mountingPointTypeId(MountingPointType_def::OutdoorCamera);
else if (dmc.startsWith(QLatin1String("KAI")))
asset.mountingPointTypeId(MountingPointType_def::IndoorCamera);
else if (dmc.startsWith(QLatin1String("OPS")))
asset.mountingPointTypeId(MountingPointType_def::IndoorIPS);
else if (dmc.startsWith(QLatin1String("WD_")))
asset.mountingPointTypeId(MountingPointType_def::EffectGenerationControlUnit);
else
{
if (bOk)
*bOk = false;
WARNING_LOG(m_logger) << "Could not determine mounting point type from barcode: " << dmc.toString();
}
return asset;
}
/**
* @brief AssetListDialog::updateInstrumentationAsset
* compares the name and the mountingPointTypeId of given InstrumentationAsset asset with the ones of every InstrumentationAsset that
* is already present in the model and if it is found, it is gonna update.
* @param asset InstrumentationAsset.
* @return true on found and updated, false on unlocated.
*/
bool AssetListDialog::updateInstrumentationAsset(const InstrumentationAsset &asset) const
{
InstrumentationAsset ia = asset;
int rowCount = m_model->rowCount();
for (int i = 0; i < rowCount; ++i)
{
InstrumentationAsset iaModelSide = m_model->getRowData(i);
if ((iaModelSide.name() == ia.name()) &&
(iaModelSide.mountingPointTypeId() == ia.mountingPointTypeId()))
{
ia.id(iaModelSide.id());
QHash<int, bool> alteredCells;
QHash<int, QString> alteredValues;
// NAME
if (ia.name() != iaModelSide.name())
{
alteredCells.insert(AssetListDialogModel::NAME, true);
alteredValues.insert(AssetListDialogModel::NAME, m_model->data(m_model->index(i, AssetListDialogModel::NAME), Qt::DisplayRole).toString());
}
else
{
alteredCells.insert(AssetListDialogModel::NAME, false);
alteredValues.insert(AssetListDialogModel::NAME, QString::fromStdString(ia.name()));
}
// TYPE
if (ia.mountingPointTypeId() != iaModelSide.mountingPointTypeId())
{
alteredCells.insert(AssetListDialogModel::TYPE, true);
alteredValues.insert(AssetListDialogModel::TYPE, m_model->data(m_model->index(i, AssetListDialogModel::TYPE), Qt::DisplayRole).toString());
}
else
{
alteredCells.insert(AssetListDialogModel::TYPE, false);
alteredValues.insert(AssetListDialogModel::TYPE, QString::fromStdString(ia.name()));
}
// BARCODE
if (ia.barcode() != iaModelSide.barcode())
{
alteredCells.insert(AssetListDialogModel::BARCODE, true);
alteredValues.insert(AssetListDialogModel::BARCODE, m_model->data(m_model->index(i, AssetListDialogModel::BARCODE), Qt::DisplayRole).toString());
}
else
{
alteredCells.insert(AssetListDialogModel::BARCODE, false);
alteredValues.insert(AssetListDialogModel::BARCODE, QString::fromStdString(ia.name()));
}
// HOSTNAME
if (ia.hostname() != iaModelSide.hostname())
{
alteredCells.insert(AssetListDialogModel::HOSTNAME, true);
alteredValues.insert(AssetListDialogModel::HOSTNAME, m_model->data(m_model->index(i, AssetListDialogModel::HOSTNAME), Qt::DisplayRole).toString());
}
else
{
alteredCells.insert(AssetListDialogModel::HOSTNAME, false);
alteredValues.insert(AssetListDialogModel::HOSTNAME, QString::fromStdString(ia.name()));
}
// PROPERTIES
if (ia.properties() != iaModelSide.properties())
{
alteredCells.insert(AssetListDialogModel::PROPERTIES, true);
alteredValues.insert(AssetListDialogModel::PROPERTIES, m_model->data(m_model->index(i, AssetListDialogModel::PROPERTIES), Qt::DisplayRole).toString());
}
else
{
alteredCells.insert(AssetListDialogModel::PROPERTIES, false);
alteredValues.insert(AssetListDialogModel::PROPERTIES, QString::fromStdString(ia.name()));
}
m_model->setAlteredCells(i, alteredCells);
// for(const int col : m_model->previousValues(i).keys())
// alteredValues.insert(col, m_model->data(m_model->index(i, col), Qt::DisplayRole).toString());
m_model->setPreviousValues(i, alteredValues);
ia.assetStateId(iaModelSide.assetStateId());
ia.lastUpdated(iaModelSide == ia ? iaModelSide.lastUpdated() : QDateTime::currentMSecsSinceEpoch());
m_model->setRowData(i, ia);
return true;
}
}
return false;
}
/**
* @brief AssetListDialog::onSelectionChanged
* is called on selection-change of the listview.
* @param selected a list of all selected items; unused.
* @param deselected a list of all deselected items; unused.
*/
void AssetListDialog::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
Q_UNUSED(selected);
Q_UNUSED(deselected);
bool enabled = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SystemConfiguration);
if (m_ui->assetListView->selectionModel()->selectedRows().size() < 1)
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(false);
}
else
{
if(m_ui->assetListView->selectionModel()->selectedRows().size() == 1)
{
InstrumentationAsset asset = m_model->assetByIndex(m_ui->assetListView->currentIndex());
StructureElement se;
if(m_dtc->getStructureElementInMntPointAssetByAssetId(asset.id(), se) && enabled)
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(true);
}
else
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(false);
}
}
else
{
if (enabled)
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(true);
}
if (enabled)
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(true);
}
}
bool AssetListDialog::init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ComponentMonitor::Interface::Dtc> cmoDtc,
const std::shared_ptr<ComponentMonitor::Interface::Ftc> cmoFtc
)
{
m_dtc = dtc;
m_ftc = ftc;
m_cmoDtc = cmoDtc;
m_cmoFtc = cmoFtc;
if (!m_ftc->enableStructureElementModify())
{
ERROR_LOG(m_logger) << "Could not enable FT StructureElementModify of ISM";
return false;
}
if (!m_ftc->enableMountingPointAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT MountingPointAssetModify of ISM";
return false;
}
if (!m_ftc->enableMountingPointAssetRemove())
{
ERROR_LOG(m_logger) << "Could not enable FT MountingPointAssetRemove of ISM";
return false;
}
if (!m_ftc->enableInstrumentationAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT InstrumentationAssetModify of ISM";
return false;
}
if (!m_ftc->enableInstrumentationAssetUnmount())
{
ERROR_LOG(m_logger) << "Could not enable FT InstrumentationAssetUnmount of ISM";
return false;
}
if (!m_cmoFtc->enableTriggerUpdate())
{
ERROR_LOG(m_logger) << "Could not enable FT TriggerUpdate of CMO";
return false;
}
if(m_ftc->enableInstrumentationAssetSetState() == false)
{
ERROR_LOG(m_logger)<<"Couldn't enable InstrumentationAssetSetState";
return false;
}
delete m_model;
m_model = new AssetListDialogModel(this);
connect(m_model, &AssetListDialogModel::dataAvailable, this, &AssetListDialog::enaDisaBtnBoxBtns);
if (!m_model->initModel(m_dtc, m_cmoDtc))
{
ERROR_LOG(m_logger) << "Could not init model";
delete m_model;
m_model = nullptr;
return false;
}
m_ui->assetListView->setModel(m_model);
m_ui->assetListView->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);
// connect(m_ui->assetListView, &LtsDataView::LtsDataView::signalDoubleClicked,
// this, &AssetListDialog::onItemDoubleClicked);
connect(m_ui->assetListView, &LtsDataView::LtsDataView::selectionChanged,
this, &AssetListDialog::onSelectionChanged);
connect(m_requestHelper, &LtsUtils::RequestHelper::signalQuitLoop, m_model, [this]()
{
m_model->initModel(m_dtc, m_cmoDtc);
});
// delay trigger update buttonbox to void multiple calls
m_updateBtnBoxBtns = new QTimer(this);
m_updateBtnBoxBtns->setSingleShot(true);
m_updateBtnBoxBtns->setInterval(1000);
connect(m_updateBtnBoxBtns, &QTimer::timeout, this, &AssetListDialog::onInstrumentationAssetChanged);
connect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged,
this, [&]{ m_updateBtnBoxBtns->start(); }, Qt::UniqueConnection);
//
// ContextMen
m_actionMenu = new QMenu(this);
m_updateAction = new QAction(tr("Trigger Reachability Update"), this);
m_actionMenu->addAction(m_updateAction);
connect(m_updateAction, &QAction::triggered, this, &AssetListDialog::onReachabilityUpdateAction);
m_ui->assetListView->setContextMenuPolicyPerView(LtsDataView::LtsDataView::Page::TABLE, Qt::CustomContextMenu);
connect(m_ui->assetListView, &LtsDataView::LtsDataView::signalContextMenuRequested,
this, &AssetListDialog::onCustomContextMenuRequested);
if (!m_hostsForUpdateNotifiy)
{
m_hostsForUpdateNotifiy = new QTimer(this);
m_hostsForUpdateNotifiy->setSingleShot(true);
m_hostsForUpdateNotifiy->setInterval(1000);
connect(m_hostsForUpdateNotifiy, &QTimer::timeout,
this, &AssetListDialog::onHostsForUpdateNotifyTimeout);
}
// ButtonBox
if (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SystemConfiguration))
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &AssetListDialog::onUnmountButtonClicked);
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("Unmount"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(false);
m_buttonBox->setIcon(LtsWidgets::DialogButton::Load, QIcon(QLatin1String("icon:fixed_video_announcement.svg")));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &AssetListDialog::onSetStateButtonClicked);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Set State"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &AssetListDialog::onImportClicked);
}
m_buttonBox->connectButton(LtsWidgets::DialogButton::Export, this, &AssetListDialog::onExportClicked);
#ifndef LTS_DEBUG
m_ui->assetListView->hideColumn(AssetListDialogModel::Columns::ID);
#endif
return true;
}
void AssetListDialog::onSetStateButtonClicked()
{
const QModelIndexList indexList = m_ui->assetListView->selectedRows();
if (indexList.isEmpty())
return;
if(m_hasImportedAsset)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Save imported assets first before changing state."),
tr("Set Asset State"), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes);
return;
}
// const QString identifier = QStringLiteral("Assets: Set State");
std::vector<InstrumentationAsset> assets;
assets.reserve(indexList.size());
for(QModelIndex index: qAsConst(indexList))
{
InstrumentationAsset asset = m_model->assetByIndex(index);
assets.push_back(asset);
}
QScopedPointer<EditAssetDialog> editAssetDialog (new EditAssetDialog(this, m_ftc, assets));
editAssetDialog->exec();
}
void AssetListDialog::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->assetListView->treeView());
}
void AssetListDialog::enaDisaBtnBoxBtns(const bool b)
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Export)->setEnabled(b);
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(b);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(b);
}
void AssetListDialog::onInstrumentationAssetChanged()
{
// refresh selection buttons
onSelectionChanged(QItemSelection(), QItemSelection());
}
bool AssetListDialog::rowContainsAlteredData(const QHash<int, bool> &data)
{
for (const bool b : data)
{
if (b)
return true;
}
return false;
}
/**
* @brief AssetListDialog::onImportClicked
* is called by clicking on Import-button and inserts all InstrumentationAssets of a selected file.
* @see onExportClicked()
*/
void AssetListDialog::onImportClicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Import"), QString(),
tr("CSV-Files (*.csv)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::ReadOnly))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot open file '%1': %2").arg(file.fileName(), file.errorString()));
return;
}
QTextStream in(&file);
in.setLocale(QLocale::c());
// first get the header data
QString header = in.readLine();
Q_UNUSED(header);
bool bOk;
while (!in.atEnd())
{
const QString line = in.readLine();
QVector<QStringRef> segments = line.splitRef(QLatin1Char(';'));
if (segments.size() < 10)
{
WARNING_LOG(m_logger) << "Skipping line '" << line << "' - to few data";
continue;
}
const InstrumentationAsset ia = importData(segments, &bOk);
if (!bOk)
continue;
if (updateInstrumentationAsset(ia))
continue;
m_model->insertRow(ia, true);
m_hasImportedAsset = true;
QHash<int, bool> alteredCells;
for (int i = 0; i < segments.size(); ++i)
alteredCells.insert(m_model->rowCount() - 1, true);
m_model->setAlteredCells(m_model->rowCount() - 1, alteredCells);
QHash<int, QString> previousValues;
for (int i = 0; i <= AssetListDialogModel::Columns::LAST_UPDATED; ++i)
{
QModelIndex idx = m_model->index(m_model->rowCount() - 1, i);
previousValues[m_model->rowCount() - 1] = m_model->data(idx, Qt::DisplayRole).toString();
}
m_model->setPreviousValues(m_model->rowCount() - 1, previousValues);
}
file.close();
m_buttonBox->getButton(LtsWidgets::DialogButton::Export)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Import)->setEnabled(false);
slotChangesMade();
}
/**
* @brief AssetListDialog::onExportClicked
* is called by clicking on the Export-button and opens a new window to set several filters
* that decide which items are going to get exported.
* @see onFilterSelected()
* @see onImportClicked()
*/
void AssetListDialog::onExportClicked()
{
AssetFilterDialog *filterDialog = new AssetFilterDialog(m_model, this);
if (!filterDialog->init(m_ui->assetListView->selectionModel()->selectedRows().size() > 0))
{
ERROR_LOG(m_logger) << "Unexpected error";
return;
}
filterDialog->fillAssetComboBoxes();
connect(filterDialog, &AssetFilterDialog::exportFilterSelected, this, &AssetListDialog::onFilterSelected);
filterDialog->show();
}
void AssetListDialog::onUnmountButtonClicked()
{
if (m_ui->assetListView->selectionModel()->selectedRows().size() < 1)
return;
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(
this, tr("Do you really want to unmount selected asset(s)?"), tr("Unmount Assets"), LtsWidgets::Behaviour::Modal,
{ LtsWidgets::Button::Yes, LtsWidgets::Button::No });
if (button == LtsWidgets::Button::Yes)
{
// get asset id of all selected assets;
const QModelIndexList indexList = m_ui->assetListView->selectedRows();
for(QModelIndex index: indexList)
{
InstrumentationAsset asset = m_model->assetByIndex(index);
if(asset.id() > 0 )
{
StructureElement se;
if(m_dtc->getStructureElementInMntPointAssetByAssetId(asset.id(), se) == false)
{
WARNING_LOG(m_logger)<<" asset not mounted. name: "<<asset.name()<< " id: "<<asset.id();
continue;
}
InstrumentationAssetUnmountRequest req(asset.id());
m_requestHelper->addRequest([req, this]()
{
return m_ftc->instrumentationAssetUnmountRequest(req, this);
});
}
}
if(m_requestHelper->hasRequests() &&
m_requestHelper->startRequests() == false)
{
ERROR_LOG(m_logger)<<" Couldn't unmount selected assets";
}
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load,false);
}
}
/**
* @brief AssetListDialog::onFilterSelected
* is called by clicking on the Ok-button in the filter window.
* @param exp enum class, that informs about the selected filtering option.
* @param type gives the selected type in case of filtering by specific type, otherwise it is empty and unused.
* @see onExportClicked()
*/
void AssetListDialog::onFilterSelected(const AssetFilterDialog::Export &exp, const QString &type)
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Export"),
QString(),
tr("CSV-Files (*.csv)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly))
{
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Cannot save file '%1': %2").arg(file.fileName(),
file.errorString()));
return;
}
QTextStream out(&file);
out.setLocale(QLocale::c());
const QStringList headerNames = { QStringLiteral("Data Matrix Code"),
QStringLiteral("TKZ"),
QStringLiteral("SNr"),
QStringLiteral("MAC"),
QStringLiteral("Status"),
QStringLiteral("Bauzustand"),
QStringLiteral("UCATT Code"),
QStringLiteral("Lautsprecher"),
QStringLiteral("Mikrofon"),
QStringLiteral("Vapix Protokoll"),
QStringLiteral("Bentuzername"),
QStringLiteral("Passwort"),
QStringLiteral("Properties"),
QStringLiteral("Last updated") };
out << headerNames.join(QLatin1Char(';')) << "\n";
QVector<QString> vecStr;
if (exp == AssetFilterDialog::Export::eSpecificType)
vecStr = getExportString(exp, type);
else
vecStr = getExportString(exp);
for (int i = 0; i < vecStr.size(); ++i)
{
if (!vecStr.at(i).isEmpty())
out << vecStr.at(i) << "\n";
}
file.close();
}
void AssetListDialog::onCustomContextMenuRequested(const QPoint &globalPos, const QModelIndex &indexSrc)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, indexSrc" << indexSrc.row();
if (!indexSrc.isValid())
return;
if (!m_model || !m_updateAction)
return;
m_updateAction->setEnabled(m_model->triggerUpdateRequestUseful(indexSrc));
m_actionMenu->exec(globalPos);
}
void AssetListDialog::onReachabilityUpdateAction()
{
const QModelIndexList &mil = m_ui->assetListView->selectedRows();
QIcon icon;
QString str;
for (const QModelIndex &il : qAsConst(mil))
{
const InstrumentationAsset ia = m_model->getRowData(il.row());
bool bhasHostnameForTriggerUpdate = m_model->getReachable(ia, icon, str);
if (bhasHostnameForTriggerUpdate)
{
m_hostsForUpdate.insert(QString::fromStdString(ia.hostname()));
DEBUG_LOG(m_logger) << LOGFUNCTION << " trigger update for " << ia;
}
} // for
m_hostsForUpdateNotifiy->start(); // restart
}
void AssetListDialog::onHostsForUpdateNotifyTimeout()
{
INFO_LOG(m_logger) << LOGFUNCTION << " START, hostsForUpdate.size() = " << m_hostsForUpdate.size();
if (!m_cmoFtc)
return;
if (m_hostsForUpdate.isEmpty())
return;
for (auto item : qAsConst(m_hostsForUpdate))
DEBUG_LOG(m_logger) << LOGFUNCTION << " host = " << item;
// start request now and trigger update:
std::vector<std::string> hostnameStd;
hostnameStd.reserve(m_hostsForUpdate.size());
for (const QString &item : qAsConst(m_hostsForUpdate))
if( std::find(hostnameStd.begin(), hostnameStd.end(), item.toStdString()) == hostnameStd.end())
hostnameStd.push_back(item.toStdString());
ComponentMonitor::TriggerUpdate request;
request.hostnames(hostnameStd);
DEBUG_LOG(m_logger) << LOGFUNCTION << " TriggerUpdate - request = " << request;
m_requestHelper->addRequest([request, this]()
{
return m_cmoFtc->triggerUpdateRequest(request, this);
});
m_requestHelper->startRequests();
// cleanup in any case:
m_hostsForUpdate.clear();
}
} // namespace InfrastructureManagement
@@ -0,0 +1,117 @@
/**
* @RDE_HEADER@
* The AssetListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <AssetList/ism_filter_asset_dialog.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <ComponentMonitor/cmo_data_plugin_interface.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include "ism_edit_asset_dialog.h"
#include <QSet>
namespace Ui
{
class AssetListDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class AssetListDialogModel;
class AssetListDialog
: public LtsWidgets::LtsDialog
, protected Interface::Ftc::InstrumentationAssetModifyReplyHandler
, protected Interface::Ftc::InstrumentationAssetUnmountReplyHandler
, protected Interface::Ftc::StructureElementModifyReplyHandler
, protected Interface::Ftc::MountingPointAssetModifyReplyHandler
, protected Interface::Ftc::MountingPointAssetRemoveReplyHandler
, protected ComponentMonitor::Interface::Ftc::TriggerUpdateReplyHandler
{
Q_OBJECT
public:
explicit AssetListDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~AssetListDialog();
bool init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ComponentMonitor::Interface::Dtc> cmoDtc,
const std::shared_ptr<ComponentMonitor::Interface::Ftc> cmoFtc);
void onInstrumentationAssetModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onInstrumentationAssetUnmountReply(const Core::FunctionReplyObject &replyObject) override final {m_requestHelper->requestReply(replyObject);}
void onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onMountingPointAssetModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onMountingPointAssetRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
// CMO:
void onTriggerUpdateReply(const Core::FunctionReplyObject &reply) override final { m_requestHelper->requestReply(reply); }
private Q_SLOTS:
void onSetStateButtonClicked();
void onPrint();
void onImportClicked();
void onExportClicked();
void onUnmountButtonClicked();
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void onFilterSelected(const AssetFilterDialog::Export &exp, const QString &type = QString());
void onCustomContextMenuRequested(const QPoint &globalPos, const QModelIndex &indexSrc);
void onReachabilityUpdateAction();
void onHostsForUpdateNotifyTimeout();
void onInstrumentationAssetChanged();
private:
void retranslate() override;
bool apply() override final;
void tableColumnOrganiserSetting() override;
QVector<QString> getExportString(const AssetFilterDialog::Export &exp, const QString &type = QString()) const;
static QString exportData(const InstrumentationAsset &ia, const QString &separator = QLatin1String(";"));
InstrumentationAsset importData(const QVector<QStringRef> &segments, bool *bOk) const;
bool updateInstrumentationAsset(const InstrumentationAsset &asset) const;
void enaDisaBtnBoxBtns(const bool b);
static bool rowContainsAlteredData(const QHash<int, bool> &data);
EditAssetDialog *m_editAssetDialog{nullptr};
LtsSession::LtsSession *m_session;
AssetListDialogModel *m_model;
QString m_menuGroup;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<ComponentMonitor::Interface::Dtc> m_cmoDtc; // CMO ComponentMonitor
std::shared_ptr<ComponentMonitor::Interface::Ftc> m_cmoFtc; // CMO ComponentMonitor
LtsUtils::RequestHelper *m_requestHelper;
Ui::AssetListDialog *m_ui;
bool m_hasImportedAsset{false};
// CustomContextMenu
QMenu *m_actionMenu{nullptr};
QAction *m_updateAction{nullptr};
QSet<QString> m_hostsForUpdate;
QTimer *m_hostsForUpdateNotifiy{nullptr};
QTimer *m_updateBtnBoxBtns{nullptr};
LOGGER_T m_logger;
}; // class AssetListDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssetListDialog</class>
<widget class="QWidget" name="AssetListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Asset Stocks</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="LtsDataView::LtsDataView" name="assetListView"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,499 @@
/**
* @RDE_HEADER@
* The AssetListDialogModel provices data for AssetListDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_asset_list_dialog_model.h"
#include <InfrastructureManagement/ism_translation.h>
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <ComponentMonitor/cmo_data_plugin_interface.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QDateTime>
#include <QBrush>
#include <QSet>
#include <QTimer>
#include <QDebug>
namespace InfrastructureManagement
{
AssetListDialogModel::AssetListDialogModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<InstrumentationAsset>(
{
tr("Id"),
tr("Name"),
tr("Type"),
tr("State"),
tr("Reachability"),
tr("Barcode"),
tr("Hostname"),
tr("Mounting point"),
tr("Properties"),
tr("Last updated")
},
parent)
, m_dtc(nullptr)
, m_reachabilityGreen(QLatin1String("icon:green_light.svg"))
, m_reachabilityYellow(QLatin1String("icon:yellow_light.svg"))
, m_reachabilityOrange(QLatin1String("icon:orange_light.svg"))
, m_reachabilityRed(QLatin1String("icon:red_light.svg"))
, m_alteredCells()
, m_alteredValues()
, m_updateFilterTimer(new QTimer(this))
, m_logger(getLogger("AssetListDialogModel"))
{
m_intactStr = tr("Intact");
updateFilterStates();
updateFilterTypes();
// // updateFilterReachability();
m_updateFilterTimer->setInterval(100);
m_updateFilterTimer->setSingleShot(true);
connect(m_updateFilterTimer, &QTimer::timeout,
this, &AssetListDialogModel::onUpdateFilter, Qt::UniqueConnection);
}
QVariant AssetListDialogModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
switch (section)
{
case TYPE:
return m_cbxFilterType;
case STATE:
return m_cbxFilterState;
case REACHABILITY:
return m_cbxFilterReachability;
default:
break;
}
}
return LtsWidgets::LtsAbstractTableModel<InstrumentationAsset>::headerData(section, orientation, role);
}
QVariant AssetListDialogModel::data(const QModelIndex &index, int role) const
{
if ((role != Qt::DisplayRole &&
role != Qt::BackgroundRole &&
role != Qt::ToolTipRole &&
role != Qt::DecorationRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
|| !indexIsValid(index))
return QVariant();
const InstrumentationAsset &currentAsset = m_vecData.at(index.row());
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case ID:
return currentAsset.id();
case NAME:
return QString::fromStdString(currentAsset.name());
case TYPE:
return toString(currentAsset.mountingPointTypeId());
case BARCODE:
return QString::fromStdString(currentAsset.barcode());
case HOSTNAME:
return QString::fromStdString(currentAsset.hostname());
case MOUNTINGPOINT:
{
StructureElement se;
if (m_dtc->getStructureElementInMntPointAssetByAssetId(currentAsset.id(), se) && se.id() > 0 )
{
return QString::fromStdString(se.displayName());
}
else
{
return QStringLiteral("-");
}
}
case PROPERTIES:
return QString::fromStdString(currentAsset.properties());
case STATE:
{
const InstrumentationAssetState_def::type &currAssetState = currentAsset.assetStateId().underlying();
if(currAssetState == InstrumentationAssetState_def::Unmounted || currAssetState == InstrumentationAssetState_def::Mounted)
{
return m_intactStr;
}
else
{
return toString(currentAsset.assetStateId());
}
//return toString(currentAsset.assetStateId());
}
case REACHABILITY:
{
QIcon icon;
QString str;
getReachable(currentAsset, icon, str);
return str;
}
case LAST_UPDATED:
return QDateTime::fromMSecsSinceEpoch(currentAsset.lastUpdated());
}
}
if (role == Qt::ToolTipRole)
{
if (index.column() == REACHABILITY)
{
if (triggerUpdateRequestUseful(currentAsset))
{
return QDateTime::fromSecsSinceEpoch(m_reachabilityLastCheck[currentAsset.id()]);
}
}
const auto cont = m_alteredValues.value(index.row());
if (!cont.value(index.column()).isEmpty())
return tr("Previous: %1").arg(m_alteredValues.at(index.row()).value(index.column()));
}
if (role == Qt::BackgroundRole)
{
const auto cont = m_alteredCells.value(index.row());
if (cont.value(index.column()))
return QBrush(QColor(Qt::red));
}
if (role == Qt::DecorationRole)
{
if (index.column() == REACHABILITY)
{
QIcon icon;
QString str;
getReachable(currentAsset, icon, str);
return icon;
}
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
switch (index.column())
{
case TYPE:
return currentAsset.mountingPointTypeId().underlying();
case STATE:
if(currentAsset.assetStateId().underlying() == InstrumentationAssetState::Mounted ||
currentAsset.assetStateId().underlying() == InstrumentationAssetState::Unmounted)
{
return m_intactStr;
}
else
return currentAsset.assetStateId().underlying();
case REACHABILITY:
{
QIcon icon;
QString str;
const InstrumentationAsset &innerCurrentAsset = m_vecData.at(index.row());
getReachable(innerCurrentAsset, icon, str);
return str;
}
default:
break;
}
}
return QVariant();
}
inline bool isMptRelevant(MountingPointType_def::type type)
{
return ((type == MountingPointType_def::IndoorCamera) ||
(type == MountingPointType_def::OutdoorCamera) ||
(type == MountingPointType_def::EffectGenerationControlUnit) ||
(type == MountingPointType_def::BuildingSensorModule)
);
}
bool AssetListDialogModel::getReachable(const InstrumentationAsset &currentAsset,
QIcon &iconOut, QString &stringOut) const
{
bool bEnableTriggerUpdate = false;
const bool bIsRelevant = isMptRelevant(currentAsset.mountingPointTypeId().underlying());
if (bIsRelevant)
{
const bool bIsMounted = currentAsset.assetStateId().underlying() == InfrastructureManagement::InstrumentationAssetState_def::Mounted;
if (bIsMounted)
{
if (m_cmoDtc)
{
const ComponentMonitor::ComponentStatus &cs = m_cmoDtc->componentStatus(currentAsset.id());
const ComponentMonitor::ComponentState state = cs.state();
switch (state.underlying()) {
case ComponentMonitor::ComponentState_def::Undefined:
iconOut = m_reachabilityOrange;
stringOut = tr("Undefined");
break;
case ComponentMonitor::ComponentState_def::Reachable:
iconOut = m_reachabilityGreen;
stringOut = tr("Reachable");
break;
case ComponentMonitor::ComponentState_def::Unreachable:
iconOut = m_reachabilityRed;
stringOut = tr("Unreachable");
break;
default:
// empty
break;
}
}
bEnableTriggerUpdate = true;
} else {
// GUEZE-1566: keine gelbe Ampel
// iconOut = m_reachabilityYellow;
// GUEZE-1566
stringOut = QStringLiteral("-");
}
} else { // if (bIsRelevant)
// Icon stays empty
iconOut = QIcon();
stringOut = QStringLiteral("-");
}
return bEnableTriggerUpdate;
}
bool AssetListDialogModel::triggerUpdateRequestUseful(const QModelIndex &index) const
{
if (!index.isValid())
return false;
const InstrumentationAsset &currentAsset = getRowData(index.row());
return triggerUpdateRequestUseful(currentAsset);
}
bool AssetListDialogModel::triggerUpdateRequestUseful(const InstrumentationAsset &currentAsset) const
{
// GUEZE-1490:
static QString dummyStr;
static QIcon dummyIcon;
bool bEnableTriggerUpdate = getReachable(currentAsset, dummyIcon, dummyStr);
return bEnableTriggerUpdate;
}
void AssetListDialogModel::onUpdateFilter()
{
// // updateFilterStates content does not change
updateFilterTypes();
updateFilterReachability();
}
void AssetListDialogModel::onComponentStatusChanged(const ComponentMonitor::ComponentStatus &data, DataModification modType)
{
// handle eRemoved also
Q_UNUSED(modType);
const int row = findRowForId(data.id()); // ComponentStatus.id == InstrumentationAsset.id
if (row < 0)
return;
// For Tooltip:
m_reachabilityLastCheck[data.id()] = data.last_check();
const auto idx(index(row, REACHABILITY));
emit dataChanged(idx, idx, {Qt::DisplayRole, Qt::BackgroundRole, Qt::DecorationRole, Qt::ToolTipRole});
m_updateFilterTimer->start();
}
bool AssetListDialogModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ComponentMonitor::Interface::Dtc> &cmoDtc)
{
m_dtc = dtc;
m_cmoDtc = cmoDtc;
if (!m_dtc->enableInstrumentationAsset())
{
ERROR_LOG(m_logger) << "Could not enable Datatopic InstrumentationAsset of the Data Topic Client";
return false;
}
if (!m_cmoDtc->enableComponentStatus())
{
ERROR_LOG(m_logger) << "Could not enable Datatopic enableComponentStatus of cmo";
return false;
}
disconnect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged, this, &AssetListDialogModel::onDataChanged);
clear();
m_vecData.clear();
connect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged,
this, &AssetListDialogModel::onDataChanged);
auto cb = [this](const InfrastructureManagement::InstrumentationAsset & data)
{
// avoid display information of following mountinhPointTypes
if(data.mountingPointTypeId() == MountingPointType::MeteoDataUnit ||
data.mountingPointTypeId() == MountingPointType::BuildingControlUnit /*||
data.mountingPointTypeId() == MountingPointType::OutdoorIPS */)
{
return;
}
insertRow(data, true);
QHash<int, bool> alteredCells;
for (int i = 0; i <= LAST_UPDATED; ++i)
alteredCells.insert(i, false);
m_alteredCells.append(alteredCells);
QHash<int, QString> previousValues;
for (int i = 0; i <= LAST_UPDATED; ++i)
previousValues[i] = QString();
m_alteredValues.append(previousValues);
};
m_dtc->instrumentationAssets(cb);
emit dataAvailable(m_vecData.size() > 0);
if (m_cmoDtc)
{
connect(m_cmoDtc.get(), &ComponentMonitor::Interface::Dtc::componentStatusChanged,
this, &AssetListDialogModel::onComponentStatusChanged, Qt::UniqueConnection);
auto compStatCb = [this](const ComponentMonitor::ComponentStatus &data)
{
onComponentStatusChanged(data, DataModification::eAdded);
};
m_cmoDtc->componentStatuss(compStatCb);
}
connect(this, &AssetListDialogModel::rowsInserted, this, &AssetListDialogModel::onUpdateFilter);
connect(this, &AssetListDialogModel::rowsRemoved, this, &AssetListDialogModel::onUpdateFilter);
connect(this, &AssetListDialogModel::modelReset, this, &AssetListDialogModel::onUpdateFilter);
onUpdateFilter();
INFO_LOG(m_logger) << "initModel successfull";
return true;
}
InstrumentationAsset AssetListDialogModel::assetByIndex(const QModelIndex &index) const
{
if (!indexIsValid(index))
return InstrumentationAsset();
return getRowData(index.row());
}
void AssetListDialogModel::insertRow(const InstrumentationAsset &asset, bool b)
{
Q_UNUSED(b);
LtsWidgets::LtsAbstractTableModel<InstrumentationAsset>::insertRow(asset);
m_alteredCells.resize(rowCount());
}
void AssetListDialogModel::setAlteredCells(const int row, const QHash<int, bool> &data)
{
if (data.isEmpty() || row < 0 || row >= m_alteredCells.size())
return;
m_alteredCells[row] = data;
}
void AssetListDialogModel::removeBackgroundHighlighting()
{
for (int i = 0; i < this->rowCount(); ++i)
{
for (int j = 0; j < this->columnCount(); ++j)
m_alteredCells[i].insert(j, false);
}
}
void AssetListDialogModel::updateFilterStates()
{
LtsWidgets::ComboboxFilterContent cfc;
LtsWidgets::ComboboxFilterData cfd;
const auto states = {
InstrumentationAssetState::Mounted,
//InstrumentationAssetState::Unmounted, // mounted and unmounted will are displayed as "intact" in asset list dialog
InstrumentationAssetState::Defect,
};
for (const auto es : states)
{
if(es == InstrumentationAssetState::Mounted ||
es == InstrumentationAssetState::Unmounted)
{
cfd.data = m_intactStr;
cfd.text = m_intactStr;
}
else
{
cfd.data = es;
cfd.text = toString(es);
}
cfc.data.push_back(cfd);
}
cfc.sortItems = false;
m_cbxFilterState = cfc.toVariant();
}
void AssetListDialogModel::updateFilterTypes()
{
LtsWidgets::ComboboxFilterContent cfc;
LtsWidgets::ComboboxFilterData cfd;
QSet<InfrastructureManagement::MountingPointType> types;
for (const auto &r : qAsConst(m_vecData))
types.insert(r.mountingPointTypeId());
for (const auto es : qAsConst(types))
{
if(es == MountingPointType::MeteoDataUnit ||
es == MountingPointType::BuildingControlUnit /*||
es == MountingPointType::OutdoorIPS*/ )
{
continue;
}
cfd.data = es.underlying();
cfd.text = toString(es);
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
m_cbxFilterType = cfc.toVariant();
}
void AssetListDialogModel::updateFilterReachability()
{
LtsWidgets::ComboboxFilterContent cfc;
LtsWidgets::ComboboxFilterData cfd;
QMap<QString, QIcon> values;
for (const auto &item : qAsConst(m_vecData))
{
QIcon icon;
QString str;
getReachable(item, icon, str);
values.insert(str, icon);
}
QMapIterator<QString, QIcon> it(values);
while (it.hasNext())
{
it.next();
cfd.data = it.key();
cfd.text = it.key();
cfd.icon = it.value();
cfc.data.push_back(cfd);
}
// for (const QPair<QIcon, QString> &val : qAsConst(values))
// {
// cfd.data = val.first;
// cfd.text = val.first;
// cfd.icon = val.second;
// cfc.data.push_back(cfd);
// }
cfc.sortItems = true;
m_cbxFilterReachability = cfc.toVariant();
}
} // namespace InfrastructureManagement
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* The AssetListDialogModel provices data for AssetListDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <ComponentMonitor/cmo_data_plugin_interface.h>
#include <LtsWidgets/lts_abstract_table_model.h>
namespace InfrastructureManagement
{
class AssetListDialogModel final : public LtsWidgets::LtsAbstractTableModel<InstrumentationAsset>
{
Q_OBJECT
public:
explicit AssetListDialogModel(QObject *parent = nullptr);
enum Columns
{
ID = 0,
NAME,
TYPE,
STATE,
REACHABILITY,
BARCODE,
HOSTNAME,
MOUNTINGPOINT,
PROPERTIES,
LAST_UPDATED
};
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ComponentMonitor::Interface::Dtc> &cmoDtc);
InstrumentationAsset assetByIndex(const QModelIndex &index) const;
QVector<QHash<int, bool>> alteredRows() const { return m_alteredCells; }
void setAlteredCells(const int row, const QHash<int, bool> &data);
QHash<int, QString> previousValues(const int row) const { return m_alteredValues[row]; }
void setPreviousValues(const int row, const QHash<int, QString> &value) { m_alteredValues.insert(row, value); }
void removeBackgroundHighlighting();
void insertRow(const InstrumentationAsset &asset, bool b);
void updateFilterStates();
void updateFilterTypes();
void updateFilterReachability();
bool getReachable(const InstrumentationAsset &currentAsset,
QIcon &iconOut, QString &stringOut) const;
bool triggerUpdateRequestUseful(const QModelIndex &index) const;
bool triggerUpdateRequestUseful(const InstrumentationAsset &currentAsset) const;
private Q_SLOTS:
void onUpdateFilter();
void onComponentStatusChanged(const ComponentMonitor::ComponentStatus &data, DataModification modType);
signals:
void dataAvailable(bool b);
private: // attributes
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<ComponentMonitor::Interface::Dtc> m_cmoDtc; // CMO ComponentMonitor
QIcon m_reachabilityGreen;
QIcon m_reachabilityYellow;
QIcon m_reachabilityOrange;
QIcon m_reachabilityRed;
QVector<QHash<int, bool>> m_alteredCells;
QVector<QHash<int, QString>> m_alteredValues;
QVariant m_cbxFilterType;
QVariant m_cbxFilterState;
QVariant m_cbxFilterReachability;
QHash<int, long long> m_reachabilityLastCheck; // SECONDS since Epoch
QTimer *m_updateFilterTimer{nullptr};
QString m_intactStr;
LOGGER_T m_logger;
}; // class AssetListDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,127 @@
/**
* @RDE_HEADER@
* The EditAssetDialog offers an UI to edit the attributes of an instrumentaion asset
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-16
*/
#include "ism_edit_asset_dialog.h"
#include "ui_ism_edit_asset_dialog.h"
#include "ism_set_properties_dialog.h"
#include <InfrastructureManagement/ism_translation.h>
namespace InfrastructureManagement
{
/*!
* \brief EditAssetDialog::EditAssetDialog
* \param parent
* \param ftc
* \param assets
*/
EditAssetDialog::EditAssetDialog(QWidget *parent, const std::shared_ptr<Interface::Ftc> &ftc, const std::vector<InstrumentationAsset> &assets)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_ui(new Ui::EditAssetDialog)
, m_ftc(ftc)
, m_asset(assets)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("EditAssetDialog"))
{
m_ui->setupUi(this);
for(auto const &asset: assets)
{
m_ui->listWidget->addItem(QString::fromStdString(asset.name()));
}
connect(m_ui->toIntactBtn, &QPushButton::clicked, this, &EditAssetDialog::slotSetAssetToIntact);
connect(m_ui->toDefectBtn, &QPushButton::clicked, this, &EditAssetDialog::slotSetAssetToDefect);
connect(m_ui->cancelBtn, &QPushButton::clicked, this, &EditAssetDialog::slotClose);
}
/*!
* \brief EditAssetDialog::~EditAssetDialog
*/
EditAssetDialog::~EditAssetDialog()
{
delete m_requestHelper;
delete m_ui;
}
/*!
* \brief EditAssetDialog::slotSetAssetToIntact
* Setting the asset state to 'Intact' means setting the state to umounted
*/
void EditAssetDialog::slotSetAssetToIntact()
{
const InstrumentationAssetState newState = InstrumentationAssetState::type::Unmounted;
apply(newState);
slotClose();
}
/*!
* \brief EditAssetDialog::slotSetAssetToDefect
* Setting the asset state to 'defect' => asset will be unmounted and state will be set to defect
*/
void EditAssetDialog::slotSetAssetToDefect()
{
const InstrumentationAssetState newState = InstrumentationAssetState::type::Defect;
apply(newState);
slotClose();
}
/*!
* \brief EditAssetDialog::slotClose
* this Method close the modal dialog
*/
void EditAssetDialog::slotClose()
{
close();
}
/*!
* \brief EditAssetDialog::apply
* Apply the defined state to selected assets
* \param newState
* \return
*/
bool EditAssetDialog::apply(const InstrumentationAssetState newState)
{
const QString stateStr = (newState==InstrumentationAssetState::Mounted || newState==InstrumentationAssetState::Unmounted) ? tr("Intact") : tr("Defect");
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(
this, tr(""), tr("Do you really want to apply \"%1\" state ?").arg(stateStr), LtsWidgets::Behaviour::Modal,
{ LtsWidgets::Button::Yes, LtsWidgets::Button::No }
);
if (button == LtsWidgets::Button::Yes)
{
InstrumentationAssetSetStateRequest req;
for(const auto &asset : qAsConst(m_asset))
{
if (asset.id() == -1)
{
continue;
}
if (asset.assetStateId() == newState)
{
continue;
}
// if state is mounted or unmounted and the aim state is intact nothing will be done
if (((asset.assetStateId() == InstrumentationAssetState::Mounted) || (asset.assetStateId() == InstrumentationAssetState::Unmounted)) &&
(newState == InstrumentationAssetState::Unmounted)) // state intact
{
continue;
}
req.id(asset.id());
req.instrumentationAssetStateId(newState);
m_requestHelper->addRequest([req, this]()
{
return m_ftc->instrumentationAssetSetStateRequest(req, this);
});
}
return m_requestHelper->startRequests();
}
return false;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,63 @@
/**
* @RDE_HEADER@
* The EditAssetDialog offers an UI to edit the attributes of an instrumentaion asset
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-16
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace LtsWidgets
{
class LtsProgressDialogHelper;
}
namespace Ui
{
class EditAssetDialog;
}
namespace InfrastructureManagement
{
class EditAssetDialog
: public LtsWidgets::LtsFramelessDialog
, protected Interface::Ftc::InstrumentationAssetModifyReplyHandler
, protected Interface::Ftc::InstrumentationAssetSetStateReplyHandler
, protected Interface::Ftc::StructureElementModifyReplyHandler
, protected Interface::Ftc::InstrumentationAssetRemoveReplyHandler
{
Q_OBJECT
public:
explicit EditAssetDialog(QWidget *parent,const std::shared_ptr<Interface::Ftc> &ftc, const std::vector<InstrumentationAsset> &assets);
~EditAssetDialog();
void onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onInstrumentationAssetRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onInstrumentationAssetSetStateReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onInstrumentationAssetModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
private slots:
void slotSetAssetToIntact();
void slotSetAssetToDefect();
void slotClose();
private:
bool apply(const InstrumentationAssetState newState) ;
Ui::EditAssetDialog *m_ui;
std::shared_ptr<Interface::Ftc> m_ftc;
std::vector<InstrumentationAsset> m_asset;
LtsUtils::RequestHelper *m_requestHelper;
LOGGER_T m_logger;
}; // class EditAssetDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditAssetDialog</class>
<widget class="QWidget" name="EditAssetDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>414</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Set Asset State</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Set State for following Assets:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="listWidget">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="toIntactBtn">
<property name="text">
<string>to Intact</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toDefectBtn">
<property name="text">
<string>to Defect</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelBtn">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,101 @@
/**
* @RDE_HEADER@
* The AssetFilterDialog shows options to export items, filtering items by certain criteria
* $Id: ism_asset_list_dialog.h 37724 2017-12-07 11:54:11Z bueltel $
* $HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Plugins/InfrastructureManagement/Gui/ResourceManagement/AssetList/ism_asset_list_dialog.h $
* $Author: bueltel $
* Created by Malte Schroeder, NLSE, 2018-06-16
*/
#include "ism_filter_asset_dialog.h"
#include "ui_ism_filter_asset_dialog.h"
#include <InfrastructureManagement/ism_translation.h>
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
namespace InfrastructureManagement
{
/**
* @brief AssetFilterDialog::AssetFilterDialog
* The AssetFilterDialog shows options to export items, filtering items by certain criteria
* @param model
* @param parent
*/
AssetFilterDialog::AssetFilterDialog(AssetListDialogModel *model, QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent)
, m_model(model)
, m_ui(new Ui::AssetFilterDialog)
, m_logger(getLogger("AssetFilterDialog"))
{
setAttribute(Qt::WA_DeleteOnClose, true);
m_ui->setupUi(this);
}
AssetFilterDialog::~AssetFilterDialog()
{
delete m_ui;
}
bool AssetFilterDialog::init(bool selectedItems)
{
m_ui->buttonBox->setButtonVisible(LtsWidgets::DialogButton::Ok);
m_ui->buttonBox->setButtonVisible(LtsWidgets::DialogButton::Close);
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
m_ui->rbSelectedItems->setEnabled(selectedItems);
m_ui->cmbType->setEnabled(false);
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, &AssetFilterDialog::onPbOk);
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &AssetFilterDialog::close);
connect(m_ui->rbAll, &QRadioButton::toggled, this, &AssetFilterDialog::onRbToggled);
connect(m_ui->rbSelectedItems, &QRadioButton::toggled, this, &AssetFilterDialog::onRbToggled);
connect(m_ui->rbType, &QRadioButton::toggled, this, &AssetFilterDialog::onRbToggled);
connect(m_ui->cmbType, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, [ = ]()
{
onRbToggled (m_ui->cmbType->currentIndex() != 0 && m_ui->rbType->isChecked());
});
return true;
}
/**
* @brief AssetFilterDialog::fillAssetComboBoxes
* examines every row of the model and inserts the types onefold in the combobox
*/
void AssetFilterDialog::fillAssetComboBoxes()
{
QSet<InfrastructureManagement::MountingPointType> types;
types.reserve(20);
for (int i = 0; i < m_model->rowCount(); ++i)
types += m_model->getRowData(i).mountingPointTypeId();
m_ui->cmbType->addItem(QLatin1String("---"));
for (const auto &type : qAsConst(types))
m_ui->cmbType->addItem(InfrastructureManagement::toString(type), type.underlying());
m_ui->cmbType->setCurrentIndex(0);
}
void AssetFilterDialog::onPbOk()
{
if (m_ui->rbAll->isChecked())
emit exportFilterSelected(Export::eAll);
else if (m_ui->rbSelectedItems->isChecked())
emit exportFilterSelected(Export::eSelected);
else if (m_ui->rbType->isChecked())
emit exportFilterSelected(Export::eSpecificType, m_ui->cmbType->currentText());
}
void AssetFilterDialog::onRbToggled(bool b)
{
if (m_ui->rbAll->isChecked() ||
m_ui->rbSelectedItems->isChecked() ||
m_ui->rbType->isChecked())
{
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(b);
if (m_ui->rbType->isChecked() && m_ui->cmbType->currentIndex() == 0)
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
m_ui->cmbType->setEnabled(m_ui->rbType->isChecked());
}
}
}
@@ -0,0 +1,52 @@
/**
* @RDE_HEADER@
* The AssetFilterDialog shows options to export items, filtering items by certain criteria
* $Id: ism_asset_list_dialog.h 37724 2017-12-07 11:54:11Z bueltel $
* $HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Plugins/InfrastructureManagement/Gui/ResourceManagement/AssetList/ism_asset_list_dialog.h $
* $Author: bueltel $
* Created by Malte Schroeder, NLSE, 2018-06-16
*/
#pragma once
#include "ism_asset_list_dialog_model.h"
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsWidgets/lts_combo_box.h>
namespace Ui
{
class AssetFilterDialog;
}
namespace InfrastructureManagement
{
class AssetFilterDialog : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
explicit AssetFilterDialog(AssetListDialogModel *model, QWidget *parent = nullptr);
~AssetFilterDialog();
bool init(bool selectedItems);
void fillAssetComboBoxes();
enum class Export
{
eAll,
eSelected,
eSpecificType
};
signals:
void exportFilterSelected(const Export &ex, const QString &type = QString());
private slots:
void onPbOk();
void onRbToggled(bool b);
private:
AssetListDialogModel *m_model;
Ui::AssetFilterDialog *m_ui;
LOGGER_T m_logger;
};
}
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssetFilterDialog</class>
<widget class="LtsWidgets::LtsFramelessDialog" name="AssetFilterDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>363</width>
<height>144</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1">
<widget class="LtsWidgets::LtsDialogButtonBox" name="buttonBox"/>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbType">
<property name="text">
<string>Specific Type:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="cmbType"/>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="rbAll">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbSelectedItems">
<property name="text">
<string>Selected Ite&amp;ms</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsDialogButtonBox</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_dialog_button_box.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsFramelessDialog</class>
<extends>QDialog</extends>
<header>LtsWidgets/lts_frameless_dialog.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,163 @@
/**
* @RDE_HEADER@
* The SetPropertiesDialog offers an UI to edit the properties of an instrumentation asset
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-16
*/
#include "ism_set_properties_dialog.h"
#include "ui_ism_set_properties_dialog.h"
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QLabel>
#include <QtWidgets/QHBoxLayout>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
using namespace InfrastructureManagement;
SetPropertiesDialog::SetPropertiesDialog(QLineEdit *lineEdit, QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent)
, m_ui(new Ui::SetPropertiesDialog)
, m_lineEdit(lineEdit)
, m_logger(getLogger("SetPropertiesDialog"))
{
m_ui->setupUi(this);
init();
}
SetPropertiesDialog::~SetPropertiesDialog()
{
delete m_ui;
}
void SetPropertiesDialog::init()
{
m_ui->buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &SetPropertiesDialog::onAddClicked);
// nicht über connectButton - gibt sonst komische Message-Boxes
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked,
this, &SetPropertiesDialog::onOkClicked);
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked,
this, &SetPropertiesDialog::reject);
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close)->setText(tr("Cancel")); //
m_ui->scrollArea->widget()->setLayout(m_ui->vlScrollBar);
if (!m_lineEdit->text().isEmpty())
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(m_lineEdit->text().toUtf8(), &error);
if (error.error != QJsonParseError::NoError)
{
ERROR_LOG(m_logger) << error.errorString();
return;
}
if (!doc.isObject())
{
ERROR_LOG(m_logger) << "Properties String is no JSON-Object";
return;
}
QJsonObject obj = doc.object();
for (auto it = obj.constBegin(); it != obj.constEnd(); ++it)
addProperty(it.key(), it.value().toVariant());
}
}
void SetPropertiesDialog::onOkClicked()
{
QJsonObject obj;
for (auto it = m_properties.constBegin(); it != m_properties.constEnd(); ++it)
{
QString propVal(it.value()->text());
QJsonValue jsonVal;
switch (propValType(propVal))
{
case PropValType::INT:
jsonVal = propVal.toInt();
break;
case PropValType::DOUBLE:
jsonVal = propVal.toDouble();
break;
case PropValType::BOOL:
{
if (propVal.toLower() == QStringLiteral("true"))
jsonVal = true;
if (propVal.toLower() == QStringLiteral("false"))
jsonVal = false;
break;
}
case PropValType::STRING:
default:
jsonVal = propVal;
}
obj.insert(it.key()->text(), jsonVal);
}
m_lineEdit->setText(QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact)));
close();
}
void SetPropertiesDialog::onAddClicked()
{
addProperty(tr("name"), tr("value"));
}
void SetPropertiesDialog::addProperty(const QString &propName, const QVariant &propValue)
{
QHBoxLayout *layout = new QHBoxLayout;
QLineEdit *lePropName = new QLineEdit(propName, this);
QLineEdit *lePropVal = new QLineEdit(propValue.toString(), this);
QPushButton *pbRemove = new QPushButton(this);
QLabel *colon = new QLabel(QStringLiteral(":"), this);
pbRemove->setText(tr("remove"));
layout->addWidget(lePropName);
layout->addWidget(colon);
layout->addWidget(lePropVal);
layout->addWidget(pbRemove);
m_properties.insert(lePropName, lePropVal);
m_ui->vlPorts->addLayout(layout);
connect(pbRemove, &QPushButton::clicked,
this, [=]()
{
m_ui->vlPorts->removeItem(layout);
m_properties.remove(lePropName);
delete lePropName;
delete lePropVal;
delete colon;
pbRemove->deleteLater();
});
}
SetPropertiesDialog::PropValType SetPropertiesDialog::propValType(const QString &prop)
{
bool isOk;
(void)prop.toInt(&isOk);
if (isOk)
return PropValType::INT;
(void)prop.toDouble(&isOk);
if (isOk)
return PropValType::DOUBLE;
if (prop.toLower() == QStringLiteral("true") || prop.toLower() == QStringLiteral("false"))
return PropValType::BOOL;
return PropValType::STRING;
}
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* The SetPropertiesDialog offers an UI to edit the properties of an instrumentation asset
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-16
*/
#pragma once
#include <LtsWidgets/lts_frameless_dialog.h>
#include <InfrastructureManagement/logger.h>
#include <QtCore/QMap>
class QLineEdit;
namespace Ui
{
class SetPropertiesDialog;
}
namespace InfrastructureManagement
{
class SetPropertiesDialog
: public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
explicit SetPropertiesDialog(QLineEdit *lineEdit, QWidget *parent = nullptr);
~SetPropertiesDialog();
private:
void init();
private Q_SLOTS:
void onOkClicked();
void onAddClicked();
private: // other
enum class PropValType
{
INT,
DOUBLE,
BOOL,
STRING
};
private: // methods
void addProperty(const QString &propName, const QVariant &propValue);
PropValType propValType(const QString &prop);
private: // attributes
Ui::SetPropertiesDialog *m_ui;
QMap<QLineEdit *, QLineEdit *> m_properties; // <propname, propval>
QLineEdit *m_lineEdit;
LOGGER_T m_logger;
}; // class SetPropertiesDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SetPropertiesDialog</class>
<widget class="QWidget" name="SetPropertiesDialog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">Set Ports</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>313</width>
<height>153</height>
</rect>
</property>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>340</x>
<y>80</y>
<width>160</width>
<height>80</height>
</rect>
</property>
<layout class="QVBoxLayout" name="vlScrollBar">
<item>
<layout class="QVBoxLayout" name="vlPorts"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsDialogButtonBox</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_dialog_button_box.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,126 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-10-28
#
SET(src
ExerciseAssignment/ism_exercise_assignment_dialog.cpp
ExerciseAssignment/ism_exercise_assignment_dialog_model.cpp
ExerciseAssignment/ism_exercise_assignment_dialog_requesters.cpp
ExerciseAssignment/ism_exercise_assignment_dialog_proxy_model.cpp
Overview/ism_overview_dialog.cpp
Overview/ism_overview_dialog_model.cpp
Overview/ism_overview_mounting_point_list_dialog.cpp
Overview/ism_overview_mounting_point_list_model.cpp
Overview/ism_overview_conflicts_dialog.cpp
Overview/ism_overview_conflicts_model.cpp
AssetList/ism_asset_list_dialog_model.cpp
AssetList/ism_asset_list_dialog.cpp
AssetList/ism_edit_asset_dialog.cpp
AssetList/ism_filter_asset_dialog.cpp
AssetList/ism_set_properties_dialog.cpp
MountingPointInfo/ism_mounting_point_info_dialog.cpp
MountingPointMapSelection/ism_dds_selector.cpp
MountingPointMapSelection/ism_selector.cpp
MountingPointList/ism_mounting_point_list_dialog.cpp
MountingPointList/ism_mounting_point_list_dialog_model.cpp
MountingPointList/ism_mounting_point_list_dialog_checkbox_delegate.cpp
MountingPointList/ism_mounting_point_list_dialog_checkbox_proxy_model.cpp
MountingPointList/ism_mounting_point_list_dialog_list_sort_model.cpp
ApproachingPoints/ism_approaching_point_list_dialog_model.cpp
ApproachingPoints/ism_approaching_point_list_dialog.cpp
ApproachingPoints/ism_edit_approaching_point_dialog.cpp
# ScheduleDifferences ersetzt durch neuen VollständigkeitsCheck:
# Overview/ism_overview_mounting_point_list{model, dialog}
# ScheduleDifferences/ism_schedule_differences_list_dialog.cpp
# ScheduleDifferences/ism_schedule_differences_list_model.cpp
ism_resource_gui_plugin.cpp
ism_resource_gui_plugin.h
ism_building_mount_point_dialog.cpp
ism_building_mount_point_model.cpp
ism_plan_dialog.cpp
ism_plan_edit_dialog.cpp
ism_plan_dialog_model.cpp
#Timeline/ism_plan_tln_delegate.cpp
#Timeline/ism_plan_tln_delegate.h
#Timeline/ism_plan_tln_dialog.cpp
#Timeline/ism_plan_tln_dialog.h
#Timeline/ism_plan_tln_model.cpp
#Timeline/ism_plan_tln_model.h
PlanChooser/plan_chooser.cpp
PlanChooser/new_plan_dialog.cpp
CustomViews/ism_schedule.cpp
)
NGL_WRAP_UI(src
Overview/ism_overview_dialog.ui
Overview/ism_overview_mounting_point_list_dialog.ui
Overview/ism_overview_conflicts_dialog.ui
AssetList/ism_asset_list_dialog.ui
AssetList/ism_edit_asset_dialog.ui
AssetList/ism_filter_asset_dialog.ui
AssetList/ism_set_properties_dialog.ui
MountingPointInfo/ism_mounting_point_info_dialog.ui
MountingPointList/ism_mounting_point_list_dialog.ui
# ScheduleDifferences/ism_schedule_differences_list_dialog.ui
ism_building_mount_point_dialog.ui
ism_plan_dialog.ui
ism_plan_edit_dialog.ui
#Timeline/ism_plan_tln_dialog.ui
PlanChooser/plan_chooser.ui
PlanChooser/new_plan_dialog.ui
CustomViews/ism_schedule.ui
ApproachingPoints/ism_approaching_point_list_dialog.ui
ApproachingPoints/ism_edit_approaching_point_dialog.ui
ExerciseAssignment/ism_exercise_assignment_dialog.ui
)
NGL_ADD_LIBRARY(WS IsmResGuiPlugin MODULE ${src})
NGL_TARGET_LINK_LIBRARIES(IsmResGuiPlugin
LtsPrinting
NGLLogger
nglwidgets
ngltools
LtsSession
LtsSessionData
LtsNotification
AvmDataPluginInterface
IsmResGuiPluginInterface
IsmDataPluginInterface
IsmShared
Qt5::Widgets
LtsWidgets
LtsDataView
LtsUtilsCore # json
LtsUtilsGuiDds
LtsCoordTrans
ltsCoordWidget
SituationMapGuiPluginInterface
situationMap
LtsUtilsGuiConnectDialog
LtsUtilsSettings
#LtsTimeline
LtsSessionDataDds
ExmDataPluginInterface
CmoDataPluginInterface
)
NGL_INSTALL_TARGET(IsmResGuiPlugin)
@@ -0,0 +1,77 @@
/**
* @RDE_HEADER@
* CustomView for Exercises
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-04-08
*/
#include "ism_schedule.h"
#include "ui_ism_schedule.h"
#include "ism_plan_dialog_model.h"
#include <ngltools/ngltools_dtg.h>
#include <QDateTime>
namespace InfrastructureManagement
{
CustomViewSchedule::CustomViewSchedule(QWidget *parent)
: AbstractDisplayWidget(parent)
, m_ui(new Ui::CustomViewSchedule)
, m_logger(getLogger("CustomViewSchedule"))
{
m_ui->setupUi(this);
}
CustomViewSchedule::~CustomViewSchedule()
{
delete m_ui;
}
bool CustomViewSchedule::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
const QString msName = rowData(idx, InfrastructureManagement::PlanDialogModel::NAME).toString();
m_ui->lblName->setText(msName);
int msId = rowData(idx, InfrastructureManagement::PlanDialogModel::ID).toInt();
if (msId == 0)
{
m_ui->lblName->setWordWrap(true);
m_ui->lbCreated->hide();
m_ui->lblCreated->hide();
m_ui->lbBegin->hide();
m_ui->lblBegin->hide();
m_ui->lbEnd->hide();
m_ui->lblEnd->hide();
m_ui->lblStatus->hide();
}
else
{
m_ui->lbCreated->hide();
m_ui->lblCreated->hide();
#ifndef LTS_DEBUG
// m_ui->lblCreated->setVisible(true); // Should not be visible in Release build, but it is
// m_ui->lbCreated->setVisible(true);
#endif
m_ui->lblCreated->setText(rowData(idx, InfrastructureManagement::PlanDialogModel::CREATED).toString());
m_ui->lblBegin->setText(rowData(idx, InfrastructureManagement::PlanDialogModel::START).toString());
m_ui->lblEnd->setText(rowData(idx, InfrastructureManagement::PlanDialogModel::END).toString());
m_ui->lblStatus->setText(rowData(idx, InfrastructureManagement::PlanDialogModel::STATUS).toString());
QPalette p = m_ui->lblStatus->palette();
QColor newCol = rowData(idx, PlanDialogModel::STATUS, Qt::TextColorRole).value<QColor>();
p.setColor(m_ui->lblStatus->backgroundRole(), newCol);
p.setColor(m_ui->lblStatus->foregroundRole(), newCol);
m_ui->lblStatus->setPalette(p);
}
return true;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,33 @@
/**
* @RDE_HEADER@
* CustomView for Exercises
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-04-08
*/
#pragma once
#include <Viewer/LtsDataView/abstract_display_widget.h>
#include <InfrastructureManagement/logger.h>
namespace Ui
{
class CustomViewSchedule;
}
namespace InfrastructureManagement
{
class CustomViewSchedule final : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
public:
explicit CustomViewSchedule(QWidget *parent = nullptr);
~CustomViewSchedule();
bool init(const QModelIndex &idx) override;
private:
Ui::CustomViewSchedule* m_ui;
LOGGER_T m_logger;
};
} // namespace
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CustomViewSchedule</class>
<widget class="QWidget" name="CustomViewSchedule">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>258</width>
<height>133</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblName">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string notr="true">&lt;Schedule Name&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lbCreated">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Created:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblCreated">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string notr="true">&lt;Created Date&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbBegin">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Begin:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblBegin">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string notr="true">&lt;Begin Date&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbEnd">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>End:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblEnd">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string notr="true">&lt;End Date&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="lblStatus">
<property name="text">
<string notr="true">&lt;Status&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,390 @@
/**
* @RDE_HEADER@
* The ExerciseAssignmentDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id: ism_exercise_assignment_dialog.cpp 57783 2022-08-03 11:07:05Z ojog_i $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/22_09_resmgmt2.0/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog.cpp $
* $Author: ojog_i $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
* Refreshed by Mike Wille, SLTE, 2022-09-26
*/
#include "ism_exercise_assignment_dialog.h"
#include "ui_ism_exercise_assignment_dialog.h"
#include "ism_exercise_assignment_dialog_requesters.h"
#include "ism_exercise_assignment_dialog_proxy_model.h"
#include <LtsUtilsCore/json_object.h>
#include <ExerciseManagement/exm_data_plugin_interface.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <LtsSession/lts_session.h>
#include <LtsPrinting/printing.h>
#include <LtsWidgets/lts_overlay_loading.h>
#include <LtsUtilsSettings/settings.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
using namespace LtsUtils;
using namespace LtsWidgets;
namespace InfrastructureManagement
{
ExerciseAssignmentDialog::ExerciseAssignmentDialog(LtsSession::LtsSession *session, QWidget *parent) noexcept(false)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_session(session)
, m_ui(new Ui::ExerciseAssignmentDialog)
, m_model(nullptr)
, m_modelAssignedFilter(new ExerciseAssignmentDialogModelFilterProxy(this))
, m_modelUnassignedFilter(new ExerciseAssignmentDialogModelFilterProxy(this))
, m_logger(getLogger("ExerciseAssignmentDialog"))
{
m_ui->setupUi(this);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ExerciseAssignmentDialog::onPrint);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Exercise_Assignment"));
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
if (!m_session->getDtc<DataInterface>(m_dtc) ||
!m_session->getFtc<DataInterface>(m_ftc) ||
!m_session->getDtc<ExerciseManagement::DataInterface>(exmDtc))
throw std::exception();
if (!m_ftc->enableMainStructureElementModify())
{
ERROR_LOG(m_logger) << "Could not enable FT MainStructureElementModify of ISM";
throw std::exception();
}
if (!exmDtc->enableExercise())
{
ERROR_LOG(m_logger) << "Could not enable DT Exercise of EXM";
throw std::exception();
}
// Add all available exercises to comboBox (do not add deleted or terminated exercises)
exmDtc->exercises([this](const ExerciseManagement::Exercise &data)
{
if (data.isDeleted())
return;
switch(data.state().underlying())
{
case ExerciseManagement::ExerciseState_def::Created:
case ExerciseManagement::ExerciseState_def::Started:
case ExerciseManagement::ExerciseState_def::Paused:
case ExerciseManagement::ExerciseState_def::Stopped:
{
m_exercises.insert(data.id(), data);
break;
}
default:
return;
}
});
for (const auto &exercise : qAsConst(m_exercises))
m_ui->cbExercises->addItem(QString::fromStdString(exercise.name()), exercise.id());
if (m_ui->cbExercises->count() == 0)
{
setEnabled(false);
setUnchangeable();
m_buttonBox->getButton(LtsWidgets::DialogButton::Print)->setEnabled(false);
return;
}
else
m_ui->label->setVisible(false);
m_model = new ExerciseAssignmentDialogModel(m_exercises, this);
// set initial exercise filter to the assigned exercises so that only buildings for exercise x are visible
auto exerciseChangedFn = [this](int index = -1)
{
Q_UNUSED(index);
m_modelAssignedFilter->setExerciseId(m_ui->cbExercises->currentData().toInt());
//m_ui->assignedExercises->expandAll();
};
connect(m_ui->cbExercises, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, exerciseChangedFn);
exerciseChangedFn();
// NOT live, otherwise:
connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged,
this, &ExerciseAssignmentDialog::onMainStructureElementChanged);
auto cb = [this](const InfrastructureManagement::MainStructureElement &mse)
{
onMainStructureElementChanged(mse, DataModification::eAdded);
};
m_dtc->mainStructureElements(cb);
m_modelUnassignedFilter->setSourceModel(m_model);
m_ui->availableExercises->setModel(m_modelUnassignedFilter);
m_ui->availableExercises->setSortingEnabled(true);
m_ui->availableExercises->sortByColumn(0, Qt::SortOrder::AscendingOrder);
m_ui->availableExercises->setDragEnabled(true);
m_ui->availableExercises->viewport()->setAcceptDrops(true);
// m_ui->availableExercises->setDropIndicatorShown(true);
m_ui->availableExercises->setDragDropMode(QAbstractItemView::DragDrop);
m_ui->availableExercises->setDefaultDropAction(Qt::DropAction::MoveAction);
m_modelAssignedFilter->setSourceModel(m_model);
m_ui->assignedExercises->setModel(m_modelAssignedFilter);
m_ui->assignedExercises->setSortingEnabled(true);
m_ui->assignedExercises->sortByColumn(0, Qt::SortOrder::AscendingOrder);
m_ui->assignedExercises->setDragEnabled(true);
m_ui->assignedExercises->viewport()->setAcceptDrops(true);
// m_ui->assignedExercises->setDropIndicatorShown(true);
m_ui->assignedExercises->setDragDropMode(QAbstractItemView::DragDrop);
m_ui->assignedExercises->setDefaultDropAction(Qt::DropAction::MoveAction);
connect(m_modelAssignedFilter, &ExerciseAssignmentDialogModelFilterProxy::doRefilter,
this, &ExerciseAssignmentDialog::onUnassignedNeedsUpdate);
connect(m_modelUnassignedFilter, &ExerciseAssignmentDialogModelFilterProxy::doRefilter,
this, &ExerciseAssignmentDialog::onAssignedNeedsUpdate);
}
ExerciseAssignmentDialog::~ExerciseAssignmentDialog()
{
delete m_ui;
}
void ExerciseAssignmentDialog::onUnassignedNeedsUpdate(const QSet<QModelIndex> &setToExpand)
{
m_modelUnassignedFilter->invalidate();
for(auto indexToExpand : setToExpand)
m_ui->assignedExercises->expand(m_modelAssignedFilter->mapFromSource(indexToExpand));
slotChangesMade();
}
void ExerciseAssignmentDialog::onAssignedNeedsUpdate(const QSet<QModelIndex> &setToExpand)
{
m_modelAssignedFilter->invalidate();
for(auto indexToExpand : setToExpand)
m_ui->availableExercises->expand(m_modelUnassignedFilter->mapFromSource(indexToExpand));
slotChangesMade();
}
void ExerciseAssignmentDialog::retranslate()
{
translate(m_ui, tr("Exercise Assignment"));
}
void ExerciseAssignmentDialog::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &mse, DataModification modType)
{
auto seti = mse.structureElementTypeId();
if (seti != StructureElementType::Building &&
seti != StructureElementType::Announcement)
return;
// read exercise id and add to assigned exercises
QString displayName(m_dtc->getBuildingDisplayName(mse.id()));
if (displayName.isEmpty())
displayName = QString::fromStdString(mse.name());
int exerciseId;
try
{
exerciseId = JsonObject::fromJson(mse.properties()).value<JsonArray>(QStringLiteral("available_in_exercise")).at<int>(0); // get exercise id from properties json
}
catch(...)
{
exerciseId = 0;
}
if (!m_exercises.contains(exerciseId)) // if building is part of a deleted / terminated exercise, just add it to the unassigned buildings model
exerciseId = 0;
if (modType == DataModification::eModified)
m_model->updateMse(mse.id(), mse.groupId(), displayName, exerciseId);
else if (modType == DataModification::eAdded)
m_model->addMse(mse.id(), mse.groupId(), displayName, exerciseId);
else
m_model->removeMse(mse.id());
}
bool ExerciseAssignmentDialog::apply()
{
// XXX: HACK we don't know if user pressed ok or apply - apply() has to emidiately return, but the operation is async... so mimic ok/apply later, based on what was clicked
bool wasOkay = (sender() == static_cast<QObject *>(m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)));
LtsOverlayLoading *lol = new LtsOverlayLoading;
setOverlay(lol);
MSEModifyRequestCollector *collector = new MSEModifyRequestCollector(m_ftc, this);
{
QPushButton *pbCancel = new QPushButton;
pbCancel->setText(tr("Cancel"));
connect(pbCancel, &QPushButton::clicked,
this, [pbCancel, collector, lol]()
{
collector->cancel();
lol->setText(tr("Canceling ..."));
pbCancel->setEnabled(false);
});
qobject_cast<QVBoxLayout *>(lol->layout())->addWidget(pbCancel, 0, Qt::AlignmentFlag::AlignCenter);
}
const QVector<RequestInfos> &requestInfos = m_model->getRequestInfos();
for (const RequestInfos &ri : qAsConst(requestInfos))
{
MainStructureElementModifyRequest request;
MainStructureElement &mse = request;
mse = m_dtc->mainStructureElement(ri.mseId);
QJsonObject root;
try
{
root = JsonObject::fromJson(mse.properties()).object();
}
catch (...)
{
ERROR_LOG(m_logger) << "can't parse json for mseId " << ri.mseId << " and excId " << ri.exerciseId << " - using new json";
Q_ASSERT(false);
}
if (LtsUtils::ProjectSettings::getInstance()->value(QStringLiteral("ism"), QStringLiteral("enableSetRecordingDialog")).toBool())
setRecording(mse,ri.exerciseId != 0);
if (ri.exerciseId != 0)
root[QStringLiteral("available_in_exercise")] = QJsonArray({{ri.exerciseId}});
else
root.remove(QStringLiteral("available_in_exercise"));
mse.properties(QString::fromUtf8(QJsonDocument(root).toJson()).toStdString());
collector->addRequest(ri, request);
}
int initialCount = collector->count();
const QString leText(QStringLiteral("%1<br />%3 / %2").arg(tr("Assigning building(s) to exercise(s)")).arg(initialCount));
lol->setText(leText.arg(0));
connect(collector, &MSEModifyRequestCollector::requestComplete,
this, [collector, lol, leText, initialCount]()
{
lol->setText(leText.arg(initialCount - collector->count()));
});
connect(collector, &MSEModifyRequestCollector::finished,
this, [this, collector, wasOkay, lol](bool canceled)
{
unsetOverlay();
lol->deleteLater();
collector->deleteLater();
int failedCount = collector->failedCount();
if (failedCount > 0)
{
new LtsWidgets::LtsMessageDialogNew(this, tr("Error: %1 building(s) could not be assigned!").arg(failedCount));
return;
}
if (canceled)
return;
__unchange__(); // 'apply' behaviour
if (!wasOkay) // 'ok' behaviour
return;
closeRequest(); // we 'unchanged', so it will close directly
});
collector->go();
return false; // our request is async, say false, show a blocking dialog and do ok-/apply-button stuff later
}
/*!
* \brief ExerciseAssignmentDialog::setRecoding
* The property of an element with type indoorcamera or outdoorcamera can be updated
* \param mse
* \param state
*/
void ExerciseAssignmentDialog::setRecording(MainStructureElement &mse, bool state)
{
for(auto &el : mse.elements())
{
if(el.mountingPointTypeId() != MountingPointType::IndoorCamera &&
el.mountingPointTypeId() != MountingPointType::OutdoorCamera)
continue;
QJsonDocument propsDoc = QJsonDocument::fromJson(QByteArray::fromStdString(el.properties()));
QJsonObject propsObj;
if (propsDoc.isObject()) // if the given properties are no valid JSON object, the properties will be made from scratch
propsObj = propsDoc.object();
propsObj.insert(QLatin1String("record"), state);
el.properties(QJsonDocument(propsObj).toJson(QJsonDocument::Compact).toStdString());
}
}
void ExerciseAssignmentDialog::onPrint()
{
QTreeView tv;
tv.setModel(m_model);
tv.expandAll();
LtsPrinting::printView(m_session, this, &tv);
}
} // namespace InfrastructureManagement
//
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* The AssetListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id: ism_exercise_assignment_dialog.h 45935 2019-03-08 08:36:11Z ehrlicher $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/22_09_resmgmt2.0/Lts/Plugins/InfrastructureManagement/Gui/AudioVideoConfig/ExerciseAssignment/ism_exercise_assignment_dialog.h $
* $Author: ehrlicher $
* Created by Hannes Baeuerle, SLSE, 2017-06-29
* Refreshed by Mike Wille, SLTE, 2022-09-26
*/
#pragma once
#include <ExerciseManagement/exm_dtc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/logger.h>
#include <LtsWidgets/lts_dialog.h>
namespace Ui
{
class ExerciseAssignmentDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class ExerciseAssignmentDialogModel;
class ExerciseAssignmentDialogModelFilterProxy;
class ExerciseAssignmentDialog
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit ExerciseAssignmentDialog(LtsSession::LtsSession *session, QWidget *parent = nullptr) noexcept(false);
~ExerciseAssignmentDialog();
private slots:
void onUnassignedNeedsUpdate(const QSet<QModelIndex> &setToExpand);
void onAssignedNeedsUpdate(const QSet<QModelIndex> &setToExpand);
void onPrint();
private:
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &mse, DataModification modType);
void retranslate() override;
bool apply() override;
void setRecording(MainStructureElement &mse, bool state);
private:
LtsSession::LtsSession *m_session;
Ui::ExerciseAssignmentDialog *m_ui;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<Interface::Ftc> m_ftc;
ExerciseAssignmentDialogModel *m_model;
ExerciseAssignmentDialogModelFilterProxy *m_modelAssignedFilter;
ExerciseAssignmentDialogModelFilterProxy *m_modelUnassignedFilter;
QMap<qint32, ExerciseManagement::Exercise> m_exercises;
LOGGER_T m_logger;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExerciseAssignmentDialog</class>
<widget class="QWidget" name="ExerciseAssignmentDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>953</width>
<height>681</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#aa0000;&quot;&gt;WARNING: There are no exercises available. You can't assign buildings.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="2">
<layout class="QGridLayout" name="gridLayout"/>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lbExercises">
<property name="text">
<string>Assign to exercise:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbExercises">
<property name="currentText">
<string notr="true"/>
</property>
<property name="const" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QTreeView" name="availableExercises">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTreeView" name="assignedExercises">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,353 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#include "ism_exercise_assignment_dialog_model.h"
#include <QFont>
#include <QGuiApplication>
#include <InfrastructureManagement/ism_translation.h>
#ifdef LTS_DEBUG
#include <QTimer> // ftc delay
#endif
namespace InfrastructureManagement
{
ExerciseAssignmentDialogModel::ExerciseAssignmentDialogModel(const QMap<qint32, ExerciseManagement::Exercise> &exercises, QObject *parent) noexcept(false)
: QAbstractItemModel(parent)
, m_rootItem(new TreeItem(0, 0, tr("InvisibleRootItem"), -1))
, m_exercises(exercises)
, m_logger(getLogger("ExerciseAssignmentDialogModel"))
{
for (int it = BuildingGroup_def::UnknownGroup;
it <= BuildingGroup_def::Salchau; // WARNING: Change this, when enum changes!
++it)
{
m_rootItem->appendChild(new TreeItem(0, it, toString(static_cast<BuildingGroup_def::type>(it)), -1, m_rootItem));
}
}
ExerciseAssignmentDialogModel::~ExerciseAssignmentDialogModel()
{
delete m_rootItem;
}
void ExerciseAssignmentDialogModel::addMse(int mseId, int sectionId, const QString &displayName, int exerciseId)
{
const QList<TreeItem*> &childItems = m_rootItem->childItems();
for (auto sectionItem : qAsConst(childItems))
{
if (sectionItem->sectionId() == sectionId)
{
beginInsertRows(index(sectionItem), sectionItem->childCount(), sectionItem->childCount());
sectionItem->appendChild(new TreeItem(mseId, sectionId, displayName, exerciseId, sectionItem));
endInsertRows();
return;
}
}
ERROR_LOG(m_logger) << "Did not find section with enum value " << sectionId;
return;
}
void ExerciseAssignmentDialogModel::updateMse(int mseId, int sectionId, const QString &displayName, int exerciseId)
{
// Todo: Change of display name or moving to another section not yet implemented
Q_UNUSED(sectionId);
Q_UNUSED(displayName);
QModelIndex mi = findItemByMseId(mseId);
TreeItem* item = treeItem(mi);
if (!item)
return;
if (exerciseId != item->originalExerciseId())
{
item->setOriginalExerciseId(exerciseId);
emit dataChanged(mi, mi);
}
}
void ExerciseAssignmentDialogModel::removeMse(int mseId)
{
QModelIndex mi = findItemByMseId(mseId);
TreeItem* item = treeItem(mi);
if (!item)
return;
TreeItem* parent = item->parentItem();
if (!parent)
return;
beginRemoveRows(index(parent),item->childNumber(),item->childNumber());
parent->removeChild(item->childNumber());
endRemoveRows();
}
Qt::DropActions ExerciseAssignmentDialogModel::supportedDropActions() const
{
return Qt::MoveAction;
}
QVariant ExerciseAssignmentDialogModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() ||
(role != Qt::DisplayRole
&& role != Qt::FontRole)
)
return {};
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (!item)
return {};
if (role == Qt::FontRole)
{
if (item->originalExerciseId() == item->exerciseId())
return {};
QFont f;
f.setBold(true);
return f;
}
if (role == Qt::DisplayRole)
{
if (index.column() == 0)
return item->displayName();
if (index.column() == 1)
{
const int exerciseId = item->exerciseId();
if (exerciseId < 0)
return {};
if (exerciseId == 0)
return QStringLiteral("-");
return QString::fromStdString(m_exercises.value(exerciseId).name());
}
}
return {};
}
QVariant ExerciseAssignmentDialogModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Orientation::Horizontal || role != Qt::DisplayRole)
return QAbstractItemModel::headerData(section, orientation, role);
if (section == 0)
return tr("Building");
if (section == 1)
return tr("Assigned Exercises");
return {};
}
QModelIndex ExerciseAssignmentDialogModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return {};
TreeItem *parentItem;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
return {};
}
QModelIndex ExerciseAssignmentDialogModel::parent(const QModelIndex &mi) const
{
if (!mi.isValid())
return {};
TreeItem *childItem = static_cast<TreeItem*>(mi.internalPointer());
TreeItem *parentItem = childItem->parentItem();
return index(parentItem);
}
QModelIndex ExerciseAssignmentDialogModel::index(TreeItem *item) const
{
if (item == m_rootItem || !item)
return {};
return createIndex(item->childNumber(),0,item);
}
int ExerciseAssignmentDialogModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = treeItem(parent);
return parentItem->childCount();
}
QSet<int> ExerciseAssignmentDialogModel::childMses(const QModelIndex &mi, int exerciseId) const
{
QSet<int> mses;
const QList<TreeItem*> &childItems = treeItem(mi)->childItems();
for(auto myChild : qAsConst(childItems))
{
if (myChild->exerciseId() == exerciseId)
mses << myChild->mseId();
}
return mses;
}
TreeItem *ExerciseAssignmentDialogModel::treeItem(const QModelIndex &index) const
{
return static_cast<TreeItem*>(index.internalPointer());
}
QModelIndex ExerciseAssignmentDialogModel::findItemByMseId(int mseId) const
{
// This only works as long as first level is section and second level is Building!
// Otherwise we need to go into recursion!
const QList<TreeItem*> &childItems = m_rootItem->childItems();
for (auto sectionItem : qAsConst(childItems))
{
const QList<TreeItem*> &sectionChildItems= sectionItem->childItems();
for (auto mseItem : qAsConst(sectionChildItems))
{
if (mseItem->mseId() == mseId)
return index(mseItem);
}
}
return {};
}
void ExerciseAssignmentDialogModel::setExerciseId(const QModelIndex &mi, int exerciseId)
{
TreeItem *ti = treeItem(mi);
if (!ti)
return;
ti->setExerciseId(exerciseId);
emit dataChanged(mi, mi, {Qt::DisplayRole, Qt::FontRole});
}
QVector<RequestInfos> ExerciseAssignmentDialogModel::getRequestInfos(bool all) const
{
QVector<RequestInfos> requestInfos;
m_rootItem->getAllUnderlyingRequestInfos(requestInfos, all);
return requestInfos;
}
TreeItem::TreeItem(int mseId, int sectionId, const QString &displayName, int exerciseId, TreeItem *parentItem)
: m_mseId(mseId)
, m_sectionId(sectionId)
, m_displayName(displayName)
, m_exerciseId(exerciseId)
, m_originalExerciseId(exerciseId)
, m_parentItem(parentItem)
{
}
TreeItem::~TreeItem()
{
qDeleteAll(m_childItems);
}
void TreeItem::appendChild(TreeItem *child)
{
m_childItems.append(child);
}
TreeItem *TreeItem::child(int row)
{
if (row < 0 || row >= m_childItems.size())
return nullptr;
return m_childItems.at(row);
}
int TreeItem::childNumber() const
{
if (m_parentItem)
return m_parentItem->childItems().indexOf(const_cast<TreeItem*>(this));
return 0;
}
int TreeItem::childCount() const
{
return m_childItems.count();
}
void TreeItem::removeChild(int id)
{
delete(m_childItems.value(id));
m_childItems.removeAt(id);
}
void TreeItem::getAllUnderlyingRequestInfos(QVector<RequestInfos> &requestInfos, bool all) const
{
const QList<TreeItem*> &childItemsRef = childItems();
for (auto myChild : qAsConst(childItemsRef))
{
if (all || (myChild->exerciseId() != myChild->originalExerciseId()))
requestInfos.append({myChild->mseId(), myChild->exerciseId()});
myChild->getAllUnderlyingRequestInfos(requestInfos, all);
}
}
} // namespace InfrastructureManagement
//
@@ -0,0 +1,109 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#pragma once
#include <InfrastructureManagement/logger.h>
#include <ExerciseManagement/exm.hpp>
#include <QAbstractItemModel>
#include <QSet>
namespace InfrastructureManagement
{
/// RequestInfos
struct RequestInfos
{
int mseId;
int exerciseId;
};
// class ExerciseAssignmentDialogModel;
class TreeItem
{
public:
explicit TreeItem(int mseId, int sectionId, const QString &displayName, int exerciseId, TreeItem *parentItem = nullptr);
~TreeItem();
void appendChild(TreeItem *child);
void removeChild(int id);
TreeItem* child(int row);
int childNumber() const;
int childCount() const;
const QList<TreeItem*> childItems() const { return m_childItems; }
int sectionId() const { return m_sectionId; }
int mseId() const { return m_mseId; }
QString displayName() const { return m_displayName; }
void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; }
int exerciseId() const { return m_exerciseId; }
void setOriginalExerciseId(int exerciseId) { m_originalExerciseId = exerciseId; }
int originalExerciseId() const { return m_originalExerciseId; }
TreeItem* parentItem() { return m_parentItem; }
void getAllUnderlyingRequestInfos(QVector<RequestInfos> &requestInfos, bool all = false) const;
private:
int m_mseId;
int m_sectionId;
QString m_displayName;
int m_exerciseId;
int m_originalExerciseId;
QList<TreeItem*> m_childItems;
TreeItem* m_parentItem;
};
/// ExerciseAssignmentDialogModel
class ExerciseAssignmentDialogModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit ExerciseAssignmentDialogModel(const QMap<qint32, ExerciseManagement::Exercise> &exercises, QObject *parent = nullptr) noexcept(false);
~ExerciseAssignmentDialogModel();
void addMse(int mseId, int sectionId, const QString &displayName, int exerciseId);
void updateMse(int mseId, int sectionId, const QString &displayName, int exerciseId);
void removeMse(int mseId);
QModelIndex findItemByMseId(int mseId) const;
void setExerciseId(const QModelIndex &mi, int exerciseId);
int exerciseId(const QModelIndex &mi) const { return treeItem(mi) ? treeItem(mi)->exerciseId() : -1; }
int mseId(const QModelIndex &mi) const { return treeItem(mi) ? treeItem(mi)->mseId() : 0; }
QVector<RequestInfos> getRequestInfos(bool all = false) const;
QSet<int> childMses(const QModelIndex &mi, int exerciseId) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
protected:
int rowCount(const QModelIndex &parent = {}) const override;
QVariant data(const QModelIndex &index, int role) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &index) const override;
int columnCount(const QModelIndex &) const override { return 2; }
Qt::DropActions supportedDropActions() const override;
private:
TreeItem* treeItem(const QModelIndex &index) const;
QModelIndex index(TreeItem *item) const;
TreeItem* m_rootItem;
QMap<qint32, ExerciseManagement::Exercise> m_exercises;
LOGGER_T m_logger;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,183 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#include "ism_exercise_assignment_dialog_proxy_model.h"
#include "ism_exercise_assignment_dialog_model.h"
#include <QMimeData>
namespace InfrastructureManagement
{
void ExerciseAssignmentDialogModelFilterProxy::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<ExerciseAssignmentDialogModel *>(sourceModel);
Q_ASSERT(m_sourceModel != nullptr);
QSortFilterProxyModel::setSourceModel(sourceModel);
}
void ExerciseAssignmentDialogModelFilterProxy::setExerciseId(int exerciseId)
{
m_exerciseId = exerciseId;
invalidateFilter();
}
bool ExerciseAssignmentDialogModelFilterProxy::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
{
const QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
if (!sourceIndex.isValid())
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
// Parents are true automatically...
if (m_sourceModel->mseId(sourceIndex) == 0)
return false;
return (m_sourceModel->exerciseId(sourceIndex) == m_exerciseId);
}
bool ExerciseAssignmentDialogModelFilterProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
return QString::localeAwareCompare(sourceModel()->data(left).toString(), sourceModel()->data(right).toString()) < 0;
}
QVariant ExerciseAssignmentDialogModelFilterProxy::headerData(int section, Qt::Orientation orientation, int role) const
{
if (section == 0 && orientation == Qt::Orientation::Horizontal && role == Qt::DisplayRole)
return m_exerciseId > 0 ? tr("Assigned Buildings") : tr("Unassigned Buildings");
return m_sourceModel->headerData(section, orientation, role);
}
QMimeData *ExerciseAssignmentDialogModelFilterProxy::mimeData(const QModelIndexList &indexes) const
{
QJsonObject root;
QJsonArray mseIds;
for(const QModelIndex mi : indexes)
{
QModelIndex miSource = mapToSource(mi);
int mseId = m_sourceModel->mseId(miSource);
if (mseId <= 0)
{
const QSet<int> childMses = m_sourceModel->childMses(miSource, m_exerciseId);
for (int mse : qAsConst(childMses))
mseIds << mse;
}
else
mseIds << mseId;
}
root[QStringLiteral("eams")] = mseIds;
root[QStringLiteral("oldExerciseId")] = m_exerciseId;
QMimeData *mimeData = new QMimeData;
mimeData->setData(QStringLiteral("rheinmetall/exercise-assignment"), QJsonDocument(root).toJson());
return mimeData;
}
Qt::ItemFlags ExerciseAssignmentDialogModelFilterProxy::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = Qt::ItemIsDropEnabled | QAbstractItemModel::flags(index);
if (index.isValid())
f |= Qt::ItemIsDragEnabled;
return f;
}
bool ExerciseAssignmentDialogModelFilterProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
if (!canDropMimeData(data, action, row, column, parent))
return false;
const JsonObject root(JsonObject::fromJson(data->data(QStringLiteral("rheinmetall/exercise-assignment"))));
const JsonArray eams(root.value<JsonArray>(QStringLiteral("eams")));
QSet<QModelIndex> setToExpand;
const QVector<int> &eamsVec = eams.toVector<int>();
for (int mseId : qAsConst(eamsVec))
{
QModelIndex sourceMi = m_sourceModel->findItemByMseId(mseId);
setToExpand.insert(sourceMi.parent());
if (sourceMi.isValid())
m_sourceModel->setExerciseId(sourceMi, m_exerciseId);
}
// Don't know why we have to do this, as always "dataChanged()" is emitted...
invalidateFilter();
emit doRefilter(setToExpand);
return true;
}
Qt::DropActions ExerciseAssignmentDialogModelFilterProxy::supportedDropActions() const
{
return Qt::MoveAction;
}
bool ExerciseAssignmentDialogModelFilterProxy::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(parent)
if (action != supportedDropActions())
return false;
const JsonObject root(JsonObject::fromJson(data->data(QStringLiteral("rheinmetall/exercise-assignment"))));
int oldExerciseId = root.value<int>(QStringLiteral("oldExerciseId"));
return oldExerciseId != m_exerciseId;
}
} // namespace InfrastructureManagement
//
@@ -0,0 +1,122 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#pragma once
#include <InfrastructureManagement/logger.h>
#include <QSortFilterProxyModel>
#include <LtsUtilsCore/json_object.h>
using namespace LtsUtils;
namespace InfrastructureManagement
{
class ExerciseAssignmentDialogModel;
/// ExerciseAssignmentDialogModelFilterProxy
class ExerciseAssignmentDialogModelFilterProxy : public QSortFilterProxyModel
{
Q_OBJECT
public:
ExerciseAssignmentDialogModelFilterProxy(QObject *parent)
: QSortFilterProxyModel(parent)
, m_exerciseId(0)
, m_logger(getLogger("ExerciseAssignmentDialogModelFilterProxy"))
{
setRecursiveFilteringEnabled(true);
}
void setSourceModel(QAbstractItemModel *sourceModel) override;
void setExerciseId(int exerciseId);
signals:
void doRefilter(const QSet<QModelIndex> &setToExpand);
protected:
bool filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &rioght) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
int columnCount(const QModelIndex &) const override { return 1; }
QMimeData* mimeData(const QModelIndexList &_indexes) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
Qt::DropActions supportedDropActions() const override;
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
QStringList mimeTypes() const override
{
return { QStringLiteral("rheinmetall/exercise-assignment") };
}
class ExerciseAssignmentMime
{
public:
ExerciseAssignmentMime(const JsonObject &root) noexcept(false) // drop
: m_mseId(root.value<int>(QStringLiteral("mseId")))
{}
ExerciseAssignmentMime(int mseId) noexcept(false) // drag
: m_mseId(mseId)
{}
QJsonObject toJson() const
{
return { { QStringLiteral("mseId"), m_mseId } };
}
int mseId() const { return m_mseId; }
private:
int m_mseId;
};
private:
int m_exerciseId;
ExerciseAssignmentDialogModel *m_sourceModel;
LOGGER_T m_logger;
};
} // namespace InfrastructureManagement
//
@@ -0,0 +1,119 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#include "ism_exercise_assignment_dialog_requesters.h"
#include "ism_exercise_assignment_dialog_model.h"
#include <QFont>
#include <QGuiApplication>
#include <QMimeData>
#ifdef LTS_DEBUG
#include <QTimer> // ftc delay
#endif
namespace InfrastructureManagement
{
/// MSEModifyRequestCollector
void MSEModifyRequestCollector::next()
{
if (m_requests.isEmpty())
{
emit finished(m_canceled);
return;
}
MSEModifyRequester *requester = new MSEModifyRequester;
const QPair<RequestInfos, MainStructureElementModifyRequest> request(m_requests.takeFirst());
connect(requester, &MSEModifyRequester::finished,
this, [this](const QString &msg)
{
bool failed = (!msg.isEmpty());
if (failed)
{
m_failedCount++;
}
else
{
// ri.model->unchange(ri.rowId);
}
emit requestComplete(failed);
if (m_canceled)
m_requests.clear();
next();
});
auto go = [this, request, requester]()
{
m_ftc->mainStructureElementModifyRequest(request.second, requester);
};
#ifdef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
{
QTimer::singleShot(3000, this, go);
return;
}
#endif
go();
}
} // namespace InfrastructureManagement
//
@@ -0,0 +1,132 @@
/**
* @RDE_HEADER@
* $Id: $
* $HeadURL: $
* $Author: $
*
* Created by Mike Wille, SLTE, 2022-09-27
*/
#pragma once
#include "ism_exercise_assignment_dialog_model.h"
#include <InfrastructureManagement/ism_ftc.h>
#include <QObject>
#include <QVector>
#include <QPair>
namespace InfrastructureManagement
{
/// MSEModifyRequester
class MSEModifyRequester : public QObject,
public Interface::Ftc::MainStructureElementModifyReplyHandler
{
Q_OBJECT
public:
MSEModifyRequester()
: QObject() // do NOT parent!
{}
void onMainStructureElementModifyReply(const Core::FunctionReplyObject &reply) override
{
if (reply.error())
emit finished(reply.translated());
else
emit finished({});
deleteLater();
}
signals:
void finished(const QString &msg);
};
/// MSEModifyRequestCollector
class MSEModifyRequestCollector : public QObject
{
Q_OBJECT
public:
MSEModifyRequestCollector(std::shared_ptr<Interface::Ftc> &ftc, QObject *parent)
: QObject(parent)
, m_ftc(ftc)
{}
void addRequest(const RequestInfos &requestInfos, const MainStructureElementModifyRequest &request)
{
m_requests += QPair<RequestInfos, MainStructureElementModifyRequest>(requestInfos, request);
}
void cancel()
{
m_canceled = true;
}
void go()
{
next();
}
int count() const
{
return m_requests.count();
}
int failedCount() const
{
return m_failedCount;
}
private slots:
void next();
signals:
void finished(bool canceled);
void requestComplete(bool failed);
private:
QVector<QPair<RequestInfos, MainStructureElementModifyRequest> > m_requests;
std::shared_ptr<Interface::Ftc> m_ftc;
bool m_canceled = false;
int m_failedCount = 0;
};
} // namespace InfrastructureManagement
//
@@ -0,0 +1,382 @@
/**
* @RDE_HEADER@
* The MountingPointInfoDialog shows information about a single mounting point
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-01-12
*/
#include "ism_mounting_point_info_dialog.h"
#include "ui_ism_mounting_point_info_dialog.h"
#include <InfrastructureManagement/ism_translation.h>
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <AudioVideoManagement/ava_session.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
namespace InfrastructureManagement
{
MountingPointInfoDialog::MountingPointInfoDialog(int32_t mountingPointId, int32_t scheduleId, const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_ui(new Ui::MountingPointInfoDialog)
, m_mountingPointId(mountingPointId)
, m_assetId(-1)
, m_scheduleId(scheduleId)
, m_menuGroup(menuGroup)
, m_dtc(nullptr)
, m_ismIfc(nullptr)
, m_avmIfc(nullptr)
, m_logger(getLogger("MountingPointInfoDialog"))
{
m_ui->setupUi(this);
m_ui->gbxAsset->hide();
}
MountingPointInfoDialog::~MountingPointInfoDialog()
{
delete m_ui;
qDeleteAll(m_dynamicAssetPropLabels);
}
void MountingPointInfoDialog::retranslate()
{
//nfrastructureManagement::InstrumentationAsset ia = m_dtc->instrumentationAsset(m_mountingPointId);
StructureElement se;
m_dtc->getStructureElementById(m_mountingPointId, se);
QString seName = QString::fromStdString(se.displayName()).trimmed();
QString lbName;
// display name is composed by mse name and se name => se.displayname
// when se.displayname is empty > we will manually compose it.
if(seName.isEmpty())
{
MainStructureElement mse= m_dtc->mainStructureElement(se.mainStructureElementId());
lbName = QString::fromStdString(mse.name()) + QStringLiteral(" - ") + QString::fromStdString(se.name());
}
else
{
lbName = seName.replace(QStringLiteral("bldg_"), QStringLiteral(""));
}
translate(m_ui, lbName);
}
bool MountingPointInfoDialog::init(const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ForeignDataInterface> &ismIfc,
const std::shared_ptr<AudioVideoManagement::ForeignDataInterface> &avmIfc)
{
DEBUG_LOG(m_logger) << "Initializing MountingPointInfoDialog ...";
disconnect();
m_dtc = dtc;
m_ismIfc = ismIfc;
m_avmIfc = avmIfc;
StructureElement mountingPointData;
if (!(dtc != nullptr &&
m_dtc->enableInstrumentationAsset() &&
m_dtc->enableMountingPointAsset() &&
m_dtc->enableMainStructureElement() &&
m_dtc->enableMainSchedule() &&
m_dtc->waitForHistoricalDataInstrumentationAsset(10000) &&
m_dtc->waitForHistoricalDataMountingPointAsset(10000) &&
m_dtc->waitForHistoricalDataMainStructureElement(10000) &&
m_dtc->waitForHistoricalDataMainSchedule(10000) &&
m_dtc->getStructureElementById(m_mountingPointId, mountingPointData) &&
connect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged,
this, &MountingPointInfoDialog::onInstrumentationAssetChanged) &&
connect(m_dtc.get(), &Interface::Dtc::mountingPointAssetChanged,
this, &MountingPointInfoDialog::onMountingPointAssetChanged) &&
connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged,
this, &MountingPointInfoDialog::onMainScheduleChanged)
))
return false;
m_ui->lblNameEntry->setText(QString::fromStdString(mountingPointData.name()));
m_ui->lblTypeEntry->setText(toString(mountingPointData.mountingPointTypeId()));
if (mountingPointData.mountingPointTypeId() != MountingPointType::OutdoorCamera &&
mountingPointData.mountingPointTypeId() != MountingPointType::MeteoDataUnit &&
mountingPointData.mountingPointTypeId() != MountingPointType::VirtualIPS)
{
// searching path backwards until we find a building structure element
QMap<StructureElementType, QString> names;
for (int parentId = mountingPointData.path().size() - 1; parentId >= 0; --parentId)
{
StructureElement parent;
m_dtc->getStructureElementById(mountingPointData.path().at(parentId), parent);
names[parent.structureElementTypeId()] = QString::fromStdString(parent.displayName().size() > 0 ? parent.displayName() : parent.name());
if (StructureElementType::Building == parent.structureElementTypeId().underlying())
break;
}
// Building lbl
m_ui->lblBuildingEntry->setText(names.value(StructureElementType::Building));
m_ui->lblPosition->hide();
m_ui->lblPositionEntry->hide();
// Floor lbl
if (names.contains(StructureElementType::Floor))
m_ui->lblFloorEntry->setText(names.value(StructureElementType::Floor));
else
{
m_ui->lblFloorEntry->hide();
m_ui->lblFloor->hide();
}
// Room lbl
if (names.contains(StructureElementType::Room))
m_ui->lblRoomEntry->setText(names.value(StructureElementType::Room));
else
{
m_ui->lblRoomEntry->hide();
m_ui->lblRoom->hide();
}
}
else
{
// hide what isn't needed
m_ui->lblBuildingEntry->hide();
m_ui->lblBuilding->hide();
m_ui->lblFloorEntry->hide();
m_ui->lblFloor->hide();
m_ui->lblRoomEntry->hide();
m_ui->lblRoom->hide();
MainStructureElement mainStructure = m_dtc->mainStructureElement(mountingPointData.mainStructureElementId());
m_ui->lblPositionEntry->setText(LtsCoordTrans::mgrsFromGeographic(mainStructure.geoPosition().lon(),
mainStructure.geoPosition().lat()));
}
if (mountingPointData.mountingPointTypeId() == MountingPointType::OutdoorCamera ||
mountingPointData.mountingPointTypeId() == MountingPointType::IndoorCamera)
{
connect(m_ui->pbShowStream, &QToolButton::clicked, this, &MountingPointInfoDialog::onShowStream);
m_ui->pbShowStream->setVisible(m_avmIfc->hasAvsSession() && m_avmIfc->avaSession()->isEstablished());
m_ui->pbAnnouncement->hide();
}
else
{
connect(m_ui->pbAnnouncement, &QToolButton::clicked, this, &MountingPointInfoDialog::onAnnouncement);
m_ui->pbShowStream->hide();
m_ui->pbAnnouncement->setVisible(m_avmIfc->hasAvsSession() && m_avmIfc->avaSession()->isEstablished());
}
setIsIncluded(m_dtc->mainSchedule(m_scheduleId));
// set the asset (if possible)
QMap<qint32, MountingPointAsset> mpAssets = m_dtc->mountingPointAssets();
for (auto it = mpAssets.begin(); it != mpAssets.end(); ++it)
{
if (it.value().structureElementId() == m_mountingPointId)
{
showAsset(m_dtc->instrumentationAsset(it.value().assetId()));
break;
}
}
switch (mountingPointData.mountingPointTypeId().underlying())
{
case InfrastructureManagement::MountingPointType::BuildingSensorModule:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Building_Sensor_Module"));
break;
case InfrastructureManagement::MountingPointType::BuildingControlUnit:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Building_Control_Unit"));
break;
case InfrastructureManagement::MountingPointType::OutdoorCamera:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Outdoor_Camera"));
break;
case InfrastructureManagement::MountingPointType::IndoorCamera:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Indoor_Camera"));
break;
case InfrastructureManagement::MountingPointType::OutdoorIPS:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Outdoor_IPS"));
break;
case InfrastructureManagement::MountingPointType::IndoorIPS:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Indoor_IPS"));
break;
case InfrastructureManagement::MountingPointType::MeteoDataUnit:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Meteo_Data_Unit"));
break;
case InfrastructureManagement::MountingPointType::AnnouncementUnit:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Announcement_Unit"));
break;
case InfrastructureManagement::MountingPointType::VirtualIPS:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Virtual_IPS"));
break;
case InfrastructureManagement::MountingPointType::EffectGenerationControlUnit:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Effect_Generation_Control_Unit"));
break;
case InfrastructureManagement::MountingPointType::BuildingNetworkSwitch:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Building_Network_Switch_Control_Unit"));
break;
case InfrastructureManagement::MountingPointType::OutdoorControlUnit:
setOnlineHelpFilename(QStringLiteral("Info_Dialog-Outdoor_Control_Unit"));
break;
case InfrastructureManagement::MountingPointType::Unknown:
default:
WARNING_LOG(m_logger) << "Unknown MountingPointType found for assetId " << m_assetId << ": " << toString(mountingPointData.mountingPointTypeId());
break;
} // switch
DEBUG_LOG(m_logger) << "Initializing MountingPointInfoDialog done :)";
return true;
}
void MountingPointInfoDialog::onInstrumentationAssetChanged(const InfrastructureManagement::InstrumentationAsset &data, DataModification modType)
{
if (data.id() != m_assetId)
return;
if (modType == DataModification::eRemoved)
removeAsset();
else
showAsset(data);
}
void MountingPointInfoDialog::onMountingPointAssetChanged(const InfrastructureManagement::MountingPointAsset &data, DataModification modType)
{
if (data.structureElementId() != m_mountingPointId)
return;
if (modType == DataModification::eRemoved)
removeAsset();
else
showAsset(m_dtc->instrumentationAsset(data.assetId()));
}
void MountingPointInfoDialog::onMainScheduleChanged(const InfrastructureManagement::MainSchedule &data, DataModification modType)
{
if (data.id() != m_scheduleId ||
modType != DataModification::eModified)
return;
setIsIncluded(data);
}
void MountingPointInfoDialog::onShowStream() const
{
if (!m_avmIfc)
{
ERROR_LOG(m_logger) << "m_avmIfc is not loaded.";
return;
}
m_avmIfc->showCamera(/*m_session->baseLayoutWidget()*/nullptr, m_mountingPointId);
}
void MountingPointInfoDialog::onAnnouncement() const
{
if (!m_avmIfc)
{
ERROR_LOG(m_logger) << "m_avmIfc is not loaded.";
return;
}
m_avmIfc->showAnnouncementUnit(m_mountingPointId);
}
void MountingPointInfoDialog::showAsset(const InfrastructureManagement::InstrumentationAsset &asset)
{
removeAsset();
DEBUG_LOG(m_logger) << "Showing new asset";
m_assetId = asset.id();
addAssetProperty(tr("Name"), QString::fromStdString(asset.name()));
addAssetProperty(tr("State"), toString(asset.assetStateId()));
addAssetProperty(tr("Hostname"), QString::fromStdString(asset.hostname()));
addAssetProperty(tr("Barcode"), QString::fromStdString(asset.barcode()));
const QJsonObject dynamicProps(QJsonDocument::fromJson(QByteArray::fromStdString(asset.properties())).object());
for (auto it = dynamicProps.begin(); it != dynamicProps.end(); ++it)
{
if (it.key() == QStringLiteral("hasSpeaker") && it.value() == true)
{
// Show Button Announcement
connect(m_ui->pbAnnouncement, &QToolButton::clicked, this, &MountingPointInfoDialog::onAnnouncement);
m_ui->pbAnnouncement->setVisible(m_avmIfc->hasAvsSession() && m_avmIfc->avaSession()->isEstablished());
}
addAssetProperty(it.key(), jsonValToString(it.value()));
}
m_ui->gbxAsset->show();
}
void MountingPointInfoDialog::removeAsset()
{
DEBUG_LOG(m_logger) << "Removing asset information";
m_assetId = -1;
m_ui->gbxAsset->hide();
for (QLabel *lbl : qAsConst(m_dynamicAssetPropLabels))
m_ui->gbxAsset->layout()->removeWidget(lbl);
qDeleteAll(m_dynamicAssetPropLabels);
m_dynamicAssetPropLabels.clear();
}
void MountingPointInfoDialog::addAssetProperty(const QString &propName, const QString &propValue)
{
DEBUG_LOG(m_logger) << "Adding asset property "
<< propName
<< ':'
<< propValue;
QLabel *lblPropName = new LtsWidgets::LtsElidedLabel(propName + QLatin1Char(':'));
QLabel *lblPropValue = new QLabel(propValue);
m_dynamicAssetPropLabels.append(lblPropName);
m_dynamicAssetPropLabels.append(lblPropValue);
QGridLayout *assetsLayout = static_cast<QGridLayout *>(m_ui->gbxAsset->layout());
int row = assetsLayout->rowCount();
assetsLayout->addWidget(lblPropName, row, 0);
assetsLayout->addWidget(lblPropValue, row, 1);
}
void MountingPointInfoDialog::setIsIncluded(const MainSchedule &schedule)
{
for (const MountingPointPlan &currentPlan : schedule.elements())
{
if (currentPlan.structureElementId() == m_mountingPointId)
{
m_ui->lblIncludedEntry->setText(tr("Yes"));
return;
}
}
m_ui->lblIncludedEntry->setText(tr("No"));
}
QString MountingPointInfoDialog::jsonValToString(const QJsonValue &val) const
{
switch (val.type())
{
case QJsonValue::Bool:
case QJsonValue::Double:
case QJsonValue::String:
return val.toVariant().toString();
case QJsonValue::Array:
return QString::fromUtf8(QJsonDocument(val.toArray()).toJson(QJsonDocument::Compact));
case QJsonValue::Object:
return QString::fromUtf8(QJsonDocument(val.toObject()).toJson(QJsonDocument::Compact));
case QJsonValue::Null:
case QJsonValue::Undefined:
default:
return QString();
}
}
} // namespace InfrastructureManagement
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* The MountingPointInfoDialog shows information about a single mounting point
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-01-12
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <InfrastructureManagement/logger.h>
class QJsonValue;
class QLabel;
namespace Ui
{
class MountingPointInfoDialog;
}
namespace InfrastructureManagement
{
class MountingPointInfoDialog
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit MountingPointInfoDialog(int32_t mountingPointId, int32_t scheduleId, const QString &menuGroup, QWidget *parent = nullptr);
~MountingPointInfoDialog();
bool init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<InfrastructureManagement::ForeignDataInterface> &ismIfc,
const std::shared_ptr<AudioVideoManagement::ForeignDataInterface> &avmIfc);
private Q_SLOTS:
void onInstrumentationAssetChanged(const InfrastructureManagement::InstrumentationAsset &data, DataModification modType);
void onMountingPointAssetChanged(const InfrastructureManagement::MountingPointAsset &data, DataModification modType);
void onMainScheduleChanged(const InfrastructureManagement::MainSchedule &data, DataModification modType);
void onShowStream() const;
void onAnnouncement() const;
private: // methods
void retranslate() override;
void showAsset(const InfrastructureManagement::InstrumentationAsset &asset);
void removeAsset();
void addAssetProperty(const QString &propName, const QString &propValue);
void setIsIncluded(const MainSchedule &schedule);
QString jsonValToString(const QJsonValue &val) const;
private: // attributes
Ui::MountingPointInfoDialog *m_ui;
int32_t m_mountingPointId;
int32_t m_assetId;
int32_t m_scheduleId;
QString m_menuGroup;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_ismIfc;
std::shared_ptr<AudioVideoManagement::ForeignDataInterface> m_avmIfc;
QVector<QLabel *> m_dynamicAssetPropLabels;
LOGGER_T m_logger;
}; // class MountingPointInfoDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MountingPointInfoDialog</class>
<widget class="QWidget" name="MountingPointInfoDialog">
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="7" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblPosition">
<property name="text">
<string>Position:</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QToolButton" name="pbAnnouncement">
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../Styles/Light/resources/rme_light_style.qrc">
<normaloff>:/style/announcement_menu.svg</normaloff>:/style/announcement_menu.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="pbShowStream">
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="text">
<string notr="true">...</string>
</property>
<property name="icon">
<iconset resource="../../../../Styles/Light/resources/rme_light_style.qrc">
<normaloff>:/style/video_menu.svg</normaloff>:/style/video_menu.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblBuilding">
<property name="text">
<string>Building:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblIncluded">
<property name="text">
<string>Included:</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblRoom">
<property name="text">
<string>Room:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblIcon">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblFloor">
<property name="text">
<string>Floor:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="LtsWidgets::LtsElidedLabel" name="lblType">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="lblNameEntry">
<property name="text">
<string notr="true">&lt;NAME&gt;</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="lblTypeEntry">
<property name="text">
<string notr="true">&lt;TYPE&gt;</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="4">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0" colspan="4">
<widget class="QGroupBox" name="gbxAsset">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Equipped asset</string>
</property>
<layout class="QGridLayout" name="gridLayout"/>
</widget>
</item>
<item row="7" column="2" colspan="2">
<widget class="QLabel" name="lblPositionEntry">
<property name="text">
<string notr="true">&lt;POSITION&gt;</string>
</property>
</widget>
</item>
<item row="6" column="2" colspan="2">
<widget class="QLabel" name="lblRoomEntry">
<property name="text">
<string notr="true">&lt;ROOM&gt;</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="2">
<widget class="QLabel" name="lblFloorEntry">
<property name="text">
<string notr="true">&lt;FLOOR&gt;</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="2">
<widget class="QLabel" name="lblBuildingEntry">
<property name="text">
<string notr="true">&lt;TYPE&gt;</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QLabel" name="lblIncludedEntry">
<property name="text">
<string notr="true">&lt;INCLUDED&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsElidedLabel</class>
<extends>QLabel</extends>
<header>LtsWidgets/lts_elided_label.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../../Styles/Light/resources/rme_light_style.qrc"/>
</resources>
<connections/>
</ui>
@@ -0,0 +1,811 @@
/**
* @RDE_HEADER@
* The MountingPointListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_mounting_point_list_dialog.h"
#include "ui_ism_mounting_point_list_dialog.h"
#include "ism_mounting_point_list_dialog_model.h"
#include "ism_mounting_point_list_dialog_checkbox_proxy_model.h"
#include "ism_mounting_point_list_dialog_checkbox_delegate.h"
#include "ism_mounting_point_list_dialog_list_sort_model.h"
#include <LtsUtilsGuiDds/request_helper.h>
#include <LtsUtilsCore/dds_vector.h>
#include <InfrastructureManagement/ism_translation.h>
#include <InfrastructureManagement/ism_operator_rights.h>
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <FilterManagement/flt_building_cmpnt_helper.h> // getVisibleTypesOfFilter
#include <SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <SituationMap/Map/map.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <LtsPrinting/printing.h>
#include <QItemDelegate>
#include <QTreeView>
#include <QListWidget>
#include <QMenu>
#include <QHeaderView>
#include <QScrollBar>
#include <QTimer>
using namespace LtsWidgets;
namespace InfrastructureManagement
{
/// DummyLtsColumnFilterProxyModel
class DummyLtsColumnFilterProxyModel : public LtsColumnFilterProxyModel
{
Q_OBJECT
public:
void setColumnStringFilter(const QString &, int ) override {}
void setColumnDataFilter(const QVariant &newFilterData, int column) override
{
emit signalSetColumnDataFilter(newFilterData, column);
}
bool filterAcceptsRow(int /*source_row*/, const QModelIndex &/*source_parent*/) const override
{
return true;
}
signals:
void signalSetColumnDataFilter(const QVariant &newFilterData, int column);
};
/// MountingPointListDialog
MountingPointListDialog::MountingPointListDialog(const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_menuGroup(menuGroup)
, m_ismGuiIfc(nullptr)
, m_mapGuiInterface(nullptr)
, m_typeFilterColumn(0)
, m_typeFilterRow(0)
, m_ddsSelector(nullptr)
, m_scheduleId(-1)
, m_ui(new Ui::MountingPointListDialog)
, m_logger(getLogger("MountingPointListDialog"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Mounting_Point_List"));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &MountingPointListDialog::onPrint);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
MountingPointListDialog::~MountingPointListDialog()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_mapGuiInterface->removeObjectIndicator();
m_mapGuiInterface->setSkipMapObjectSelectionDialog(false);
if (m_ismGuiIfc)
m_ismGuiIfc->setSelector(nullptr);
if (m_buildingComponentSettings)
m_buildingComponentSettings->removeChangedCallback(this);
m_mapGuiInterface->setResourceManagerMode(m_oldResourceManagerMode);
delete m_ui;
delete m_ddsSelector;
delete m_requestHelper;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void MountingPointListDialog::retranslate()
{
translate(m_ui, m_dtc->mainSchedule(m_scheduleId), tr("Mounting Point List"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("Unmount"));
}
bool MountingPointListDialog::init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
InfrastructureManagement::ForeignResourceManagementGuiInterface *ismGuiIfc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &mapIfc,
const std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> fltBuildingComponentIfc)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_dtc = dtc;
m_ftc = ftc;
m_dataIfc = dataInterface;
m_session = session;
m_mapGuiInterface = mapIfc;
m_ismGuiIfc = ismGuiIfc;
m_fltBuildingComponentIfc = fltBuildingComponentIfc;
disconnect(m_ui->mountingPointListView);
disconnect(this);
if (!m_ftc->enableInstrumentationAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT InstrumentationAssetModify of ISM";
return false;
}
if (!m_ftc->enableInstrumentationAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT enableInstrumentationAssetModify of ISM";
return false;
}
if (!m_ftc->enableInstrumentationAssetRemove())
{
ERROR_LOG(m_logger) << "Could not enable FT enableInstrumentationAssetRemove of ISM";
return false;
}
if (!m_ftc->enableInstrumentationAssetUnmount())
{
ERROR_LOG(m_logger) << "Could not enable FT enableInstrumentationAssetUnmount of ISM";
return false;
}
if (!m_ftc->enableMountingPointAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT MountingPointAssetModify of ISM";
return false;
}
if (!m_ftc->enableMountingPointAssetRemove())
{
ERROR_LOG(m_logger) << "Could not enable FT MountingPointAssetRemove of ISM";
return false;
}
if (!m_ftc->enableStructureElementModify())
{
ERROR_LOG(m_logger) << "Could not enable FT enableStructureElementModify of ISM";
return false;
}
delete m_sourceModel;
m_sourceModel = new MountingPointListDialogModel(this);
const QSet<MountingPointType> filters = { MountingPointType::BuildingSensorModule,
MountingPointType::OutdoorCamera,
// MountingPointType::BuildingControlUnit,
MountingPointType::IndoorCamera,
MountingPointType::OutdoorIPS,
MountingPointType::IndoorIPS,
MountingPointType::EffectGenerationControlUnit,
#ifndef GUEZ_MODE
MountingPointType::AnnouncementUnit,
MountingPointType::BuildingNetworkSwitch
#endif
};
m_sourceModel->setMntPointFilterTypes(filters);
if (!m_sourceModel->initModel(m_dtc, m_dataIfc))
{
ERROR_LOG(m_logger) << "Could not init model";
delete m_sourceModel;
m_sourceModel = nullptr;
return false;
}
connect(m_sourceModel, &MountingPointListDialogModel::changesMade,
this, &MountingPointListDialog::slotChangesMade); /*[this]
{
slotChangesMade();
});*/
delete m_sortProxyModel;
m_sortProxyModel = new MountingPointListSortModel(this);
m_sortProxyModel->setTypeFilter(filters);
m_sortProxyModel->setSourceModel(m_sourceModel);
delete m_checkboxProxyModel;
m_checkboxProxyModel = new CheckboxProxyModel;
/* OKAY, get this...:
* We need LtsDataView's filtering mechanism. But the CheckBoxProxyModel needs to be the *last* Proxy Model
* because it checks which Checkbox state a leaf's parent and its parent's parents has. If the LtsDataView
* does the filtering, then the CheckboxProxyModel doesn't know what lines were hidden, so the Checkbox
* states don't match.
* If LtsDataView is given an LtsColumnFilterProxyModel instead of an ItemModel, it will not create a
* LtsColumnFilterProxyModel for filtering, but use the given one instead.
* Here's the super hacky solution:
* 1. First we need a barebones LtsColumnFilterProxyModel as the LAST model instance, for the LtsDataView,
* which just sends a signa - when setColumnStringFilter was called - to ...
* 2. the REAL LtsColumnFilterProxyModel, which does the real filtering. It needs to be put BEFORE
* the CheckboxFilterProxy. So the CheckboxFilterProxy will see ALL rows that remain visible.
*/
// Model => Sort => rcfpm => CheckboxProxy => dcfpm => View
m_sortProxyModel->setRecursiveFilteringEnabled(true); // non-leafs don't have a type to filter by, so tell LtsDataView's filter proxy model to ignore these and still show them if at least ONE child (recursive) of a non-leaf is visible
LtsColumnFilterProxyModel *rcfpm = new LtsColumnFilterProxyModel; // the REAL filter, put before CheckboxFilterProxy.
rcfpm->setSourceModel(m_sortProxyModel);
rcfpm->setRecursiveFilteringEnabled(true); // non-leafs don't have a type to filter by, so tell LtsDataView's filter proxy model to ignore these and still show them if at least ONE child (recursive) of a non-leaf is visible
m_checkboxProxyModel->setSourceModel(rcfpm);
DummyLtsColumnFilterProxyModel *dcfpm = new DummyLtsColumnFilterProxyModel; // the fake filter, put as LAST instance. Source model is the CheckboxFilterProxy.
dcfpm->setRecursiveFilteringEnabled(true); // non-leafs don't have a type to filter by, so tell LtsDataView's filter proxy model to ignore these and still show them if at least ONE child (recursive) of a non-leaf is visible
connect(dcfpm, &DummyLtsColumnFilterProxyModel::signalSetColumnDataFilter,
rcfpm, &LtsColumnFilterProxyModel::onSetColumnDataFilter);
dcfpm->setSourceModel(m_checkboxProxyModel);
m_ui->mountingPointListView->setModel(dcfpm);
// Needed as otherwise changes to the model do not affect the visibility of Rooms and Levels.
connect(m_sourceModel, &MountingPointListDialogModel::dataChanged, m_sortProxyModel, &MountingPointListSortModel::invalidateFilter);
if (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SystemConfiguration))
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &MountingPointListDialog::onUnmountButtonClicked);
m_buttonBox->setIcon(LtsWidgets::DialogButton::Load, QIcon(QLatin1String("icon:fixed_video_announcement.svg")));
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(false);
}
// connect signals of TableView/CustomView: (for MapObjectIndicator
connect(m_ui->mountingPointListView, &LtsDataView::LtsDataView::clicked, this, &MountingPointListDialog::onDataViewClicked);
connect(m_ui->mountingPointListView, &LtsDataView::LtsDataView::signalEntered, this, &MountingPointListDialog::onDataViewEntered);
//------------- Filter ----------------
// SWPÄ 2/22 / GUEZE-1478:
// Diese Filter werden ersetzt durch übergeordnete BuildingComponentnFilter (Extras | SituationMap | BuildingComponent)
// subscribe to Filter:
if (m_fltBuildingComponentIfc)
{
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
m_buildingComponentSettings = m_fltBuildingComponentIfc->buildingComponentSettingsForOperator(operatorId, m_session->workspaceId());
if (m_buildingComponentSettings)
m_buildingComponentSettings->addChangedCallback(this); // will call onBuildingComponentSettingsChanged
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " addChangedCallback fltBuildingComponentIfc failed";
#ifdef LTS_DEBUG
Q_ASSERT(false);
#endif // LTS_DEBUG
}
// call on init:
onBuildingComponentSettingsChanged();
}else
{
ERROR_LOG(m_logger) << "No BuildingCOmponentIfc ";
}
// honor visibilityChanged (dialog toogles between foreground/background)
connect(this, &MountingPointListDialog::visibilityChanged, this, &MountingPointListDialog::onVisibilityChanged);
// show first tree level when activating the dialog
m_ui->mountingPointListView->treeView()->expandToDepth(0);
delete m_ddsSelector;
m_ddsSelector = nullptr;
m_ddsSelector = new DdsSelector(dtc, ftc, m_dataIfc, m_requestHelper);
// always select from the map when the dialog is visible
m_ismGuiIfc->setSelector(m_ddsSelector);
// SWPÄ GUEZE-1478 (?)
// Mit Aufschalten des Dialog wird umgeschaltet auf Modus SituationMap::ResourceManagerMode::RMM_PlanDefinitionView
// mit RMM_PlanDefinitionView sollte die Notification disabled werden...
// bis Ende des Dialoges...
m_oldResourceManagerMode = m_mapGuiInterface->resourceManagerMode();
// since switching _to_ RMM_PlanDefinitionView could be timeconsuming:
// (and give the GlobalWaitDialog time being displayed)
QTimer::singleShot(100, this, [this] () {
m_mapGuiInterface->setResourceManagerMode(SituationMap::ResourceManagerMode::RMM_PlanDefinitionView);
});
m_mapGuiInterface->setSkipMapObjectSelectionDialog(true);
m_scheduleId = m_dataIfc->scheduleId();
connect(m_dataIfc.get(), &ForeignDataInterface::scheduleIdChanged,
this, &MountingPointListDialog::onScheduleIdChanged);
m_ui->mountingPointListView->setContextMenuPolicyPerView(LtsDataView::LtsDataView::Page::TABLE, Qt::CustomContextMenu);
connect(m_ui->mountingPointListView->treeView(), &QTreeView::customContextMenuRequested,
this, &MountingPointListDialog::onCustomContextMenu);
m_ui->mountingPointListView->treeView()->setColumnWidth(0, 500);
m_ui->mountingPointListView->treeView()->setColumnWidth(1, 300);
m_ui->mountingPointListView->treeView()->setColumnWidth(2, 300);
m_ui->mountingPointListView->treeView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
m_ui->mountingPointListView->searchView()->setColumnWidth(0, 500);
m_ui->mountingPointListView->searchView()->setColumnWidth(1, 300);
m_ui->mountingPointListView->searchView()->setColumnWidth(2, 300);
m_ui->mountingPointListView->searchView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
connect(m_ui->mountingPointListView->searchView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->mountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
connect(m_ui->mountingPointListView->treeView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->mountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
m_ui->mountingPointListView->treeView()->setItemDelegateForColumn(MountingPointListDialogModel::Columns::NAME, new CheckboxDelegate);
// connect onEscapePressed of Map:
if (m_mapGuiInterface && m_mapGuiInterface->map())
connect(m_mapGuiInterface->map().data(), &SituationMap::Map::escapePressed,
this, &MountingPointListDialog::onEscapePressed, Qt::UniqueConnection);
// InfoMountButton:
connect(m_ui->tbMountMode, &QToolButton::clicked,
this, &MountingPointListDialog::onInfoMountButtonClicked, Qt::UniqueConnection);
onUpdateInfoMountButtonAndBehaviour();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void MountingPointListDialog::getMountingPointPlanData(const QModelIndex &index, std::vector<MountingPointPlan>&modify, const QHash<int, MountingPointPlan> &mppMap)
{
NGLTreeItem *item = m_sourceModel->privateData(index);
if (!item)
return;
if (item->data().canConvert<SimpleMountingPointData>())
{
const SimpleMountingPointData &data = item->data().value<SimpleMountingPointData>();
DEBUG_LOG(m_logger) << "Item: " << m_sourceModel->data(index, Qt::DisplayRole).toString()
<< ", Structure Element Id: " << data.id;
if (mppMap.contains(data.id))
{
if (data.aimState != mppMap[data.id].mountingPointState())
modify.push_back(MountingPointPlan(data.id, data.aimState));
}
else if (data.aimState != MountingPointState_def::Idle)
{
DEBUG_LOG(m_logger) << "Not available in Map. Desired: " << data.aimState;
modify.push_back(MountingPointPlan(data.id, data.aimState));
}
}
for (int i =0 ; i< m_sourceModel->rowCount(index); i++ )
getMountingPointPlanData(m_sourceModel->index(i, 0, index), modify, mppMap);
}
bool MountingPointListDialog::hasMountingPointMountedAsset(const QModelIndex &index)
{
NGLTreeItem *treeItem = m_sourceModel->privateData(mapToSourciest(index));
if (!treeItem)
return false;
QVariant v = treeItem->data();
if (v.canConvert<SimpleMountingPointData>())
{
// MountingPoint:
const SimpleMountingPointData itemData = v.value<SimpleMountingPointData>();
int assetId = m_dtc->getMountedAssetId(itemData.id);
return !(assetId == -1);
}
return false;
}
void MountingPointListDialog::onMountingPointPlanModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onInstrumentationAssetModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onInstrumentationAssetUnmountReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onMountingPointAssetModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onMountingPointAssetRemoveReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MountingPointListDialog::onBuildingComponentSettingsChanged()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
// update view via m_sortProxyModel:
if (!m_buildingComponentSettings)
return;
const FilterManagement::BuildingComponentSettings::BldCmpSettings &bldCmpSettings =
m_buildingComponentSettings->bldCmpSettings();
// 1) setTypeFilter:
{
const QSet<MountingPointType> visibleTypes = FilterManagement::getVisibleTypesOfFilter(bldCmpSettings);
m_sortProxyModel->setTypeFilter(visibleTypes);
}
// 2) floor:
{
// '-10' is floorId of Exterior / Outdoor
// Filter has HIDDEN floorIds
// (good reason: if filter not available (or nothing is checked), show all item on map...)
// so translate here to visibleFloors:
const QSet<int> &hiddenFloorIds = bldCmpSettings.buildingSettings.hiddenFloorIds;
const QSet<int> &availableFloors = m_sourceModel->getAvailableFloors();
QSet<int> visibleFloors;
for (int floor : availableFloors)
if (!hiddenFloorIds.contains(floor))
visibleFloors.insert(floor);
// qCritical() << " hiddenFloorIds" << hiddenFloorIds;
// qCritical() << " availableFloors" << availableFloors;
// qCritical() << " visibleFloors" << visibleFloors;
m_sortProxyModel->setFloorFilter(visibleFloors);
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
bool MountingPointListDialog::apply()
{
std::vector<MountingPointPlan> modify;
const QModelIndex root = m_sourceModel->getIndexOfVisibleRootItem();
if (!root.isValid())
return false;
MainSchedule mainSchedule = m_dataIfc->mainSchedule(m_dataIfc->scheduleId());
QHash<int,MountingPointPlan> mppMap;
for(const auto &elem : mainSchedule.elements())
mppMap[elem.structureElementId()] = elem;
getMountingPointPlanData(root, modify, mppMap);
if (modify.empty())
return true;
MountingPointPlanModifyRequest req(m_dataIfc->scheduleId(), modify);
return m_requestHelper->startSingleRequest([req, this]()
{
return m_ftc->mountingPointPlanModifyRequest(req, this);
});
}
void MountingPointListDialog::onPrint()
{
MainSchedule ms = m_dtc->mainSchedule(m_dataIfc->scheduleId());
QString header;
header += QStringLiteral("<p>");
header += tr("Instrumentation Plan: %1").arg(QString::fromStdString(ms.name()));
header += QStringLiteral("<br/>");
header += tr("Status: %1").arg(toString(ms.statusId()));
header += QStringLiteral("<br/>");
header += tr("Created: %1").arg(DTG::toStringMSec(ms.timeCreated()));
header += QStringLiteral("<br/>");
if (ms.timeStart().is_set())
header += tr("START: %1").arg(DTG::toStringMSec(ms.timeStart().get()));
else
header += tr("START: %1").arg(tr("[N/A]"));
header += QStringLiteral(" - ");
if (ms.timeEnd().is_set())
header += tr("END: %1").arg(DTG::toStringMSec(ms.timeEnd().get()));
else
header += tr("END: %1").arg(tr("[N/A]"));
header += QStringLiteral("<br/>");
header += QStringLiteral("</p>");
m_ui->mountingPointListView->expandAll();
LtsPrinting::printView(m_session, this, m_ui->mountingPointListView->treeView(), header);
}
void MountingPointListDialog::onScheduleIdChanged(int32_t scheduleId)
{
if (scheduleId == m_scheduleId)
return;
// scheduleId changed, data is maybe invalid -> close dialog:
deleteLater();
}
void MountingPointListDialog::onVisibilityChanged(bool visible)
{
Q_UNUSED(visible);
// maybe dialog is put to background -> leave mount mode:
onUpdateInfoMountButtonAndBehaviour();
}
void MountingPointListDialog::onCustomContextMenu(QPoint pos)
{
QMenu *contextMenu = new QMenu(this);
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
{
QAction *action = new QAction(tr("Expand All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->mountingPointListView->expandAll();
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->mountingPointListView->collapseAll();
});
contextMenu->addAction(action);
}
contextMenu->addSeparator();
QModelIndex index = m_ui->mountingPointListView->treeView()->indexAt(pos);
bool hasChildren = m_ui->mountingPointListView->treeView()->model()->rowCount(index) > 0;
{
QAction *action = new QAction(tr("Expand"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
#if QT_VERSION < QT_VERSION_CHECK(5,13,0)
m_ui->mountingPointListView->treeView()->expand(index);
#else
m_ui->mountingPointListView->treeView()->expandRecursively(index);
#endif
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
m_ui->mountingPointListView->treeView()->collapse(index);
});
contextMenu->addAction(action);
}
contextMenu->popup(m_ui->mountingPointListView->treeView()->mapToGlobal(pos));
}
void MountingPointListDialog::onDataViewClicked(const QModelIndex &mi)
{
m_clickedObjectStore.reset();
onDataViewEntered(mi);
// suppress Entered for a while:
m_clickedObjectStore.timestampMsec = QDateTime::currentMSecsSinceEpoch();
bool enabled = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SystemConfiguration);
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setEnabled(hasMountingPointMountedAsset(mi) && enabled);
}
QModelIndex MountingPointListDialog::mapToSourciest(const QModelIndex &index)
{
QModelIndex currentIndex = index;
const QAbstractItemModel *model = index.model();
//qWarning() << "start" << model << currentIndex;
while (true)
{
const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel *>(model);
if (proxyModel == nullptr)
break;
model = proxyModel->sourceModel();
currentIndex = proxyModel->mapToSource(currentIndex);
//qWarning() << "new" << model << currentIndex;
}
//qWarning() << "done" << model << currentIndex;
return currentIndex;
}
void MountingPointListDialog::onDataViewEntered(const QModelIndex & mi)
{
if ( (QDateTime::currentMSecsSinceEpoch() - m_clickedObjectStore.timestampMsec) < 500)
return;
const QModelIndex &theIndex(mapToSourciest(mi));
NGLTreeItem *treeItem = m_sourceModel->privateData(theIndex);
if (!treeItem)
return;
const QVariant v(treeItem->data());
if (v.canConvert<SimpleStructureElementData>())
{
// Building:
const SimpleStructureElementData itemData = v.value<SimpleStructureElementData>();
m_clickedObjectStore.mot = SituationMap::MapObjectType::MOT_Building;
m_clickedObjectStore.entityId = itemData.mseId;
}
else if (v.canConvert<SimpleMountingPointData>())
{
// MountingPoint:
const SimpleMountingPointData itemData = v.value<SimpleMountingPointData>();
m_clickedObjectStore.mot = SituationMap::MapObjectType::MOT_MountingPoint;
m_clickedObjectStore.entityId = itemData.id;
}
else
{
m_clickedObjectStore.reset();
}
if (m_clickedObjectStore.entityId>=0)
{
m_mapGuiInterface->objectIndicatorToMapObject(m_clickedObjectStore.mot, m_clickedObjectStore.entityId, true);
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
m_mapGuiInterface->centerMapToMapObject(m_clickedObjectStore.mot, m_clickedObjectStore.entityId);
}
}
void MountingPointListDialog::onEscapePressed()
{
if (!m_mapGuiInterface)
return;
m_mapGuiInterface->removeObjectIndicator();
}
void MountingPointListDialog::onUnmountButtonClicked()
{
if (m_ui->mountingPointListView->selectionModel()->selectedRows().size() < 1)
return;
NGLTreeItem *treeItem = m_sourceModel->privateData(mapToSourciest(m_ui->mountingPointListView->currentIndex()));
if (!treeItem)
return;
const QVariant v = treeItem->data();
if (v.canConvert<SimpleMountingPointData>())
{
const SimpleMountingPointData itemData = v.value<SimpleMountingPointData>();
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(
this, tr("Do you really want to unmount asset on selected mounting point?"), tr("Unmount Assets"), LtsWidgets::Behaviour::Modal,
{ LtsWidgets::Button::Yes, LtsWidgets::Button::No });
if (button == LtsWidgets::Button::Yes)
{
const int assetId = m_dtc->getMountedAssetId(itemData.id);
if (assetId > 0)
{
InstrumentationAssetUnmountRequest req(assetId);
bool ret = m_requestHelper->startSingleRequest([req, this]()
{
return m_ftc->instrumentationAssetUnmountRequest(req, this);
});
if (!ret)
WARNING_LOG(m_logger)<<" couldn't unmount asset on MountingPoinAsset id: "<<req.id();
else
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load,false);
}
else // mounted asset id not found
{
LtsWidgets::LtsMessageDialog::showMessage(
this, tr("No mounted asset found on this mounting point"), tr("Unmount Assets"), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Ok);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load,false);
}
} // end if allow unmount asset
}
else
{
ERROR_LOG(m_logger)<<" Couldn't convert to SimpleMountingPointData: ";
}
}
void MountingPointListDialog::onInfoMountButtonClicked(bool)
{
// toggle btn and sitMap behaviour, but keep visibility in mind:
switch (m_infoMount) {
case InfoMount::IM_INFO:
m_infoMount = InfoMount::IM_MOUNT;
break;
case InfoMount::IM_MOUNT:
m_infoMount = InfoMount::IM_INFO;
break;
default:
// empty
break;
} // switch
onUpdateInfoMountButtonAndBehaviour();
}
void MountingPointListDialog::onUpdateInfoMountButtonAndBehaviour()
{
// // maybe dialog is put to background and is hidden now -> leave mount mode:
// // in that case switch to 'IM_INFO' tempoary:
InfoMount infoMountTemp = m_infoMount;
const bool bDialogIsVisi = this->isVisible();
if (!bDialogIsVisi)
infoMountTemp = InfoMount::IM_INFO;
switch (infoMountTemp) {
case InfoMount::IM_INFO:
{
QColor backgroundColor = QToolButton().palette().window().color();
QColor textColor = QGuiApplication::palette().color(QPalette::Text);
QString style = QStringLiteral("QToolButton { background-color: rgb(%1,%2,%3); color: rgb(%4,%5,%6) }")
.arg(backgroundColor.red()).arg(backgroundColor.green()).arg(backgroundColor.blue())
.arg(textColor.red()).arg(textColor.green()).arg(textColor.blue());
m_ui->tbMountMode->setText(tr("Info"));
m_ui->tbMountMode->setStyleSheet(style);
m_ui->tbMountMode->setToolTip(tr("Click on map object opens info dialog"));
m_ismGuiIfc->setSelector(nullptr);
m_mapGuiInterface->setSkipMapObjectSelectionDialog(false);
}
break;
case InfoMount::IM_MOUNT:
{
QColor color = QGuiApplication::palette().color(QPalette::Link);
QString style = QStringLiteral("QToolButton { background-color: rgb(%1,%2,%3); color: white }").arg(
QString::number(color.red()), QString::number(color.green()), QString::number(color.blue())
);
m_ui->tbMountMode->setStyleSheet(style);
m_ui->tbMountMode->setText(tr("Map Selection"));
m_ui->tbMountMode->setToolTip(tr("Click on map object toogles aim state"));
m_ismGuiIfc->setSelector(m_ddsSelector);
m_mapGuiInterface->setSkipMapObjectSelectionDialog(true);
}
break;
default:
// empty
break;
} // switch
}
//------------------------------------------------------------------------------
//( class ClickedObjectStore
//------------------------------------------------------------------------------
void MountingPointListDialog::ClickedObjectStore::reset()
{
mot = SituationMap::MapObjectType::MOT_Undefined;
entityId = -1;
timestampMsec = 0;
}
} // namespace InfrastructureManagement
#include "ism_mounting_point_list_dialog.moc"
@@ -0,0 +1,167 @@
/**
* @RDE_HEADER@
* The MountingPointListDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/logger.h>
#include <InfrastructureManagement/ism_data_plugin_interface.h>
#include <SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <InfrastructureManagement/Gui/ResourceManagement/MountingPointMapSelection/ism_dds_selector.h>
#include <InfrastructureManagement/Gui/ResourceManagement/MountingPointMapSelection/ism_selector.h>
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h> // honor current filter settings (menue SituationMap)
#include <FilterManagement/flt_building_cmpnt_settings.h> // hold current filter settings (and for addCSubscriberCallback)
#include <LtsWidgets/lts_dialog.h>
#include <LtsDataView/check_state_proxy_model.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <QItemDelegate>
class QCheckBox;
namespace Ui
{
class MountingPointListDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace SituationMap
{
enum class MapObjectType;
}
namespace InfrastructureManagement
{
class MountingPointListDialogModel;
class MountingPointListSortModel;
class CheckboxProxyModel;
class MountingPointListDialog final
: public LtsWidgets::LtsDialog
, protected Interface::Ftc::MountingPointPlanModifyReplyHandler
, protected Interface::Ftc::InstrumentationAssetUnmountReplyHandler
, protected Interface::Ftc::StructureElementModifyReplyHandler
, protected Interface::Ftc::InstrumentationAssetModifyReplyHandler
, protected Interface::Ftc::MountingPointAssetModifyReplyHandler
, protected Interface::Ftc::MountingPointAssetRemoveReplyHandler
, protected FilterManagement::BuildingComponentSettings::SettingsChangedCallback
{
Q_OBJECT
public:
explicit MountingPointListDialog(const QString &menuGroup, QWidget *parent = nullptr);
~MountingPointListDialog();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
InfrastructureManagement::ForeignResourceManagementGuiInterface *ismGuiIfc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &mapIfc,
const std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> fltBuildingComponentIfc
);
void onMountingPointPlanModifyReply(const Core::FunctionReplyObject &replyObject) override final;
void onInstrumentationAssetModifyReply(const Core::FunctionReplyObject &replyObject) override final;
void onInstrumentationAssetUnmountReply(const Core::FunctionReplyObject &replyObject) override final;
void onStructureElementModifyReply(const Core::FunctionReplyObject &replyObject) override final;
void onMountingPointAssetModifyReply(const Core::FunctionReplyObject &replyObject) override final;
void onMountingPointAssetRemoveReply(const Core::FunctionReplyObject &replyObject) override final;
void onBuildingComponentSettingsChanged() override final;
void getMountingPointPlanData(const QModelIndex &index, std::vector<MountingPointPlan> &add, const QHash<int, MountingPointPlan> &mppMap);
bool hasMountingPointMountedAsset(const QModelIndex &index);
friend class MountingPointSelector;
private slots:
void onVisibilityChanged(bool visible);
void onPrint();
void onScheduleIdChanged(int32_t scheduleId);
void onCustomContextMenu(QPoint pos);
void onDataViewClicked(const QModelIndex &mi);
void onDataViewEntered(const QModelIndex &mi);
void onEscapePressed();
void onUnmountButtonClicked();
void onInfoMountButtonClicked(bool);
void onUpdateInfoMountButtonAndBehaviour();
private: // methods
void retranslate() override;
bool apply() override final;
bool isIncludedId(int32_t mountingPointId) const;
QModelIndex mapToSourciest(const QModelIndex &index);
private: // attributes
MountingPointListDialogModel *m_sourceModel{nullptr};
MountingPointListSortModel *m_sortProxyModel{nullptr};
CheckboxProxyModel *m_checkboxProxyModel{nullptr};
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<ForeignDataInterface> m_dataIfc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
QString m_menuGroup;
LtsSession::LtsSession *m_session{nullptr};
ForeignResourceManagementGuiInterface *m_ismGuiIfc{nullptr};
std::shared_ptr<SituationMap::ForeignGuiInterface> m_mapGuiInterface;
struct ClickedObjectStore
{
SituationMap::MapObjectType mot {SituationMap::MapObjectType::MOT_Undefined};
int entityId {-1};
qint64 timestampMsec {-1};
void reset();
} m_clickedObjectStore;
unsigned int m_typeFilterColumn;
unsigned int m_typeFilterRow;
DdsSelector *m_ddsSelector{nullptr};
int32_t m_scheduleId;
// click leads to a) InfoDialog or b) mounting/changing aimState (Idle, Equipped, Empty)
enum class InfoMount
{
IM_INFO, ///! on Click on MapObject, normal map behaviour: info dialog
IM_MOUNT ///! on Click on MapObject, change aim state
}
m_infoMount{InfoMount::IM_INFO};
SituationMap::ResourceManagerMode m_oldResourceManagerMode{SituationMap::ResourceManagerMode::Undefined};
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> m_fltBuildingComponentIfc;
std::shared_ptr<FilterManagement::BuildingComponentSettings> m_buildingComponentSettings;
Ui::MountingPointListDialog *m_ui{nullptr};
LOGGER_T m_logger;
}; // class MountingPointListDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MountingPointListDialog</class>
<widget class="QWidget" name="MountingPointListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>833</width>
<height>478</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Asset Stocks</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2">
<widget class="LtsDataView::LtsDataView" name="mountingPointListView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
<property name="toolButtonsVisible" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>439</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2">
<widget class="QToolButton" name="tbMountMode">
<property name="minimumSize">
<size>
<width>150</width>
<height>50</height>
</size>
</property>
<property name="text">
<string notr="true">mountMode</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,52 @@
#include "ism_mounting_point_list_dialog_checkbox_delegate.h"
#include "ism_mounting_point_list_dialog_model.h"
#include <QPainter>
namespace InfrastructureManagement
{
CheckboxDelegate::CheckboxDelegate(QObject *parent)
: QItemDelegate(parent)
{}
void CheckboxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QItemDelegate::paint(painter, option, index);
if (index.column() != MountingPointListDialogModel::Columns::NAME)
return;
painter->save();
painter->setClipRect(option.rect);
painter->setClipping(true);
const QVariant value(index.data(Qt::UserRole + 1));
if (value.isValid() && value.canConvert<int>())
{
QPixmap x(QStringLiteral(":/style/checkbox-multi-state.svg"));
switch (value.toInt())
{
case MountingPointState::Equipped:
x = QPixmap(QStringLiteral(":/style/checkbox-true.svg"));
break;
case MountingPointState::Idle:
x = QPixmap(QStringLiteral(":/style/checkbox-empty.svg"));
break;
case MountingPointState::Empty:
x = QPixmap(QStringLiteral(":/style/checkbox-false.svg"));
break;
}
const QStyleOptionViewItem opt = setOptions(index, option);
const QRect checkRect(QItemDelegate::doCheck(opt, opt.rect, /*value*/1));
painter->drawPixmap(checkRect.adjusted(3,0,3,0), x, QRect());
//QItemDelegate::drawCheck(painter, opt, checkRect, Qt::CheckState::Checked); // test
}
painter->restore();
}
} // namespace InfrastructureManagement
@@ -0,0 +1,18 @@
#pragma once
#include "ism_mounting_point_list_dialog_checkbox_delegate.h"
#include <QItemDelegate>
namespace InfrastructureManagement
{
class CheckboxDelegate : public QItemDelegate
{
Q_OBJECT
public:
CheckboxDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,168 @@
#include "ism_mounting_point_list_dialog_checkbox_proxy_model.h"
#include "ism_mounting_point_list_dialog_model.h"
namespace InfrastructureManagement
{
Qt::ItemFlags CheckboxProxyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return sourceModel()->flags(index); // delegate to source model for further processing if necessary
// Sets only the checkbox nodes on user checkable,
// checkbox leaves must be handled in source model.
QModelIndex sourceIndex = mapToSource(index);
Qt::ItemFlags fl = sourceModel()->flags(sourceIndex);
if (index.column() == 0)
return fl | Qt::ItemIsUserCheckable;
return fl;
}
QVariant CheckboxProxyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return {};
const QModelIndex sourceIndex(mapToSource(index));
// delegate everything except CheckStateRole to source model
if (role != (Qt::UserRole + 1))
return sourceModel()->data(sourceIndex, role);
// delegate a leaf too with CheckStateRole to source model
if (isLeaf(index))
return sourceModel()->data(sourceIndex, role);
// delegate to source model for further processing of further columns if necessary
if (index.column() != MountingPointListDialogModel::Columns::NAME)
return sourceModel()->data(sourceIndex, role);
// sets the node checkboxes and decoration depending on the entries in the tree structure
bool lastMpsSet = false; // std::optional >_>
int lastMps = -2;
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
const QModelIndex childIndex(this->index(childRow, 0, index));
const QVariant value(data(childIndex, (Qt::UserRole + 1)));
if (value.isValid() && value.canConvert<int>())
{
int state = value.toInt();
if (!lastMpsSet)
{
lastMpsSet = true;
lastMps = state;
continue;
}
if (lastMps != state) // if at one point there is a different status inside one parent, show the 'partial' checkbox state as there are mixed states
return -2;
}
}
return lastMps;
}
QString mpsToString(const int mps)
{
switch ((int)mps)
{
case -2:
return QStringLiteral("PARTIALLY");
case -1:
return QStringLiteral("EMPTY");
case 0:
return QStringLiteral("IDLE");
case 1:
return QStringLiteral("EQUIPPED");
default:
return QStringLiteral("( !UNKNOWN! )");
}
}
QString mpsToString(const MountingPointState_def::type mps)
{
return mpsToString((int)mps);
}
bool CheckboxProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
/* this setData is called if the user clicks on a checkbox
* then this setData calls the sourceModel's setData to finally
* set the underlying checkboxes */
if (!index.isValid())
return false;
const QModelIndex sourceIndex(mapToSource(index));
// delegate to source model for further processing of further columns if necessary
if (index.column() != MountingPointListDialogModel::Columns::NAME)
return sourceModel()->setData(sourceIndex, value, role);
/* Qt calls setData with role == Qt::CheckStateRole if the user clicks on a checkbox.
* We need to know at this point if wither the call to this method was called by Qt,
* or if this method called setData recursively. If this is the first call, the new
* checkbox state has to be determined at this point. To determine if the call to
* setData is a recursive call, we set role to Qt::UserRole+1. Kind of a hack. */
int newMps = value.toInt();
if (role == Qt::CheckStateRole)
{
//newMps = (int)MountingPointState_def::Idle;
int mps = index.data(Qt::UserRole + 1).toInt();
switch (mps)
{
case -2: // SPECIAL CASE, not a real MPS, but the indicator that there are mixed states on the underlying children
newMps = (int)MountingPointState_def::Idle;
break;
case (int)MountingPointState_def::Idle:
newMps = (int)MountingPointState_def::Equipped;
break;
case (int)MountingPointState_def::Equipped:
newMps = (int)MountingPointState_def::Empty;
break;
case (int)MountingPointState_def::Empty:
newMps = (int)MountingPointState_def::Idle;
break;
default:
return false;
}
}
if (isLeaf(index))
{
// delegate a leaf to source model
sourceModel()->setData(sourceIndex, newMps, role);
}
else
{
// update underlying children recursively (Additional nodes with leaves may also exist)
const int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
const QModelIndex childIndex(this->index(childRow, 0, index));
setData(childIndex, newMps, (Qt::UserRole + 1));
}
}
return true;
}
bool CheckboxProxyModel::isLeaf(const QModelIndex &index) const
{
const QModelIndex sourceIndex(mapToSource(index));
return sourceModel()->flags(sourceIndex).testFlag(Qt::ItemIsUserCheckable);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,19 @@
#pragma once
#include <QIdentityProxyModel>
namespace InfrastructureManagement
{
class CheckboxProxyModel : public QIdentityProxyModel
{
public:
using QIdentityProxyModel::QIdentityProxyModel;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
bool isLeaf(const QModelIndex &index) const;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,120 @@
#include "ism_mounting_point_list_dialog_list_sort_model.h"
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
namespace InfrastructureManagement
{
void MountingPointListSortModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<MountingPointListDialogModel*>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(m_sourceModel);
}
void MountingPointListSortModel::setTypeFilter(const QSet<MountingPointType> &visibleTypes)
{
if (m_visibleTypes == visibleTypes)
return;
m_visibleTypes = visibleTypes;
invalidateFilter();
}
void MountingPointListSortModel::addToTypeFilter(MountingPointType mpt, bool bAdd)
{
auto visibleTypes = m_visibleTypes;
if (bAdd)
{
if(mpt == MountingPointType::IndoorIPS)
{
visibleTypes.insert(MountingPointType::OutdoorIPS);
}
visibleTypes.insert(mpt);
}
else
{
if(mpt == MountingPointType::IndoorIPS)
{
visibleTypes.remove(MountingPointType::OutdoorIPS);
}
visibleTypes.remove(mpt);
}
setTypeFilter(visibleTypes);
}
void MountingPointListSortModel::setFloorFilter(const QSet<int> &visibleFloors)
{
if (m_visibleFloors == visibleFloors)
return;
m_visibleFloors = visibleFloors;
invalidateFilter();
}
void MountingPointListSortModel::addToFloorFilter(int floor, bool bAdd)
{
auto visibleFloors = m_visibleFloors;
if (bAdd)
visibleFloors.insert(floor);
else
visibleFloors.remove(floor);
setFloorFilter(visibleFloors);
}
bool MountingPointListSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel)
return true;
bool isRootItem = !source_parent.isValid();
if (isRootItem)
{
Q_ASSERT(source_row == 0);
return true; // root item shall always be visible
}
const QModelIndex childIdx = m_sourceModel->index(source_row, 0, source_parent);
const NGLTreeItem *itemChild = m_sourceModel->privateData(childIdx);
Q_ASSERT(itemChild);
bool isLeaf = itemChild->data().canConvert<SimpleMountingPointData>();
if (isLeaf)
{
const SimpleMountingPointData data = itemChild->data().value<SimpleMountingPointData>();
Q_ASSERT(data.isMountingPoint());
return m_visibleTypes.contains(data.mpType) && m_visibleFloors.contains(data.floor);
}
else
{
if (!itemChild->data().canConvert<SimpleStructureElementData>())
return true;
const SimpleStructureElementData ssed = itemChild->data().value<SimpleStructureElementData>();
if (ssed.floor != -20 && !m_visibleFloors.contains(ssed.floor))
return false;
}
// Qt5.11: setRecursiveFilteringEnabled(true);
for (int i = 0; i < itemChild->childCount(); ++i)
{
if (filterAcceptsRow(i, childIdx))
return true;
}
return false;
}
bool MountingPointListSortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel || source_left.column() != source_right.column())
return BaseClass::lessThan(source_left, source_right);
const NGLTreeItem *itemLeft = m_sourceModel->privateData(source_left);
const NGLTreeItem *itemRight = m_sourceModel->privateData(source_right);
if (!itemLeft || !itemRight)
return BaseClass::lessThan(source_left, source_right);
const SimpleMountingPointData left = itemLeft->data().value<SimpleMountingPointData>();
const SimpleMountingPointData right = itemRight->data().value<SimpleMountingPointData>();
if (left.name != right.name)
return left.name < right.name;
return left.id < right.id;
}
} // namespace InfrastructureManagement
@@ -0,0 +1,38 @@
#pragma once
#include "ism_mounting_point_list_dialog_model.h"
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QSet>
namespace InfrastructureManagement
{
class MountingPointListSortModel final : public LtsWidgets::LtsColumnFilterProxyModel
{
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
void setTypeFilter(const QSet<MountingPointType> &visibleTypes);
void addToTypeFilter(MountingPointType mpt, bool bAdd);
void setFloorFilter(const QSet<int> &visibleFloors);
void addToFloorFilter(int floor, bool bAdd);
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
using LtsWidgets::LtsColumnFilterProxyModel::invalidateFilter;
private:
MountingPointListDialogModel *m_sourceModel = nullptr;
QSet<MountingPointType> m_visibleTypes;
QSet<int> m_visibleFloors;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,478 @@
/**
* @RDE_HEADER@
* The MountingPointListDialogModel provices data for MountingPointListDialog
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_mounting_point_list_dialog_model.h"
#include "ism_mounting_point_list_dialog_list_sort_model.h"
#include <InfrastructureManagement/ism_translation.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <QTimer>
// #define BENCHMARK
#ifdef BENCHMARK
# include <QElapsedTimer>
# include <QDebug>
#endif
namespace InfrastructureManagement
{
MountingPointListDialogModel::MountingPointListDialogModel(QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), { tr("Name"), tr("Type"), tr("Asset"), tr("Aim State") })
, m_visRoot(new NGLTreeItem(tr("Mounting Points")))
, m_dtc(nullptr)
, m_scheduleId(-1)
, m_dataChangedTimer(new QTimer(this))
, m_logger(getLogger("MountingPointListDialogModel"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_dataChangedTimer->setSingleShot(true);
m_dataChangedTimer->setInterval(100);
connect(m_dataChangedTimer, &QTimer::timeout, this, &MountingPointListDialogModel::emitDataChanged);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
QVariant MountingPointListDialogModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
NGLTreeItem *item = privateData(index);
const int indexColumn = index.column();
if (role == Qt::DisplayRole)
{
if (indexColumn != NAME && !item->data().canConvert<SimpleMountingPointData>())
return QVariant();
const SimpleMountingPointData itemData = item->data().value<SimpleMountingPointData>();
switch (indexColumn)
{
case NAME:
if (item->data().canConvert<SimpleMountingPointData>())
return item->data().value<SimpleMountingPointData>().name;
if (item->data().canConvert<SimpleStructureElementData>())
return item->data().value<SimpleStructureElementData>().name;
if (item->data().canConvert<SimpleBuildingGroupData>())
return item->data().value<SimpleBuildingGroupData>().name;
return tr("all");
case STATE:
if (itemData.seType == StructureElementType::MountingPoint)
return toString(itemData.aimState);
break;
case ASSET_BARCODE:
if (item->data().canConvert<SimpleMountingPointData>())
return item->data().value<SimpleMountingPointData>().assetBarcode;
break;
case TYPE:
if (itemData.seType == StructureElementType::MountingPoint)
{
if(itemData.mpType == MountingPointType::OutdoorIPS)
return toString(MountingPointType::IndoorIPS);
return toString(itemData.mpType);
}
break;
}
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole
&& indexColumn == TYPE)
{
const SimpleMountingPointData itemData = item->data().value<SimpleMountingPointData>();
if (itemData.mpType.underlying() == MountingPointType::Unknown)
{
ERROR_LOG(m_logger) << "unknown!!!";
return QVariant(); // return INVALID QVariant to let LtsDataView's proxy filter model ignore this row while filtering / aka. don't hide it when filtering
}
ERROR_LOG(m_logger) << "mpType = " << itemData.mpType.underlying();
if(itemData.mpType == MountingPointType::OutdoorIPS)
return MountingPointType::IndoorIPS;
return itemData.mpType.underlying();
}
if (role == Qt::CheckStateRole && index.column() == NAME)
return Qt::Unchecked; // dummy
if (role == Qt::UserRole && item->data().canConvert<SimpleMountingPointData>())
return item->data().value<SimpleMountingPointData>().id;
if (role == (Qt::UserRole + 1) && item->data().canConvert<SimpleMountingPointData>())
return item->data().value<SimpleMountingPointData>().aimState.underlying();
return {};
}
bool MountingPointListDialogModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ForeignDataInterface> &dataInterface)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_dtc == dtc)
return true;
if (!(dtc->enableMainStructureElement() &&
dtc->enableMountingPointAsset()))
{
ERROR_LOG(m_logger) << "Could not enable Datatopics";
return false;
}
m_dtc = dtc;
m_dataInterface = dataInterface;
m_scheduleId = m_dataInterface->scheduleId();
connect(m_dataInterface.get(), &ForeignDataInterface::mountingPointChanged,
this, &MountingPointListDialogModel::onMountingPointChanged);
DEBUG_LOG(m_logger) << "initModel successful";
initData();
beginResetModel();
endResetModel();
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
return true;
}
QModelIndex MountingPointListDialogModel::getIndexOfVisibleRootItem() const
{
return indexFromItem(m_visRoot);
}
void MountingPointListDialogModel::initData()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
#ifdef BENCHMARK
QElapsedTimer elapsedTimer1;
elapsedTimer1.start();
#endif // BENCHMARK
NGLTreeModel::resetModel();
m_rootItem->appendChild(m_visRoot);
// const InfrastructureManagement::MainSchedule &currentSchedule = m_dtc->mainSchedule(m_scheduleId);
const QMap<int, InfrastructureManagement::MainStructureElement> &mainStructEles = m_dtc->mainStructureElements();
// cfroebel 2018-11-07:
// The algorithm of building the tree structure assumes that
// the StructureElements are hierarchically ordered, i.e. that the
// MountingPoint comes after its Room, Level and Building.
// Is that guaranteed by the service?
m_mountingPointIndexes.reserve(mainStructEles.size());
m_availableBuildingGroups.reserve(mainStructEles.size());
for (const MainStructureElement &mse : mainStructEles)
{
// only consider buildings
if (mse.structureElementTypeId() != StructureElementType::Building)
continue;
// 1- if a buildingGroup modelIndex for current building dosen't exist
// a new one will be first added and used as parentIndex for the blg_Index.
QModelIndex groupIndex;
const StructureElement bse= setBuildingGroup(mse.groupId());
// Outdoor camera will not be displayed
if (mse.groupId() != BuildingGroup::OutdoorCameras)
{
if (m_availableBuildingGroups.contains(bse.id()) == false)
{
SimpleBuildingGroupData buildingGroup;
buildingGroup.name = QString::fromStdString(bse.displayName());
NGLTreeItem *groupItem = new NGLTreeItem(QVariant::fromValue(buildingGroup));
QModelIndex groupParentIndex;
groupParentIndex = indexFromItem(m_visRoot);
insertRow(rowCount(groupParentIndex), groupParentIndex, groupItem);
groupIndex = index(groupItem->row(), 0, groupParentIndex);
m_mountingPointIndexes.insert(bse.id(), groupIndex);
m_availableBuildingGroups.insert(bse.id());
}
else
{
groupIndex = m_mountingPointIndexes.value(bse.id(), indexFromItem(m_visRoot));
}
}
for (const StructureElement &currentElement : mse.elements())
{
NGLTreeItem *item;
if (currentElement.structureElementTypeId() == StructureElementType::MountingPoint)
{
const MountingPoint &mountingPoint = m_dataInterface->mountingPoint(currentElement.id());
if (!mountingPoint.isValid())
continue;
if (mountingPoint.type() == MountingPointType::Unknown ||
mountingPoint.type() == MountingPointType::BuildingControlUnit ||
mountingPoint.type() == MountingPointType::VirtualIPS ||
mountingPoint.type() == MountingPointType::MeteoDataUnit ||
mountingPoint.type() == MountingPointType::BuildingNetworkSwitch ||
mountingPoint.type() == MountingPointType::OutdoorCamera)
continue;
SimpleMountingPointData mpData;
mpData.seType = currentElement.structureElementTypeId();
mpData.id = mountingPoint.id();
mpData.name = mountingPoint.name();
mpData.aimState = mountingPoint.aimState();
mpData.mpType = mountingPoint.type();
mpData.floor = mountingPoint.floor();
// attention: getMountedAssetId could be expensive
// const int assetId = m_dtc->getMountedAssetId(mountingPoint.data().id());
// use already available mountingPoint instead: :-)
const int assetId = mountingPoint.associatedAssetId();
mpData.assetBarcode = QStringLiteral("-");
if(assetId != -1)
{
mpData.assetBarcode = QString::fromStdString(m_dtc->instrumentationAsset(assetId).barcode());
}
item = new NGLTreeItem(QVariant::fromValue(mpData));
}
else
{
SimpleStructureElementData ssed;
ssed.mseId = mse.id();
if (currentElement.structureElementTypeId() == StructureElementType::Floor)
ssed.floor = QString::fromStdString(currentElement.name()).split(QLatin1Literal("_")).value(1, QLatin1String("-10")).toInt();
else
ssed.floor = -20;
ssed.name = currentElement.displayName().empty() ? QString::fromStdString(currentElement.name()) : QString::fromStdString(currentElement.displayName());
item = new NGLTreeItem(QVariant::fromValue(ssed));
m_availableFloors << ssed.floor;
}
const auto &path = currentElement.path();
QModelIndex parentIndex;
if (path.size() > 1)
{
parentIndex = m_mountingPointIndexes.value(path.at(path.size() - 2), indexFromItem(m_visRoot)); //default sollte nie erreicht werden
if (!parentIndex.isValid())
{
ERROR_LOG(m_logger) << "Did not find parent for structure element with id " << currentElement.id() << " mseid: " << mse.id();
for (const StructureElement &se : mse.elements())
ERROR_LOG(m_logger) << " se: " << se.id() << ", " << se.displayName() << ", " << se.name();
}
}
else
{
// 2- Append building to it section index
if(groupIndex.isValid() == false)
{
parentIndex = indexFromItem(m_visRoot);
}
else
{
parentIndex = groupIndex;
}
}
insertRow(rowCount(parentIndex), parentIndex, item);
m_mountingPointIndexes.insert(currentElement.id(), index(item->row(), 0, parentIndex));
}
}
m_availableFloors << -10;
#ifdef BENCHMARK
qCritical() << " MountingPointListDialogModel::init-BENCHMARK: took " << elapsedTimer1.elapsed() << " [ms]";
#endif // BENCHMARK
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
QSet<int> MountingPointListDialogModel::getAvailableFloors() const
{
return m_availableFloors;
}
StructureElement MountingPointListDialogModel::setBuildingGroup(int groupId)
{
StructureElement se{};
InfrastructureManagement::BuildingGroup_def::type buildingGroup = static_cast<InfrastructureManagement::BuildingGroup_def::type>(groupId);
if(buildingGroup == 0)
{
buildingGroup = InfrastructureManagement::BuildingGroup_def::UnknownGroup;
}
se.id() = maxIntValue - static_cast<int>(buildingGroup);
se.name() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.displayName() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.structureElementTypeId() = InfrastructureManagement::StructureElementType::Section;
return se;
}
Qt::ItemFlags MountingPointListDialogModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags fl = NGLTreeModel::flags(index);
if (!index.isValid())
return fl;
NGLTreeItem *item = privateData(index);
bool isLeaf = item->data().canConvert<SimpleMountingPointData>();
if (isLeaf && index.column() == Columns::NAME)
return fl | Qt::ItemIsUserCheckable | Qt::ItemIsUserTristate;
return fl;
}
bool MountingPointListDialogModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
// is called by the CheckboxProxyModel's setData method
if (index.column() != NAME || !index.isValid())
return NGLTreeModel::/**/setData(index, value, role);
auto lambda = [this, &value](const QModelIndex &idx)
{
NGLTreeItem *item = privateData(idx);
if (!item->data().canConvert<SimpleMountingPointData>()) // not a leaf?
{
Q_ASSERT(false); // CheckboxProxyModel never calls this model's setData if the index is not a leaf
/* we don't know what state the parent is, wo don't know how many children there REALLY are.
* all this is hidden behind multiple proxy models. so send a signal to the dialog,
* get the clicked parent's state and set all its (visible!) children.
* at least that's the plan .... */
return;
}
SimpleMountingPointData smpd = item->data().value<SimpleMountingPointData>();
smpd.aimState = (MountingPointState::inner_enum)value.toInt();
item->setData(QVariant::fromValue(smpd));
emit changesMade();
};
if (index.parent().isValid())
{
lambda(index);
}
else
{
for (const QModelIndex &idx : qAsConst(m_mountingPointIndexes))
lambda(idx);
}
m_dataChangedTimer->start(); // ugly hack
return true;
}
QVariant MountingPointListDialogModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal
&& role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole
&& section == TYPE)
return m_cbxFilterType;
return BaseClass::headerData(section, orientation, role);
}
void MountingPointListDialogModel::setMntPointFilterTypes(QSet<MountingPointType> types)
{
LtsWidgets::ComboboxFilterContent cfc;
LtsWidgets::ComboboxFilterData cfd;
for (const auto es : qAsConst(types))
{
if (es == MountingPointType::OutdoorIPS)
continue;
cfd.data = es.underlying();
cfd.text = toString(es);
cfc.data.push_back(cfd);
// DEBUG_LOG(m_logger)<<" cfd.text: "<<cfd.text;
}
cfc.sortItems = true;
m_cbxFilterType = cfc.toVariant();
}
void MountingPointListDialogModel::onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType)
{
if (modType != DataModification::eModified)
return;
QModelIndex index = m_mountingPointIndexes.value(mountingPoint.id());
if (!index.isValid())
return;
NGLTreeItem *item = privateData(index);
if (!(item && item->data().canConvert<SimpleMountingPointData>()))
return;
SimpleMountingPointData mpData = item->data().value<SimpleMountingPointData>();
mpData.name = mountingPoint.name();
mpData.aimState = mountingPoint.aimState();
const int assetId = mountingPoint.associatedAssetId(); // (m_dtc->getMountedAssetId(mountingPoint.data().id());
mpData.assetBarcode = QStringLiteral("-");
mpData.floor = mountingPoint.floor();
if(assetId != -1)
{
mpData.assetBarcode = QString::fromStdString(m_dtc->instrumentationAsset(assetId).barcode());
}
item->setData(QVariant::fromValue(mpData));
m_dataChangedTimer->start();
}
void MountingPointListDialogModel::onScheduleIdChanged(int32_t scheduleId)
{
// is this unreachable code?
if (scheduleId == m_scheduleId)
return;
DEBUG_LOG(m_logger) << "onScheduleIdChanged: " << scheduleId;
m_scheduleId = scheduleId;
// !!! Maybe this is critical !!!
// !!! Maybe this is critical !!!
// !!! Maybe this is critical !!!
// m_dataInterface::setScheduleId will update the MountingPoints (aimState) according schedule!!!
m_dataInterface->setScheduleId(m_scheduleId);
initData();
}
void MountingPointListDialogModel::emitDataChanged()
{
QModelIndex vri = getIndexOfVisibleRootItem();
emit dataChanged(vri, index(rowCount(vri) -1, Columns::STATE, vri), {Qt::DisplayRole, Qt::CheckStateRole});
}
//
// MountingPointListSortModel
//
} // namespace InfrastructureManagement
@@ -0,0 +1,137 @@
/**
* @RDE_HEADER@
* The MountingPointListDialogModel provices data for MountingPointListDialog
* Modified version using the checkStateProxyModel to allow setting via the checkboxes of the tree structure hjl 5/19
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <QSet>
#include <nglwidgets/ngltreemodel.h>
#include <nglwidgets/ngltreeitem.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsDataView/check_state_proxy_model.h>
namespace InfrastructureManagement
{
struct SimpleMountingPointData
{
QString name;
int32_t id = 0; // StructureElementId
StructureElementType seType;
MountingPointType mpType;
MountingPointState aimState;
// int assetId; Chance to only reload assetBarcode, if assetId changes...
QString assetBarcode;
int32_t floor;
bool isMountingPoint() const { return seType == StructureElementType::MountingPoint; }
};
struct SimpleStructureElementData
{
int mseId;
QString name;
int floor;
};
struct SimpleBuildingGroupData
{
QString name;
};
class MountingPointListDialogModel final : public NGLTreeModel
{
Q_OBJECT
using BaseClass = NGLTreeModel;
public:
enum Columns
{
NAME,
TYPE,
ASSET_BARCODE,
STATE
};
explicit MountingPointListDialogModel(QObject *parent = nullptr);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
/**
* Handles the representation of data.
* In case of CheckStateRole only leafs will be handled.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] role role to which the data relates
*
*/
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<ForeignDataInterface> &dataInterface);
QModelIndex getIndexOfVisibleRootItem() const;
/**
* Sets only the leafs of the tree view to Qt::ItemIsUserCheckable.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
*
*/
Qt::ItemFlags flags(const QModelIndex &index) const override final;
/**
* Sets the check state data according to their check box in the internal model.
* CheckState data can be set for leafs only.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] value value to be set
* @param[in] role role to which the data relates (here especially Qt::CheckStateRole)
*
*/
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
void setMntPointFilterTypes(QSet<InfrastructureManagement::MountingPointType> types);
QSet<int> getAvailableFloors() const;
StructureElement setBuildingGroup(int groupId);
static const int maxIntValue = std::numeric_limits<int>::max();
signals:
void changesMade();
public slots:
void onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType);
private slots:
void onScheduleIdChanged(int32_t scheduleId);
void emitDataChanged();
private:
void initData();
friend class MountingPointListSortModel;
NGLTreeItem *m_visRoot;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_dataInterface;
int32_t m_scheduleId;
QHash<int, QModelIndex> m_mountingPointIndexes;
QTimer *m_dataChangedTimer{nullptr};
QSet<int> m_availableFloors;
QSet<int> m_availableBuildingGroups;
QVariant m_cbxFilterType;
LOGGER_T m_logger;
}; // class MountingPointListDialogModel
} // namespace InfrastructureManagement
Q_DECLARE_METATYPE(InfrastructureManagement::SimpleMountingPointData)
Q_DECLARE_METATYPE(InfrastructureManagement::SimpleStructureElementData)
Q_DECLARE_METATYPE(InfrastructureManagement::SimpleBuildingGroupData)
@@ -0,0 +1,102 @@
/**
* @RDE_HEADER@
* Class which adds single mounting points to the current schedule by id
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-04-06
*/
#include "ism_dds_selector.h"
#include <LtsUtilsCore/dds_vector.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <QApplication>
using namespace InfrastructureManagement;
DdsSelector::DdsSelector(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<Interface::Ftc> &ftc, const std::shared_ptr<ForeignDataInterface> &ismDataIfc, LtsUtils::RequestHelper *requestHelper)
: MountingPointSelector(dtc, ftc, ismDataIfc, requestHelper, getLogger(QStringLiteral("DdsSelector")))
{
}
void DdsSelector::addMountingPoints(const QVector<int32_t> &mountingPointIds, const QMap<int32_t, MountingPointState> &states, QWidget *parentWidget)
{
if (mountingPointIds.isEmpty())
return;
Q_UNUSED(states)
std::vector<MountingPointPlan> modifyVec;
modifyVec.reserve(mountingPointIds.size());
MainSchedule mainSchedule = m_ismDataIfc->mainSchedule(m_ismDataIfc->scheduleId());
MountingPointState mps = m_ismDataIfc->mountingPoint(mountingPointIds.first()).aimState();
bool override = false;
for (int32_t currentMountingPointId : mountingPointIds)
{
MountingPoint mountingPoint = m_ismDataIfc->mountingPoint(currentMountingPointId);
if (!mountingPoint.isValid())
continue;
if (mountingPoint.aimState() == mps)
continue;
LtsWidgets::Button resButton = LtsWidgets::LtsMessageDialog::showMessage(parentWidget,
QApplication::translate("Ism::Selector", "Multiple selected components have different states.\nPlease select desired state"),
QApplication::translate("Ism::Selector", "Inconsistent component state"),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes | LtsWidgets::Button::No | LtsWidgets::Button::Discard,
{ {LtsWidgets::Button::Yes, QApplication::translate("Ism::Selector", "Equipped")},
{LtsWidgets::Button::No, QApplication::translate("Ism::Selector", "Empty")},
{LtsWidgets::Button::Discard, QApplication::translate("Ism::Selector", "Idle")}
});
switch(resButton)
{
case LtsWidgets::Button::Yes:
mps = MountingPointState::Equipped;
break;
case LtsWidgets::Button::No:
mps = MountingPointState::Empty;
break;
case LtsWidgets::Button::Discard:
default:
mps = MountingPointState::Idle;
break;
}
override = true;
break;
}
for (int32_t currentMountingPointId : mountingPointIds)
{
MountingPoint mountingPoint = m_ismDataIfc->mountingPoint(currentMountingPointId);
if (!mountingPoint.isValid())
continue;
MountingPointState aimState = override ? mps : mountingPoint.getNextMountingPointState(mountingPoint.aimState());
auto it = std::find_if(mainSchedule.elements().cbegin(), mainSchedule.elements().cend(), [currentMountingPointId](const MountingPointPlan &mpp){ return (mpp.structureElementId() == currentMountingPointId); });
if (it != mainSchedule.elements().cend())
{
if ((*it).mountingPointState() == aimState)
continue;
MountingPointPlan mpp = (*it);
mpp.mountingPointState() = aimState;
modifyVec.push_back(mpp);
}
else if (aimState != MountingPointState::Idle)
modifyVec.push_back(MountingPointPlan(currentMountingPointId,aimState));
}
if (!modifyVec.empty())
startModifyRequest(modifyVec);
}
@@ -0,0 +1,25 @@
/**
* @RDE_HEADER@
* Class which adds single mounting points to the current schedule by id
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-04-06
*/
#pragma once
#include "ism_selector.h"
namespace InfrastructureManagement
{
class DdsSelector
: public MountingPointSelector
{
public:
explicit DdsSelector(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<Interface::Ftc> &ftc, const std::shared_ptr<ForeignDataInterface> &ismDataIfc, LtsUtils::RequestHelper *requestHelper);
void addMountingPoints(const QVector<int32_t> &mountingPointIds, const QMap<int32_t, MountingPointState> &states, QWidget *parentWidget) override final;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* Abstract class which defines selection behavior when clicking on mounting points on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-04-05
*/
#include "ism_selector.h"
#include <LtsUtilsGuiDds/request_helper.h>
namespace InfrastructureManagement
{
MountingPointSelector::MountingPointSelector(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &ismDataIfc,
LtsUtils::RequestHelper *requestHelper,
LOGGER_T logger)
: m_ismDataIfc(ismDataIfc)
, m_ftc(ftc)
, m_dtc(dtc)
, m_requestHelper(requestHelper)
, m_logger(logger)
{
if (!m_ftc->enableMountingPointPlanModify())
{
ERROR_LOG(m_logger) << "Could not enable FT MountingPointPlanModify of ISM";
}
}
void MountingPointSelector::onMountingPointPlanModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (replyObject.error())
ERROR_LOG(m_logger) << "MountingPointPlansRemove error: "
<< replyObject.str();
else
DEBUG_LOG(m_logger) << "MountingPointPlansRemove success";
}
void MountingPointSelector::startModifyRequest(const std::vector<MountingPointPlan> &data)
{
if (data.empty())
return;
MountingPointPlanModifyRequest req(m_ismDataIfc->scheduleId(), data);
m_requestHelper->startSingleRequest([req, this]()
{
return m_ftc->mountingPointPlanModifyRequest(req, this);
});
}
}
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Abstract class which defines selection behavior when clicking on mounting points on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-04-05
*/
#pragma once
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/logger.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
namespace LtsUtils
{
class RequestHelper;
}
namespace InfrastructureManagement
{
class MountingPointSelector
: public Interface::Ftc::MountingPointPlanModifyReplyHandler
{
public:
explicit MountingPointSelector(const std::shared_ptr<Interface::Dtc> &dtc, const std::shared_ptr<Interface::Ftc> &ftc, const std::shared_ptr<ForeignDataInterface> &ismDataIfc, LtsUtils::RequestHelper *requestHelper, LOGGER_T logger);
virtual ~MountingPointSelector() = default;
virtual void addMountingPoints(const QVector<int32_t> &mountingPointIds, const QMap<int32_t, MountingPointState> &states, QWidget *parentWidget) = 0;
void onMountingPointPlanModifyReply(const Core::FunctionReplyObject &replyObject) override final;
protected: //methods
void startModifyRequest(const std::vector<MountingPointPlan> &data);
protected: // attributes
std::shared_ptr<ForeignDataInterface> m_ismDataIfc;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<Interface::Dtc> m_dtc;
LtsUtils::RequestHelper *m_requestHelper;
LOGGER_T m_logger;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,233 @@
/**
* @RDE_HEADER@
* The ConflictsDialog shows conflicts between 2 instrumentation plans
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLTE, 2022-11-15
*/
#include "ism_overview_conflicts_dialog.h"
#include "ui_ism_overview_conflicts_dialog.h"
#include "ism_overview_conflicts_model.h"
#include <InfrastructureManagement/ism_translation.h>
#include <LtsPrinting/printing.h>
#include <QMenu>
#include <QAction>
#include <QTreeView>
#include <QHeaderView>
#include <QScrollBar>
using namespace InfrastructureManagement;
ConflictsDialog::ConflictsDialog(const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkCancel)
, m_ui(new Ui::ConflictsDialog)
, m_sourceModel(nullptr)
, m_menuGroup(menuGroup)
, m_logger(getLogger("ConflictsDialog"))
{
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Conflicts"));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ConflictsDialog::onPrint);
}
ConflictsDialog::~ConflictsDialog()
{
if (m_sourceModel)
{
delete m_sourceModel;
m_sourceModel = nullptr;
}
delete m_ui;
}
void ConflictsDialog::retranslate()
{
QString plan1 = QString::fromStdString(m_dtc->mainSchedule(m_scheduleId).name());
QString plan2 = QString::fromStdString(m_dtc->mainSchedule(m_anotherScheduleId).name());
translate(m_ui, tr("Conflicts: %1 - %2").arg(plan1, plan2));
}
bool ConflictsDialog::init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
int scheduleId,
int anotherScheduleId)
{
m_session = session;
m_dtc = dtc;
m_scheduleId = scheduleId;
m_anotherScheduleId = anotherScheduleId;
if (m_scheduleId <= 0)
{
ERROR_LOG(m_logger) << "Invalid id for Instrumentation plan: " << m_scheduleId;
return false;
}
connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged, this, &ConflictsDialog::dataChanged);
m_sourceModel = new ConflictsDialogModel(this);
if (!m_sourceModel->initModel(m_scheduleId, m_anotherScheduleId, m_dtc))
{
ERROR_LOG(m_logger) << "Could not init ConflictsDialogModel";
delete m_sourceModel;
m_sourceModel = nullptr;
return false;
}
m_ui->dvConflicts->setModel(m_sourceModel);
m_ui->dvConflicts->setContextMenuPolicyPerView(LtsDataView::LtsDataView::Page::TABLE, Qt::CustomContextMenu);
connect(m_ui->dvConflicts->treeView(), &QTreeView::customContextMenuRequested,
this, &ConflictsDialog::onCustomContextMenu);
// show first tree level when activating the dialog
m_ui->dvConflicts->treeView()->expandToDepth(0);
m_ui->dvConflicts->treeView()->setColumnWidth(0, 400);
m_ui->dvConflicts->treeView()->setColumnWidth(1, 200);
m_ui->dvConflicts->treeView()->setColumnWidth(2, 200);
m_ui->dvConflicts->treeView()->setColumnWidth(3, 200);
m_ui->dvConflicts->searchView()->setColumnWidth(0, 400);
m_ui->dvConflicts->searchView()->setColumnWidth(1, 200);
m_ui->dvConflicts->searchView()->setColumnWidth(2, 200);
m_ui->dvConflicts->searchView()->setColumnWidth(3, 200);
connect(m_ui->dvConflicts->searchView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->dvConflicts->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
connect(m_ui->dvConflicts->treeView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->dvConflicts->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
m_ui->dvConflicts->treeView()->expandAll();
return true;
}
void ConflictsDialog::updateModel()
{
if(m_sourceModel)
{
m_sourceModel->onConflictedDataChanged();
m_ui->dvConflicts->treeView()->expandAll();
}
}
void ConflictsDialog::dataChanged(const InfrastructureManagement::MainSchedule &data, DataModification modType)
{
Q_UNUSED(modType);
if (data.id() == m_scheduleId)
m_sourceModel->initModel(m_scheduleId, m_anotherScheduleId, m_dtc);
}
void ConflictsDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->dvConflicts->setColumnsOrganiserEnabled(identifier(), true);
}
void ConflictsDialog::onPrint()
{
MainSchedule plan1 = m_dtc->mainSchedule(m_scheduleId);
MainSchedule plan2 = m_dtc->mainSchedule(m_anotherScheduleId);
m_ui->dvConflicts->treeView()->expandAll();
QString header;
header += QStringLiteral("<p>");
header += QStringLiteral("<b>") + tr("Overview Conflicts") + QStringLiteral("</b>");
header += QStringLiteral("<hr/>");
header += tr("Current Instrumentation Plan: %1").arg(QString::fromStdString(plan1.name()));
header += QStringLiteral(" - ");
if (plan1.timeStart().is_set())
header += tr("START: %1").arg(DTG::toStringMSec(plan1.timeStart().get()));
else
header += tr("START: %1").arg(tr("[N/A]"));
header += QStringLiteral(" - ");
if (plan1.timeEnd().is_set())
header += tr("END: %1").arg(DTG::toStringMSec(plan1.timeEnd().get()));
else
header += tr("END: %1").arg(tr("[N/A]"));
header += QStringLiteral("<br/>");
header += tr("Compared Instrumentation Plan: %1").arg(QString::fromStdString(plan2.name()));
header += QStringLiteral(" - ");
if (plan2.timeStart().is_set())
header += tr("START: %1").arg(DTG::toStringMSec(plan2.timeStart().get()));
else
header += tr("START: %1").arg(tr("[N/A]"));
header += QStringLiteral(" - ");
if (plan2.timeEnd().is_set())
header += tr("END: %1").arg(DTG::toStringMSec(plan2.timeEnd().get()));
else
header += tr("END: %1").arg(tr("[N/A]"));
header += QStringLiteral("<br/>");
header += QStringLiteral("</p>");
LtsPrinting::printView(m_session, this, m_ui->dvConflicts->treeView(), header);
}
void ConflictsDialog::onCustomContextMenu(QPoint pos)
{
QMenu *contextMenu = new QMenu(this);
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
{
QAction *action = new QAction(tr("Expand All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->dvConflicts->expandAll();
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->dvConflicts->collapseAll();
});
contextMenu->addAction(action);
}
contextMenu->addSeparator();
QModelIndex index = m_ui->dvConflicts->treeView()->indexAt(pos);
bool hasChildren = m_ui->dvConflicts->treeView()->model()->rowCount(index) > 0;
{
QAction *action = new QAction(tr("Expand"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
#if QT_VERSION < QT_VERSION_CHECK(5,13,0)
m_ui->dvConflicts->treeView()->expand(index);
#else
m_ui->dvConflicts->treeView()->expandRecursively(index);
#endif
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
m_ui->dvConflicts->treeView()->collapse(index);
});
contextMenu->addAction(action);
}
contextMenu->popup(m_ui->dvConflicts->treeView()->mapToGlobal(pos));
}
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* The ConflictsDialog shows differences between 2 instrumentation plans
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLTE, 2022-11-15
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
namespace Ui
{
class ConflictsDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class ConflictsDialogModel;
class ConflictsDialog final
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit ConflictsDialog(const QString &menuGroup, QWidget *parent = nullptr);
~ConflictsDialog();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
int scheduleId,
int anotherScheduleId);
void updateModel();
private: // methods
void retranslate() override;
void dataChanged(const InfrastructureManagement::MainSchedule &data, DataModification modType);
void tableColumnOrganiserSetting() override;
private slots:
void onPrint();
void onCustomContextMenu(QPoint pos);
private: // attributes
Ui::ConflictsDialog *m_ui{nullptr};
ConflictsDialogModel *m_sourceModel{nullptr};
std::shared_ptr<Interface::Dtc> m_dtc{nullptr};
QString m_menuGroup;
LtsSession::LtsSession *m_session{nullptr};
int m_scheduleId{-1};
int m_anotherScheduleId{-1};
LOGGER_T m_logger;
}; // class ConflictsDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConflictsDialog</class>
<widget class="QWidget" name="ConflictsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1169</width>
<height>517</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Differences</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="LtsDataView::LtsDataView" name="dvConflicts" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
<property name="toolButtonsVisible" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,388 @@
/**
* @RDE_HEADER@
* The ConflictsDialog shows differences between 2 instrumentation plans
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLTE, 2022-11-15
*/
#include "ism_overview_conflicts_model.h"
#include <InfrastructureManagement/ism_translation.h>
#include <QDebug>
#include <QElapsedTimer>
// #define BENCHMARK
#ifdef BENCHMARK
# include <QElapsedTimer>
# include <QDebug>
#endif
static const int maxIntValue = std::numeric_limits<int>::max();
namespace InfrastructureManagement
{
ConflictsDialogModel::ConflictsDialogModel(QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), { tr("Name"), tr("Type"), tr("Aim State"), tr("Conflict State") })
, m_dtc(nullptr)
, m_scheduleId(-1)
, m_anotherScheduleId(-1)
, m_logger(getLogger("OverviewConflictsDialogModel"))
{
}
QVariant ConflictsDialogModel::data(const QModelIndex &index, int role) const
{
if ( !index.isValid() && (role == Qt::DisplayRole || role == Qt::DecorationRole) )
return QVariant();
NGLTreeItem *item = privateData(index);
if (role == Qt::DisplayRole)
{
if (index.column() != NAME && !item->data().canConvert<ConflictMountingPointData>())
return QVariant();
const ConflictMountingPointData itemData = item->data().value<ConflictMountingPointData>();
switch (index.column())
{
case NAME:
if (item->data().canConvert<ConflictMountingPointData>())
return item->data().value<ConflictMountingPointData>().name;
if (item->data().canConvert<ConflictStructureElementData>())
return item->data().value<ConflictStructureElementData>().name;
return tr("all");
case AIM_STATE:
if (itemData.seType == StructureElementType::MountingPoint)
return toString(itemData.aimState);
break;
case CONFLICT_STATE:
if (itemData.seType == StructureElementType::MountingPoint)
return toString(itemData.conflictState);
break;
case TYPE:
if (itemData.seType == StructureElementType::MountingPoint)
{
const MountingPointType mpt = itemData.mpType == MountingPointType::OutdoorIPS ? MountingPointType::IndoorIPS : itemData.mpType;
return toString(mpt);
}
break;
}
}
if (role == Qt::DecorationRole)
{
if (!item->data().canConvert<ConflictMountingPointData>())
return QVariant();
const ConflictMountingPointData itemData = item->data().value<ConflictMountingPointData>();
static const QIcon green(QLatin1String("icon:green_light.svg"));
static const QIcon red(QLatin1String("icon:red_light.svg"));
switch (index.column())
{
case AIM_STATE:
{
return itemData.aimState == MountingPointState_def::Equipped ? green : red;
}
case CONFLICT_STATE:
{
return itemData.conflictState == MountingPointState_def::Equipped ? green : red;
}
default:
return QVariant();
}
}
return QVariant();
}
QVariant ConflictsDialogModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
QString plan1 = QString::fromStdString(m_dtc->mainSchedule(m_scheduleId).name());
QString plan2 = QString::fromStdString(m_dtc->mainSchedule(m_anotherScheduleId).name());
Columns col = static_cast<Columns>(section);
switch (col)
{
case NAME:
return tr("Name");
case TYPE:
return tr("Type");
case AIM_STATE:
return tr("Aim State (%1)").arg(plan1);
case CONFLICT_STATE:
return tr("Conflict State (%1)").arg(plan2);
}
}
return NGLTreeModel::headerData(section, orientation, role);
}
bool ConflictsDialogModel::initModel(int scheduleId,
int anotherScheduleId,
const std::shared_ptr<Interface::Dtc> &dtc)
{
if (m_dtc == dtc) //already initialized...
return true;
if (!(dtc->enableMainStructureElement() &&
dtc->enableMainSchedule()))
{
ERROR_LOG(m_logger) << "Could not enable Data Topics";
return false;
}
/* Stand 2022.11.16
struct MountingPointType_def {
enum type {
Unknown = 0,
BuildingSensorModule = 1,
BuildingControlUnit = 2,
OutdoorCamera = 3,
IndoorCamera = 4,
OutdoorIPS = 5,
IndoorIPS = 6,
MeteoDataUnit = 7,
AnnouncementUnit = 10,
VirtualIPS = 11,
EffectGenerationControlUnit = 12,
OutdoorControlUnit = 13,
BuildingNetworkSwitch = 14
};
*/
// same as filters in Mounting Points Dialog (ism_mounting_point_list_dialog.cpp:196)?
m_visibleTypes = { MountingPointType_def::BuildingSensorModule,
// MountingPointType_def::OutdoorCamera,
MountingPointType_def::IndoorCamera,
MountingPointType_def::OutdoorIPS,
MountingPointType_def::IndoorIPS,
MountingPointType_def::EffectGenerationControlUnit
};
m_dtc = dtc;
m_scheduleId = scheduleId;
m_anotherScheduleId = anotherScheduleId;
initData();
beginResetModel();
endResetModel();
return true;
}
StructureElement ConflictsDialogModel::setBuildingGroup(int groupId)
{
StructureElement se;
BuildingGroup_def::type buildingGroup = static_cast<BuildingGroup_def::type>(groupId);
se.id() = maxIntValue - static_cast<int>(buildingGroup);
se.name() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.displayName() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.structureElementTypeId() = StructureElementType_def::Section;
return se;
}
void ConflictsDialogModel::onConflictedDataChanged()
{
if(m_rootItem)
initData();
}
void ConflictsDialogModel::initData()
{
NGLTreeModel::resetModel();
m_availableBuildingGroups.clear();
m_mountingPointIndexes.clear();
QHash<int /*<structureElementId>*/, MountingPointPlan> currentMountingPoints;
QHash<int /*<structureElementId>*/, MountingPointPlan> compareMountingPoints;
QHash<int/*<mse.id>*/, InfrastructureManagement::MainStructureElement> conflictedMainStructElements;
QSet<int> conflictedStructElIds;
#ifdef BENCHMARK
QElapsedTimer elapsedTimer1;
QElapsedTimer elapsedTimer2;
elapsedTimer1.start();
elapsedTimer2.start();
#endif // BENCHMARK
// Plan 1
InfrastructureManagement::MainSchedule currentSchedule = m_dtc->mainSchedule(m_scheduleId);
for (const InfrastructureManagement::MountingPointPlan &currentPlan : currentSchedule.elements())
{
StructureElement se;
if (!m_dtc->getStructureElementById(currentPlan.structureElementId(), se))
continue;
if (m_visibleTypes.contains(se.mountingPointTypeId()))
currentMountingPoints.insert(currentPlan.structureElementId(), currentPlan);
}
// Plan 2
InfrastructureManagement::MainSchedule compareSchedule = m_dtc->mainSchedule(m_anotherScheduleId);
for (const InfrastructureManagement::MountingPointPlan &comparePlan : compareSchedule.elements())
{
if (!currentMountingPoints.contains(comparePlan.structureElementId()))
continue;
StructureElement structEl;
if (!m_dtc->getStructureElementById(comparePlan.structureElementId(), structEl))
continue;
if (!m_visibleTypes.contains(structEl.mountingPointTypeId()))
continue;
// calculate final state for this MP, except conflicts
// p1 | p2 | final
// equipped equipped +1
// equipped idle +1
// idle equipped +1
// empty empty 0
// idle idle 0
// empty idle 0
// idle empty 0
// equipped empty - conflict
// empty equipped - conflict
const MountingPointPlan &mp1 = currentMountingPoints[comparePlan.structureElementId()];
if ((mp1.mountingPointState() == MountingPointState::Equipped && comparePlan.mountingPointState() == MountingPointState::Empty) ||
(mp1.mountingPointState() == MountingPointState::Empty && comparePlan.mountingPointState() == MountingPointState::Equipped))
{
compareMountingPoints.insert(comparePlan.structureElementId(), comparePlan);
StructureElement se;
// get mounting point path: (building id, floor id, room id)
if (!m_dtc->getStructureElementById(comparePlan.structureElementId(), se))
continue;
const std::vector<int> &path = se.path();
for(const auto &seId : path)
conflictedStructElIds.insert(seId);
if(conflictedMainStructElements.contains(se.mainStructureElementId()))
continue;
const MainStructureElement &mse = m_dtc->mainStructureElement(se.mainStructureElementId());
conflictedMainStructElements.insert(mse.id(), mse);
}// end if currentMountingPoint contains cmp mounting point plan
}
#ifdef BENCHMARK
qCritical() << " OverviewDialogModel::initData-BENCHMARK: compareSchedule took " << elapsedTimer1.elapsed() << " [ms]";
#endif // BENCHMARK
for (const MainStructureElement &mse : conflictedMainStructElements)
{
// only consider buildings
if (mse.structureElementTypeId() != StructureElementType::Building)
continue;
// 1- if a buildingGroup modelIndex for current building doesn't exist
// a new one will be first added and used as parentIndex for the blg_Index.
QModelIndex groupIndex;
const StructureElement bse = setBuildingGroup(mse.groupId());
if(!m_availableBuildingGroups.contains(bse.id()))
{
ConflictStructureElementData buildingGroup;
buildingGroup.name = QString::fromStdString(bse.displayName());
NGLTreeItem *groupItem = new NGLTreeItem(QVariant::fromValue(buildingGroup));
QModelIndex groupParentIndex;
groupParentIndex = indexFromItem(m_rootItem);
insertRow(rowCount(groupParentIndex), groupParentIndex, groupItem);
groupIndex = index(groupItem->row(), 0, groupParentIndex);
m_mountingPointIndexes.insert(bse.id(), groupIndex);
m_availableBuildingGroups.insert(bse.id());
}
else
{
groupIndex = m_mountingPointIndexes.value(bse.id(), indexFromItem(m_rootItem));
}
for (const StructureElement &currentElement : mse.elements())
{
NGLTreeItem *item = nullptr;
if (!conflictedStructElIds.contains(currentElement.id()))
continue;
if (currentElement.structureElementTypeId() == StructureElementType::MountingPoint)
{
if (!currentMountingPoints.contains(currentElement.id()))
continue;
const MountingPointPlan &mountingPoint = currentMountingPoints[currentElement.id()];
// we don't care about Idle items
if (mountingPoint.mountingPointState() == MountingPointState::Idle)
continue;
auto compareMountingPointState = compareMountingPoints.value(currentElement.id()).mountingPointState();
if (mountingPoint.mountingPointState() == compareMountingPointState)
{
DEBUG_LOG(m_logger) << "No conflict for mounting point id = " << currentElement.id() << " - " << currentElement.name();
continue;
}
ConflictMountingPointData mpData;
mpData.seType = currentElement.structureElementTypeId();
mpData.id = currentElement.id();
mpData.name = currentElement.displayName().empty() ? QString::fromStdString(currentElement.name()) : QString::fromStdString(currentElement.displayName());
mpData.aimState = mountingPoint.mountingPointState();
mpData.conflictState = compareMountingPointState;
mpData.mpType = currentElement.mountingPointTypeId();
DEBUG_LOG(m_logger) << "## MP Id = " << mpData.id;
DEBUG_LOG(m_logger) << "## MP Name = " << mpData.name;
DEBUG_LOG(m_logger) << "## Aim state = " << mpData.aimState;
DEBUG_LOG(m_logger) << "Adding mounting point id = " << mpData.id << " - " << mpData.name;
item = new NGLTreeItem(QVariant::fromValue(mpData));
}
else
{
ConflictStructureElementData ssed;
ssed.name = currentElement.displayName().empty() ? QString::fromStdString(currentElement.name()) : QString::fromStdString(currentElement.displayName());
item = new NGLTreeItem(QVariant::fromValue(ssed));
}
const auto &path = currentElement.path();
QModelIndex parentIndex;
if (path.size() > 1)
{
parentIndex = m_mountingPointIndexes.value(path.at(path.size() - 2), indexFromItem(m_rootItem)); //default sollte nie erreicht werden
if (!parentIndex.isValid())
{
DEBUG_LOG(m_logger) << "Did not find parent for structure element with id " << currentElement.id() << " mseid: " << mse.id();
for (const StructureElement &se : mse.elements())
DEBUG_LOG(m_logger) << " se: " << se.id() << ", " << se.displayName() << ", " << se.name();
}
}
else
{
// Isn't indexFrom RootItem == QModelIndex() ?!?
parentIndex = groupIndex.isValid() ? groupIndex : indexFromItem(m_rootItem);
DEBUG_LOG(m_logger) << "Insert row under root: " << currentElement.displayName();
}
insertRow(rowCount(parentIndex), parentIndex, item);
m_mountingPointIndexes.insert(currentElement.id(), index(item->row(), 0, parentIndex));
}//end for-loop over conflicted structureelements
} //end for-loop over conflicted mainstructureelements
#ifdef BENCHMARK
qCritical() << " OverviewDialogModel::initData-BENCHMARK: initData took " << elapsedTimer2.elapsed() << " [ms]";
#endif // BENCHMARK
}
}// namespace InfrastructureManagement
@@ -0,0 +1,124 @@
/**
* @RDE_HEADER@
* The ConflictsDialog shows differences between 2 instrumentation plans
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLTE, 2022-11-15
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <nglwidgets/ngltreemodel.h>
#include <nglwidgets/ngltreeitem.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QSet>
#include <QList>
#include <QHash>
#include <QTimer>
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
struct ConflictMountingPointData
{
int32_t id = 0; // se_id
QString name; // se_name
StructureElementType seType;
MountingPointType mpType;
MountingPointState aimState; // in Plan1 (m_scheduleId)
MountingPointState conflictState; // in Plan2 (m_anotherScheduleId)
bool isMountingPoint() const { return seType == StructureElementType::MountingPoint; }
};
struct ConflictBuildingGroupData
{
QString name;
};
struct ConflictStructureElementData
{
QString name;
};
class ConflictsDialogModel final : public NGLTreeModel
{
Q_OBJECT
public:
public:
enum Columns
{
NAME,
TYPE,
AIM_STATE,
CONFLICT_STATE
};
explicit ConflictsDialogModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override final;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
bool initModel(int scheduleId, int anotherScheduleId,
const std::shared_ptr<Interface::Dtc> &dtc);
StructureElement setBuildingGroup(int groupId);
public slots:
void onConflictedDataChanged();
private:
void initData();
// friend class ConflictsDialogSortModel;
std::shared_ptr<Interface::Dtc> m_dtc;
int32_t m_scheduleId;
int32_t m_anotherScheduleId;
QHash<int, QModelIndex> m_mountingPointIndexes;
QSet<int> m_availableBuildingGroups;
QList<MountingPointType> m_visibleTypes;
LOGGER_T m_logger;
};
/*
class ConflictsDialogSortModel final : public LtsWidgets::LtsColumnFilterProxyModel
{
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel ) override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
//QList<MountingPointType> getVisibleTypes() { return m_visibleTypes ;}
//using LtsWidgets::LtsColumnFilterProxyModel::invalidateFilter;
private:
ConflictsDialogModel *m_sourceModel = nullptr;
QList<MountingPointType> m_visibleTypes;
};
*/
} // namespace InfrastructureManagement
Q_DECLARE_METATYPE(InfrastructureManagement::ConflictMountingPointData)
Q_DECLARE_METATYPE(InfrastructureManagement::ConflictStructureElementData)
Q_DECLARE_METATYPE(InfrastructureManagement::ConflictBuildingGroupData)
@@ -0,0 +1,231 @@
/**
* @RDE_HEADER@
* The OverviewDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_overview_dialog.h"
#include "ism_overview_conflicts_dialog.h"
#include "ui_ism_overview_dialog.h"
#include "ism_overview_dialog_model.h"
#include "ism_overview_conflicts_dialog.h"
#include <ngltools/ngltools_dtg.h>
#include <InfrastructureManagement/ism_translation.h>
#include <LtsSession/lts_session.h>
#include <LtsPrinting/printing.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <QTreeView>
#include <QDateTime>
#include <QComboBox>
#include <QTimer>
namespace InfrastructureManagement
{
OverviewDialog::OverviewDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_session(session)
, m_ui(new Ui::OverviewDialog)
, m_menuGroup(menuGroup)
, m_logger(getLogger("OverviewDialog"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->setupUi(this);
m_timerUpdateView = new QTimer(this);
m_timerUpdateView->setSingleShot(true);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &OverviewDialog::onPrint);
connect(m_ui->cbComparePlan, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OverviewDialog::onCbComparePlanIndexChanged);
connect(m_ui->cbBasePlan, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OverviewDialog::onCbBasePlanIndexChanged);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Overview"));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
OverviewDialog::~OverviewDialog()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete m_ui;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::aboutToClose()
{
DEBUG_LOG(m_logger) << "About to close";
if (m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts")))
m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts"))->closeRequest();
}
void OverviewDialog::retranslate()
{
translate(m_ui, m_dtc->mainSchedule(m_scheduleId), tr("Overview"));
}
void OverviewDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->overviewView->setColumnsOrganiserEnabled(identifier(), true);
}
bool OverviewDialog::init(int planId,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_scheduleId = planId;
m_dtc = dtc;
m_ftc = ftc;
m_dataIfc = dataInterface;
delete m_model;
setCbComparePlan();
setCbBasePlan();
m_model = new OverviewDialogModel(this);
if (!m_model->initModel(m_scheduleId, m_dtc, 0))
{
delete m_model;
m_model = nullptr;
return false;
}
m_ui->overviewView->setModel(m_model);
connect(m_dataIfc.get(), &ForeignDataInterface::scheduleIdChanged, this, &OverviewDialog::onScheduleIdChanged);
connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged, this, &OverviewDialog::onPlansDataChanged);
connect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged, this, &OverviewDialog::onPlansDataChanged);
connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged, this, &OverviewDialog::onPlansDataChanged);
connect(m_timerUpdateView, &QTimer::timeout, this, &OverviewDialog::reloadModel);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void OverviewDialog::setCbBasePlan()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->cbBasePlan->clear();
m_ui->cbBasePlan->addItem(tr("Actual Mountings"), 0);
m_ui->cbBasePlan->insertSeparator(1);
for (auto ms : m_dtc->mainSchedules())
m_ui->cbBasePlan->addItem(QString::fromStdString(ms.name()), ms.id());
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::setCbComparePlan()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->cbComparePlan->clear();
m_ui->cbComparePlan->addItem(tr("All active(*) plans"),0);
m_ui->cbComparePlan->insertSeparator(1);
for (auto ms : m_dtc->mainSchedules())
m_ui->cbComparePlan->addItem((ms.statusId() == ScheduleStatus_def::Active ? QLatin1Literal("* ") : QLatin1Literal(" ")) +
QString::fromStdString(ms.name()), ms.id());
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::onPrint()
{
MainSchedule ms = m_dtc->mainSchedule(m_scheduleId);
QString header;
header += QStringLiteral("<p>");
header += tr("Instrumentation Plan: %1").arg(QString::fromStdString(ms.name()));
header += QStringLiteral("<br/>");
header += tr("Status: %1").arg(toString(ms.statusId()));
header += QStringLiteral("<br/>");
header += tr("Created: %1").arg(DTG::toStringMSec(ms.timeCreated()));
header += QStringLiteral("<br/>");
if (ms.timeStart().is_set())
header += tr("START: %1").arg(DTG::toStringMSec(ms.timeStart().get()));
else
header += tr("START: %1").arg(tr("[N/A]"));
header += QStringLiteral(" - ");
if (ms.timeEnd().is_set())
header += tr("END: %1").arg(DTG::toStringMSec(ms.timeEnd().get()));
else
header += tr("END: %1").arg(tr("[N/A]"));
header += QStringLiteral("<br/>");
header += QStringLiteral("</p>");
LtsPrinting::printView(m_session, this, m_ui->overviewView->treeView() , header);
}
void OverviewDialog::onScheduleIdChanged(int32_t scheduleId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_scheduleId == scheduleId)
return;
setCbComparePlan();
setCbBasePlan();
m_scheduleId = scheduleId;
updateOverviewData();
// close Dialog OverviewConflicts, if open
if (m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts")))
m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts"))->closeRequest();
retranslate();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::onCbComparePlanIndexChanged(int index)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
Q_UNUSED(index);
updateOverviewData();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::onCbBasePlanIndexChanged(int index)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
Q_UNUSED(index);
updateOverviewData();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::onPlansDataChanged()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
updateOverviewData(); //reloadModel();
ConflictsDialog *dialog = static_cast<ConflictsDialog*>(m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts")));
if (dialog)
{
dialog->updateModel();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void OverviewDialog::updateOverviewData()
{
m_timerUpdateView->start(100);
}
void OverviewDialog::reloadModel()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_model == nullptr)
return;
const int simPlanId = m_ui->cbBasePlan->currentData().toInt();
const int cmpPlanId = m_ui->cbComparePlan->currentData().toInt();
m_model->initModel(m_scheduleId, m_dtc, cmpPlanId, simPlanId);
// close conflict dialog if opened
if (m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts")))
m_session->baseLayout()->getWidget(m_menuGroup, QStringLiteral("OverviewConflicts"))->closeRequest();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
} // namespace InfrastructureManagement
@@ -0,0 +1,77 @@
/**
* @RDE_HEADER@
* The OverviewDialog shows how many assets are needed for a specific schedule, needed elsewhere,
* totally possessed, free, and missing
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <Plugins/InfrastructureManagement/Data/ism_data_plugin.h>
#include <InfrastructureManagement/logger.h>
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
namespace Ui
{
class OverviewDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class OverviewDialogModel;
class OverviewDialog
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit OverviewDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~OverviewDialog();
bool init(int planId,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface);
void setCbComparePlan();
void setCbBasePlan();
protected:
void aboutToClose() override;
private slots:
void onPrint();
void onScheduleIdChanged(int32_t scheduleId);
void onCbComparePlanIndexChanged(int index);
void onCbBasePlanIndexChanged(int index);
void onPlansDataChanged();
void updateOverviewData();
void reloadModel();
private:
void retranslate() override;
void tableColumnOrganiserSetting() override;
LtsSession::LtsSession *m_session{nullptr};
Ui::OverviewDialog *m_ui{nullptr};
int m_scheduleId{-1};
OverviewDialogModel *m_model{nullptr};
QString m_menuGroup;
std::shared_ptr<Interface::Dtc> m_dtc{nullptr};
std::shared_ptr<Interface::Ftc> m_ftc{nullptr};
std::shared_ptr<ForeignDataInterface> m_dataIfc{nullptr};
ForeignResourceManagementGuiInterface *m_ismGuiIfc{nullptr};
QTimer *m_timerUpdateView{nullptr};
LOGGER_T m_logger;
};
} // namespace InfrastructureManagement
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OverviewDialog</class>
<widget class="QWidget" name="OverviewDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Asset Availability</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbxBasePlan">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Base Plan:</string>
</property>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsComboBox" name="cbBasePlan"/>
</item>
<item>
<widget class="QLabel" name="lbxComparePlan">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Plan to compare:</string>
</property>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsComboBox" name="cbComparePlan"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="LtsDataView::LtsDataView" name="overviewView" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,466 @@
/**
* @RDE_HEADER@
* The OverviewDialogModel provides data for OverviewDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#include "ism_overview_dialog_model.h"
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <InfrastructureManagement/ism_translation.h>
#include <algorithm>
//#define BENCHMARK
#ifdef BENCHMARK
# include <QElapsedTimer>
# include <QDebug>
#endif
namespace InfrastructureManagement
{
OverviewDialogModel::OverviewDialogModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<RowData>( {tr("Type"),
tr("Base Demand"),
tr("Compare Demand"),
tr("Total Demand"),
tr("Assets"),
tr("Free assets"),
tr("Available")
},
parent)
, m_loadedScheduleId(-1)
, m_comparedScheduleId(0)
, m_dtc(nullptr)
, m_logger(getLogger("OverviewDialogModel"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
//#define TEST
m_vecData = {RowData(MountingPointType::BuildingSensorModule),
RowData(MountingPointType::EffectGenerationControlUnit),
#ifdef TEST
MountingPointType::BuildingControlUnit,
MountingPointType::BuildingNetworkSwitch,
MountingPointType::OutdoorCamera,
MountingPointType::OutdoorControlUnit,
MountingPointType::OutdoorIPS,
MountingPointType::AnnouncementUnit,
#endif
RowData(MountingPointType::IndoorCamera),
RowData(MountingPointType::IndoorIPS)}; //TODO: for Guez add OutdoorIPS, for non-Guez show separate!
m_refMap[MountingPointType_def::BuildingSensorModule] = 0;
m_refMap[MountingPointType_def::EffectGenerationControlUnit] = 1;
m_refMap[MountingPointType_def::IndoorCamera] = 2;
m_refMap[MountingPointType_def::IndoorIPS] = 3;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
QVariant OverviewDialogModel::data(const QModelIndex &index, int role) const
{
if (!indexIsValid(index))
return {};
const auto &rowData = m_vecData.at(index.row());
// If we want to display OutdoorIPS (as IndoorIPS) (later), we need to remove this and chnage mpt to IndoorIPS...
if (rowData.mpt == MountingPointType::OutdoorIPS)
return {};
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case TYPE:
return toString(rowData.mpt);
case BASEPLAN_DEMAND:
return rowData.basePlanDemand;
case COMPARED_DEMAND:
return rowData.comparePlanDemand;
case TOTAL_DEMAND:
return rowData.totalDemand;
case ASSETS_OWNED:
return rowData.assetCount;
case ASSETS_FREE:
return rowData.assetsFree;
case ASSETS_AVAILABLE:
return rowData.assetsAvailable;
default:
return {};
}
}
else if (role == Qt::DecorationRole)
{
static const QIcon green(QLatin1String("icon:green_light.svg"));
static const QIcon red(QLatin1String("icon:red_light.svg"));
static const QIcon yellow(QLatin1String("icon:yellow_light.svg"));
switch (index.column())
{
case ASSETS_AVAILABLE:
{
if (rowData.assetsAvailable == 0)
return yellow;
else
return rowData.assetsAvailable < 0 ? red : green;
}
default:
return {};
}
}
return {};
}
bool OverviewDialogModel::initModel(int32_t mainScheduleId,
const std::shared_ptr<Interface::Dtc> &dtc,
int32_t comparedScheduleId, int32_t basePlanId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_dtc = dtc;
m_loadedScheduleId = mainScheduleId;
m_comparedScheduleId = comparedScheduleId;
m_basePlanId = basePlanId;
m_mountingPointAssets = m_dtc->mountingPointAssets();
if (!m_dtc->mainSchedules().contains(m_loadedScheduleId))
{
m_loadedScheduleId = -1;
ERROR_LOG(m_logger) << "Invalid scheduleId = " << mainScheduleId;
return false;
}
DEBUG_LOG(m_logger) << "[INITIAL] loaded: "<<m_loadedScheduleId<<" cmp: "<<m_comparedScheduleId<<" sim: "<<m_basePlanId;
if (!initData())
{
ERROR_LOG(m_logger) << "Could not init data";
return false;
}
DEBUG_LOG(m_logger) << "initModel successful";
// initModel will be executed later -> Qt::UniqueConnection
connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged,
this, &OverviewDialogModel::initData, Qt::UniqueConnection);
connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged,
this, &OverviewDialogModel::initData, Qt::UniqueConnection);
connect(m_dtc.get(), &Interface::Dtc::instrumentationAssetChanged,
this, &OverviewDialogModel::initData, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool OverviewDialogModel::initData()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
#ifdef BENCHMARK
QElapsedTimer elapsedTimer1;
elapsedTimer1.start();
#endif // BENCHMARK
beginResetModel();
// m_neededPerType.clear();
endResetModel();
m_conflictedStructureElementIds.clear();
// if (m_basePlanId != 0)
// setOverviewSimulatedData();
// else
// setOverviewData();
setNewData();
for ( int mppId : qAsConst(m_conflictedStructureElementIds))
DEBUG_LOG(m_logger) << "Conflicted structure element id = " << mppId;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
MountingPointType OverviewDialogModel::getMountingPointTypeId(int structureElementId)
{
if (m_availableMountingPointTypes.contains(structureElementId))
return m_availableMountingPointTypes[structureElementId];
StructureElement se;
if (!m_dtc->getStructureElementById(structureElementId, se))
return MountingPointType_def::get_default();
//OutdoorIPS will be considered as IndoorIPS
const MountingPointType mpType = (se.mountingPointTypeId() == MountingPointType_def::OutdoorIPS) ? MountingPointType_def::IndoorIPS : se.mountingPointTypeId();
m_availableMountingPointTypes.insert(structureElementId, mpType);
return mpType;
}
bool OverviewDialogModel::hasMountedAsset(int seId)
{
for (const InfrastructureManagement::MountingPointAsset &asset : qAsConst(m_mountingPointAssets))
{
if (asset.structureElementId() == seId)
return true;
}
return false;
}
bool OverviewDialogModel::hasConflictedMountingPoints()
{
return !m_conflictedStructureElementIds.isEmpty();
}
/**
* @brief OverviewDialogModel::mergePlans
* @param currPlanId : loaded schedule id
* @param currPlan : current active mounting points
* @param cmpPlanId: plan == 0: no compare plan | plan > 0: plan to compare with
* @return
*/
QHash<int/*sructElId*/, MountingPointPlan> OverviewDialogModel::mergePlans(const QHash<int/*sructElId*/, MountingPointPlan> &currPlan, const int cmpPlanId)
{
DEBUG_LOG(m_logger)<<"[MERGE PLANs] currPlanId: "<<m_loadedScheduleId<<" ; cmpPlanId: "<<cmpPlanId;
QHash<int/*sructElId*/, MountingPointPlan> mergedPlan = currPlan;
// iterate over all active plan
const auto msConst = m_dtc->mainSchedules();
for (const auto &schedule : msConst)
{
if (cmpPlanId == 0 && schedule.statusId() != ScheduleStatus_def::Active)
continue;
if (cmpPlanId != 0 && cmpPlanId != schedule.id())
continue;
for (const MountingPointPlan &currentMpp : schedule.elements())
{
if (m_conflictedStructureElementIds.contains(currentMpp.structureElementId()))
continue;
const MountingPointType mpType = getMountingPointTypeId(currentMpp.structureElementId());
if (!m_refMap.contains(mpType))
continue;
if (currPlan.contains(currentMpp.structureElementId()))
{
const MountingPointPlan &basePlanMpp = currPlan[currentMpp.structureElementId()];
/// 1. conflicted when 1&2: equipped | empty.
/// 2. state of merge is idle when on conflict
if ((basePlanMpp.mountingPointState() == MountingPointState::Equipped && currentMpp.mountingPointState() == MountingPointState::Empty) ||
(basePlanMpp.mountingPointState() == MountingPointState::Empty && currentMpp.mountingPointState() == MountingPointState::Equipped))
{
DEBUG_LOG(m_logger)<<" conflicted name: "<<currentMpp.structureElementId();
mergedPlan[currentMpp.structureElementId()].mountingPointState(MountingPointState::Idle);
m_conflictedStructureElementIds.insert(basePlanMpp.structureElementId());
}
else
{
switch(basePlanMpp.mountingPointState().underlying())
{
case MountingPointState_def::Empty:
mergedPlan[currentMpp.structureElementId()].mountingPointState(MountingPointState::Empty);
break;
case MountingPointState_def::Equipped:
mergedPlan[currentMpp.structureElementId()].mountingPointState(MountingPointState::Equipped);
break;
case MountingPointState_def::Idle:
mergedPlan[currentMpp.structureElementId()].mountingPointState(currentMpp.mountingPointState());
break;
default:
break;
}
}
}
else
{
mergedPlan[currentMpp.structureElementId()] = currentMpp;
}
}//end for-loop over mountingPointPlans
}// end for-loop over schedules
return mergedPlan;
}
void OverviewDialogModel::setNewData()
{
QHash<int /*<structureElementId>*/, MountingPointPlan> baseMountingPointPlans;
// If basePlanId == 0 -> current actual status is used.
DEBUG_LOG(m_logger) << "We compare plan " << m_basePlanId << " with " << m_comparedScheduleId;
baseMountingPointPlans.clear();
m_conflictedStructureElementIds.clear();
// ...on InstrumentationAssetsChanged(); || BasePlanChanged and BasePlanId == 0
for (int id : qAsConst(m_refMap))
{
m_vecData[id] = RowData(m_vecData[id].mpt);
// val.assetCount = 0;
// val.assetsDefect = 0;
// val.assetsFree = 0;
// val.assetsMounted = 0;
// val.basePlanDemand = 0;
// val.basePlanUnmount = 0;
}
const auto iaConst = m_dtc->instrumentationAssets();
for (const InstrumentationAsset &asset : iaConst )
{
//OutdoorIPS will be considered as IndoorIPS
const MountingPointType mpType = (asset.mountingPointTypeId() == MountingPointType::OutdoorIPS) ? MountingPointType::IndoorIPS : asset.mountingPointTypeId();
if (!m_refMap.contains(mpType))
continue;
++m_vecData[m_refMap[mpType]].assetCount;
/// Defekte Komponente
if (asset.assetStateId() == InstrumentationAssetState_def::Defect)
++m_vecData[m_refMap[mpType]].assetsDefect;
if (asset.assetStateId() == InstrumentationAssetState_def::Unmounted)
++m_vecData[m_refMap[mpType]].assetsFree;
if (asset.assetStateId() == InstrumentationAssetState_def::Mounted)
{
++m_vecData[m_refMap[mpType]].assetsMounted;
if (m_basePlanId == 0)
++m_vecData[m_refMap[mpType]].basePlanDemand;
}
}
// onMainSchedule[basePlanId]Changed || basePlanId changed
// for (auto id : m_refMap)
// {
// auto &val = m_vecData[id];
// val.basePlanDemand = 0;
// val.basePlanUnmount = 0;
// }
if (m_basePlanId > 0)
{
MainSchedule baseSchedule = m_dtc->mainSchedules().value(m_basePlanId);
for (const MountingPointPlan &mpp : baseSchedule.elements())
{
const MountingPointType mpType = getMountingPointTypeId(mpp.structureElementId());
if (!m_refMap.contains(mpType))
continue;
baseMountingPointPlans.insert(mpp.structureElementId(), mpp);
if (mpp.mountingPointState() == MountingPointState::Equipped)
++m_vecData[m_refMap[mpType]].basePlanDemand;
}
}
else
{
// Todo: Save this in m_currentMountingPointState and update onMSEChanged(), here: Get a copy into m_mergedMountingPoints
const auto msesConst = m_dtc->mainStructureElements();
for(const auto &mse : msesConst)
for (const auto &se : mse.elements())
if (hasMountedAsset(se.id()))
baseMountingPointPlans.insert(se.id(), MountingPointPlan(se.id(), MountingPointState_def::Equipped));
}
QHash<int/*sructElId*/, MountingPointPlan> comparedMountingPointPlans = mergePlans({}, m_comparedScheduleId);
QHash<int/*sructElId*/, MountingPointPlan> totalMPPs = comparedMountingPointPlans;
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QHashIterator<int, MountingPointPlan> it(baseMountingPointPlans);
while (it.hasNext())
{
it.next();
totalMPPs.insert(it.key(), it.value());
}
#else
totalMPPs.insert(baseMountingPointPlans);
#endif //
/// Übergreifender Bedarf
for(const auto &bla: totalMPPs)
{
MountingPointPlan compareMpp = comparedMountingPointPlans.value(bla.structureElementId(), MountingPointPlan(bla.structureElementId(), MountingPointState_def::Idle));
MountingPointPlan baseMpp = baseMountingPointPlans.value(bla.structureElementId(), MountingPointPlan(bla.structureElementId(), MountingPointState_def::Idle));
const MountingPointType mpType = getMountingPointTypeId(bla.structureElementId());
if (!m_refMap.contains(mpType))
continue;
switch(baseMpp.mountingPointState().underlying())
{
case MountingPointState_def::Empty:
if (compareMpp.mountingPointState() == MountingPointState_def::Equipped)
++m_vecData[m_refMap[mpType]].totalDemand;
break;
case MountingPointState_def::Equipped:
if (compareMpp.mountingPointState() != MountingPointState_def::Equipped)
--m_vecData[m_refMap[mpType]].totalDemand;
break;
case MountingPointState_def::Idle:
if (compareMpp.mountingPointState() == MountingPointState_def::Equipped)
++m_vecData[m_refMap[mpType]].totalDemand;
break;
default:
break;
}
switch(compareMpp.mountingPointState().underlying())
{
case MountingPointState_def::Equipped:
++m_vecData[m_refMap[mpType]].comparePlanDemand;
break;
case MountingPointState_def::Empty:
++m_vecData[m_refMap[mpType]].comparePlanUnmount;
break;
default:
break;
}
}
/// Verfügbarer Bestand: ASSETS_OWNED - DEFECT_ASSETS - MERGED_MOUNTED_ASSET - NEED_EQUIPPED + MERGE_TO_UNMOUNT_ASSETS
/// Freie Komponente bei simulation: ASSETS_OWNED - MERGED_MOUNTED_ASSET - DEFEKT_ASSETS
for (auto id : qAsConst(m_refMap))
{
auto &rowData = m_vecData[id];
const int availableAssetCount =
rowData.assetCount
- rowData.assetsDefect
- rowData.assetsMounted
- rowData.comparePlanDemand
+ rowData.comparePlanUnmount;
rowData.assetsAvailable = availableAssetCount;
}
}
QString RowData::toString() const
{
return QStringLiteral("MPT ") + InfrastructureManagement::toString(mpt) +
QStringLiteral(", bpDem: ") + QString::number(basePlanDemand) +
QStringLiteral(", pbDiff: ") + QString::number(basePlanDifference) +
QStringLiteral(", cpDem: ") + QString::number(comparePlanDemand) +
QStringLiteral(", cpUmnt: ") + QString::number(comparePlanUnmount) +
QStringLiteral(", toDem: ") + QString::number(totalDemand) +
QStringLiteral(", asCnt: ") + QString::number(assetCount) +
QStringLiteral(", asFre: ") + QString::number(assetsFree) +
QStringLiteral(", AsAv: ") + QString::number(assetsAvailable) +
QStringLiteral(", AsMt: ") + QString::number(assetsMounted) +
QStringLiteral(", AsDef: ") + QString::number(assetsDefect);
}
} // namespace InfrastructureManagement
@@ -0,0 +1,108 @@
/**
* @RDE_HEADER@
* The OverviewDialogModel provides data for OverviewDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-11-03
*/
#pragma once
#include <LtsWidgets/lts_abstract_table_model.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
namespace InfrastructureManagement
{
struct RowData
{
MountingPointType mpt;
int basePlanDemand{0}; // "PlanBedarf" (Basisplan)
int basePlanDifference{0}; // Differenzbedarf (zum aktuellen Anbaustatus)
int comparePlanDemand{0}; // "Planbedarf" (VGL Einrüstplan) (= Differenz zu Basisplan)
int comparePlanUnmount{0}; // Im Vergleichsplan zu als demontiert markierte Assets.
int totalDemand{0}; // "Übergreifender Bedarf"
int assetCount{0}; // "Komponentenbestand" // All asset states
int assetsFree{0}; // "Freie Komponenten" // AssetState: Unmounted
int assetsAvailable{0}; // "Verfügbarer Bestand"
int assetsMounted{0}; // Aktuell gemountete Assets // AssetState: Mounted
int assetsDefect{0}; // Aktuell als defekt deklarierte Assets // AssetState: Defect
explicit RowData(MountingPointType _mpt)
: mpt(_mpt){}
QString toString() const;
};
class OverviewDialogModel : public LtsWidgets::LtsAbstractTableModel<RowData>
{
Q_OBJECT
public:
explicit OverviewDialogModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(int32_t mainScheduleId,
const std::shared_ptr<Interface::Dtc> &dtc,
int32_t comparedScheduleId = 0,
int32_t basePlanId = 0);
bool initData();
// void setOverviewData();
// void setOverviewSimulatedData();
void setNewData();
bool hasConflictedMountingPoints();
QMap<MountingPointType, int> getOtherActiveNeeded(const int &currPlanId);
private: // methods
QHash<int, MountingPointPlan> mergePlans(const QHash<int, MountingPointPlan> &currPlan, const int cmpPlanId);
void setTotalCmpActiveNeed(const QMap<int, MountingPointPlan> &mergedPlan);
MountingPointType getMountingPointTypeId(int structureElementId);
bool hasMountedAsset(int seId);
private: // other
enum Columns
{
TYPE =0,
BASEPLAN_DEMAND , // needed in current plan
COMPARED_DEMAND , // needed in compared plan
TOTAL_DEMAND , // needed current plan + needed in compared plan
ASSETS_OWNED , // TOTAL components in system
ASSETS_FREE , // total unmounted assets
ASSETS_AVAILABLE , // OWNED - mounted + to_unmount (FREE + assets_to_unmount, maximal TOTAL owned)
COLUMNs_COUNT // not displayed in view
};
private: // attributes
// QMap<MountingPointType, QVector<int>> m_neededPerType;
QHash<int/*seId*/, MountingPointType> m_availableMountingPointTypes;
int32_t m_loadedScheduleId{-1}; // loaded plan
int32_t m_basePlanId{0}; // simulated plan
int32_t m_comparedScheduleId{0}; // plan to compare with
std::shared_ptr<Interface::Dtc> m_dtc;
/**
* @brief m_includedMountingPoints
* contains all mpt from : loaded plan + (active plan or cmp plan). conflicted mntp are not included
*/
QSet<int /*<structureElementId>*/> m_conflictedStructureElementIds;
QMap<qint32, InfrastructureManagement::MountingPointAsset> m_mountingPointAssets;
QMap<MountingPointType, int> m_refMap;
LOGGER_T m_logger;
}; // class OverviewDialogModel
} // namespace InfrastructureManagement
@@ -0,0 +1,520 @@
/**
* @RDE_HEADER@
* tbc
* $Id$
* $HeadURL$
* $Author$
* Created by
*/
#include "ism_overview_mounting_point_list_dialog.h"
#include "ui_ism_overview_mounting_point_list_dialog.h"
#include <QTreeView>
#include <QListWidget>
#include <QMenu>
#include <qlabel.h>
#include <InfrastructureManagement/ism_translation.h>
#include <InfrastructureManagement/Shared/ism_mounting_point.h>
#include <LtsPrinting/printing.h>
#include <ngltools/ngltools_dtg.h>
#include <QMessageBox>
#include <QHeaderView>
#include <qscrollbar.h>
using namespace InfrastructureManagement;
/*!
* \brief OverviewMountingPointListDialog::OverviewMountingPointListDialog
* \param menuGroup
* \param parent
*/
OverviewMountingPointListDialog::OverviewMountingPointListDialog(const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_menuGroup(menuGroup)
, m_ui(new Ui::OverViewMountingPointListDialog)
, m_logger(getLogger("OverviewMountingPointListDialog"))
, m_actionMenu(new QMenu(this))
, m_printMountingAction(new QAction(tr("To Mount"), this))
, m_printUnmountingAction(new QAction(tr("To Unmount"), this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
setAttribute(Qt::WA_DeleteOnClose);
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Ressourcen-Completness_Check"));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Print, true);
m_actionMenu->addAction(m_printMountingAction);
m_actionMenu->addAction(m_printUnmountingAction);
connect(m_actionMenu, &QMenu::triggered, this, &OverviewMountingPointListDialog::onPrint);
m_buttonBox->setMenu(LtsWidgets::DialogButton::Print, m_actionMenu);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
OverviewMountingPointListDialog::~OverviewMountingPointListDialog()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete m_ui;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
/*!
* \brief OverviewMountingPointListDialog::init
* \param session
* \param dtc
* \param ftc
* \param dataInterface
* \return
*/
bool OverviewMountingPointListDialog::init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
int32_t scheduleId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, scheduleId=" << scheduleId;
m_dtc = dtc;
m_dataIfc = dataInterface;
m_session = session;
m_ftc = ftc;
m_scheduleId = scheduleId;
// disconnect(m_ui->mountingPointListView);
// disconnect(this);
if (!m_ftc->enableInstrumentationAssetModify())
{
ERROR_LOG(m_logger) << "Could not enable FT InstrumentationAssetModify of ISM";
return false;
}
if (!m_ftc->enableMountingPointPlanModify())
{
ERROR_LOG(m_logger) << "Could not enable FT enableMountingPointPlansModify of ISM";
return false;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " new ViewMountingPointListModel...";
delete m_sourceModel;
m_sourceModel = new ViewMountingPointListModel(this);
if (!m_sourceModel->initModel(m_dtc, m_dataIfc, m_scheduleId))
{
ERROR_LOG(m_logger) << "Could not init model";
delete m_sourceModel;
m_sourceModel = nullptr;
return false;
}
/// current state is equipped -> to unmount
DEBUG_LOG(m_logger) << LOGFUNCTION << " new m_mountedPointSortProxyModel ...";
delete m_mountedPointSortProxyModel;
m_mountedPointSortProxyModel = new ViewMountingPointListSortModel(this);
m_mountedPointSortProxyModel->setVisibleState(MountingPointState::Equipped);
m_mountedPointSortProxyModel->setSourceModel(m_sourceModel);
m_mountedPointSortProxyModel->sort(0, Qt::AscendingOrder);
connect(m_sourceModel, &ViewMountingPointListModel::dataChanged, m_mountedPointSortProxyModel, &ViewMountingPointListSortModel::invalidateFilter);
m_ui->mountingPointListView->setModel(m_mountedPointSortProxyModel);
m_ui->mountingPointListView->setSortingEnabled(true);
/// current state is empty -> to mount
DEBUG_LOG(m_logger) << LOGFUNCTION << " new m_unmountedPointSortProxyModel ...";
delete m_unmountedPointSortProxyModel;
m_unmountedPointSortProxyModel = new ViewMountingPointListSortModel(this);
m_unmountedPointSortProxyModel->setVisibleState(MountingPointState::Empty);
m_unmountedPointSortProxyModel->setSourceModel(m_sourceModel);
m_unmountedPointSortProxyModel->sort(0, Qt::AscendingOrder);
connect(m_sourceModel, &ViewMountingPointListModel::dataChanged, m_unmountedPointSortProxyModel, &ViewMountingPointListSortModel::invalidateFilter);
m_ui->unmountingPointListView->setModel(m_unmountedPointSortProxyModel);
m_ui->unmountingPointListView->setSortingEnabled(true);
m_ui->mountingPointListView->treeView()->setColumnWidth(0, 315);
m_ui->mountingPointListView->treeView()->setColumnWidth(1, 160);
// m_ui->mountingPointListView->treeView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
// m_ui->mountingPointListView->treeView()->header()->setSectionResizeMode(0, QHeaderView::Fixed);
m_ui->mountingPointListView->searchView()->setColumnWidth(0, 315);
m_ui->mountingPointListView->searchView()->setColumnWidth(1, 160);
// m_ui->mountingPointListView->searchView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
// m_ui->mountingPointListView->searchView()->header()->setSectionResizeMode(0, QHeaderView::Fixed);
m_ui->unmountingPointListView->treeView()->setColumnWidth(0, 315);
m_ui->unmountingPointListView->treeView()->setColumnWidth(1, 160);
// m_ui->unmountingPointListView->treeView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
// m_ui->unmountingPointListView->treeView()->header()->setSectionResizeMode(0, QHeaderView::Fixed);
m_ui->unmountingPointListView->searchView()->setColumnWidth(0, 315);
m_ui->unmountingPointListView->searchView()->setColumnWidth(1, 160);
// m_ui->unmountingPointListView->searchView()->header()->setSectionResizeMode(1, QHeaderView::Fixed);
// m_ui->unmountingPointListView->searchView()->header()->setSectionResizeMode(0, QHeaderView::Fixed);
//------------- Filter ----------------
DEBUG_LOG(m_logger) << LOGFUNCTION << " filter... ...";
const auto filters = { MountingPointType::BuildingSensorModule,
// MountingPointType::OutdoorCamera,
// MountingPointType::BuildingControlUnit,
MountingPointType::IndoorCamera,
//MountingPointType::OutdoorIPS, //TODO: Remove OutdoorIPS from Enum in EnterpriseArchitect
MountingPointType::IndoorIPS,
// MountingPointType::AnnouncementUnit,
MountingPointType::EffectGenerationControlUnit
// MountingPointType::BuildingNetworkSwitch
};
m_ui->lwMountingPointType->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
connect(m_ui->lwMountingPointType, &QListWidget::itemSelectionChanged,
this, [this]()
{
QVector<MountingPointType> types;
types << MountingPointType::Unknown;
for (const QListWidgetItem *lwi : m_ui->lwMountingPointType->findItems(QLatin1String(""), Qt::MatchContains))
{
MountingPointType mpt = static_cast<MountingPointType::inner_enum>(lwi->data(Qt::UserRole).toInt());
if (lwi->isSelected())
types << mpt;
m_mountedPointSortProxyModel->addToTypeFilter(mpt, lwi->isSelected());
m_unmountedPointSortProxyModel->addToTypeFilter(mpt, lwi->isSelected());
m_ui->mountingPointListView->treeView()->expandAll();
m_ui->unmountingPointListView->treeView()->expandAll();
}
});
for (const MountingPointType currentFilter : filters)
addMountingPointTypeFilter(currentFilter);
// connect is used to to enable Accept/Ok Buttons
connect(m_sourceModel, &ViewMountingPointListModel::dataChanged, this, &OverviewMountingPointListDialog::onDataChanged);
// mounted view
connect(m_ui->mountingPointListView->searchView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->mountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
connect(m_ui->mountingPointListView->treeView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->mountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
// unmounted view
connect(m_ui->unmountingPointListView->searchView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->unmountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
connect(m_ui->unmountingPointListView->treeView()->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, [this]()
{
m_ui->unmountingPointListView->slotSetHorizontalRange(0,0);
}, Qt::QueuedConnection);
connect(m_dataIfc.get(), &ForeignDataInterface::scheduleIdChanged,
this, &OverviewMountingPointListDialog::onScheduleIdChanged);
m_ui->mountingPointListView->treeView()->expandAll();
m_ui->unmountingPointListView->treeView()->expandAll();
// context menu expand / collapse treeview
m_ui->mountingPointListView->setContextMenuPolicyPerView(LtsDataView::LtsDataView::Page::TABLE, Qt::CustomContextMenu);
connect(m_ui->mountingPointListView->treeView(), &QTreeView::customContextMenuRequested,
this, &OverviewMountingPointListDialog::onMountedCustomContextMenu);
m_ui->unmountingPointListView->setContextMenuPolicyPerView(LtsDataView::LtsDataView::Page::TABLE, Qt::CustomContextMenu);
connect(m_ui->unmountingPointListView->treeView(), &QTreeView::customContextMenuRequested,
this, &OverviewMountingPointListDialog::onUnMountedCustomContextMenu);
// update title:
retranslate();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
/*!
* \brief OverviewMountingPointListDialog::retranslate
*/
void OverviewMountingPointListDialog::retranslate()
{
if (m_dtc)
{
MainSchedule ms = m_dtc->mainSchedule(m_scheduleId);
const QString msName = QString::fromStdString(ms.name());
translate(m_ui, tr("Completeness Check '%1'").arg(msName));
}
else
translate(m_ui, tr("Completeness Check"));
}
/*!
* \brief OverviewMountingPointListDialog::addMountingPointTypeFilter
* \param mpt
*/
void OverviewMountingPointListDialog::addMountingPointTypeFilter(MountingPointType mpt)
{
QListWidgetItem *lwi = new QListWidgetItem(m_ui->lwMountingPointType);
bool isInitChecked = true;
m_mountedPointSortProxyModel->addToTypeFilter(mpt, isInitChecked);
m_unmountedPointSortProxyModel->addToTypeFilter(mpt, isInitChecked);
lwi->setData(Qt::UserRole, mpt.underlying());
const QString text = toString(mpt);
lwi->setText(text);
lwi->setSelected(isInitChecked);
}
/*!
* \brief OverviewMountingPointListDialog::onDataChanged
* \param topLeft
* \param bottomRight
* \param roles
*/
void OverviewMountingPointListDialog::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
Q_UNUSED(topLeft);
Q_UNUSED(bottomRight);
Q_UNUSED(roles);
slotChangesMade();
m_ui->mountingPointListView->treeView()->expandAll();
m_ui->unmountingPointListView->treeView()->expandAll();
}
/*!
* \brief OverviewMountingPointListDialog::onPrint
* \param action
*/
void OverviewMountingPointListDialog::onPrint(QAction *action)
{
MainSchedule ms = m_dtc->mainSchedule(m_dataIfc->scheduleId());
QString header;
header += QStringLiteral("<p>");
header += tr("Instrumentation Plan: %1").arg(QString::fromStdString(ms.name()));
header += QStringLiteral("<br/>");
header += tr("Created: %1").arg(DTG::toStringMSec(ms.timeCreated()));
header += QStringLiteral("<br/>");
if (ms.timeStart().is_set())
header += tr("START: %1").arg(DTG::toStringMSec(ms.timeStart().get()));
else
header += tr("START: %1").arg(tr("[N/A]"));
header += QStringLiteral(" - ");
if (ms.timeEnd().is_set())
header += tr("END: %1").arg(DTG::toStringMSec(ms.timeEnd().get()));
else
header += tr("END: %1").arg(tr("[N/A]"));
header += QStringLiteral("<br/>");
QString filterTypes;
if(!getUsedFilterTypes().isEmpty())
{
QStringList filterList = getUsedFilterTypes();
header += QStringLiteral("<br/>");
filterTypes = tr("<b>Active filter:</b>");
filterTypes += QStringLiteral("<ul>");
for (int i=0; i<filterList.count(); i++ ) {
filterTypes += QStringLiteral("<li>%1</li>").arg(filterList.at(i));
}
filterTypes += QStringLiteral("</ul><br/>");
header += filterTypes;
}
if (action->text() == m_printMountingAction->text())
{
//
header += tr("The following items have to be mounted:");
header += QStringLiteral("<br/>");
header += QStringLiteral("</p>");
m_ui->mountingPointListView->expandAll();
if(itemsHaveNoChildren(m_ui->mountingPointListView->treeView()) == false)
LtsPrinting::printView(m_session, this, m_ui->mountingPointListView->treeView(), header );
else
{
QMessageBox::warning(this, tr("Completeness Check"), tr("There is No Entry to Print"), QMessageBox::Ok);
}
}
else if (action->text() == m_printUnmountingAction->text())
{
header += tr("The following items have to be unmounted:");
header += QStringLiteral("<br/>");
header += QStringLiteral("</p>");
m_ui->unmountingPointListView->expandAll();
if(itemsHaveNoChildren(m_ui->unmountingPointListView->treeView()) == false)
LtsPrinting::printView(m_session, this, m_ui->unmountingPointListView->treeView(), header );
else
{
QMessageBox::warning(this, tr("Completeness Check"), tr("There is No Entry to Print"), QMessageBox::Ok);
}
}
}
/*!
* \brief OverviewMountingPointListDialog::itemsHaveNoChildren
* \param view
* \return
*/
bool OverviewMountingPointListDialog::itemsHaveNoChildren(const QTreeView *view)
{
const QAbstractItemModel *itemModel = view->model();
int rowCount = itemModel->rowCount();
for (int row = 0; row < rowCount; ++row)
{
if (itemModel->hasChildren(itemModel->index(row, 0)))
return false;
}
return true;
}
void OverviewMountingPointListDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->mountingPointListView->setColumnsOrganiserEnabled(identifier(), true);
}
/*!
* \brief OverviewMountingPointListDialog::getUsedFilterTypes
* get the list of the selected filter
* \return QStringList
*/
QStringList OverviewMountingPointListDialog::getUsedFilterTypes()
{
QStringList filterList;
for (const QListWidgetItem *lwi : m_ui->lwMountingPointType->findItems(QLatin1String(""), Qt::MatchContains))
{
MountingPointType mpt = static_cast<MountingPointType::inner_enum>(lwi->data(Qt::UserRole).toInt());
if (lwi->isSelected())
filterList<<toString(mpt);
}
return filterList;
}
/*!
* \brief OverviewMountingPointListDialog::onScheduleIdChanged
* \param scheduleId
*/
void OverviewMountingPointListDialog::onScheduleIdChanged(int32_t scheduleId)
{
if (scheduleId == m_scheduleId)
return;
// scheduleId changed, data is maybe invalid -> close dialog:
this->close(); // Since Qt::WA_DeleteOnClose the dtor will be called :-)
}
void OverviewMountingPointListDialog::onMountedCustomContextMenu(QPoint pos)
{
QMenu *contextMenu = new QMenu(this);
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
{
QAction *action = new QAction(tr("Expand All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->mountingPointListView->expandAll();
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->mountingPointListView->collapseAll();
});
contextMenu->addAction(action);
}
contextMenu->addSeparator();
QModelIndex index = m_ui->mountingPointListView->treeView()->indexAt(pos);
bool hasChildren = m_ui->mountingPointListView->treeView()->model()->rowCount(index) > 0;
{
QAction *action = new QAction(tr("Expand"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
#if QT_VERSION < QT_VERSION_CHECK(5,13,0)
m_ui->dvConflicts->treeView()->expand(index);
#else
m_ui->mountingPointListView->treeView()->expandRecursively(index);
#endif
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
m_ui->mountingPointListView->treeView()->collapse(index);
});
contextMenu->addAction(action);
}
contextMenu->popup(m_ui->mountingPointListView->treeView()->mapToGlobal(pos));
}
void OverviewMountingPointListDialog::onUnMountedCustomContextMenu(QPoint pos)
{
QMenu *contextMenu = new QMenu(this);
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
{
QAction *action = new QAction(tr("Expand All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->unmountingPointListView->expandAll();
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse All"), this);
action->setEnabled(true);
connect(action, &QAction::triggered, this, [this]()
{
m_ui->unmountingPointListView->collapseAll();
});
contextMenu->addAction(action);
}
contextMenu->addSeparator();
QModelIndex index = m_ui->unmountingPointListView->treeView()->indexAt(pos);
bool hasChildren = m_ui->unmountingPointListView->treeView()->model()->rowCount(index) > 0;
{
QAction *action = new QAction(tr("Expand"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
#if QT_VERSION < QT_VERSION_CHECK(5,13,0)
m_ui->dvConflicts->treeView()->expand(index);
#else
m_ui->unmountingPointListView->treeView()->expandRecursively(index);
#endif
});
contextMenu->addAction(action);
}
{
QAction *action = new QAction(tr("Collapse"), this);
action->setEnabled(hasChildren);
connect(action, &QAction::triggered, this, [this, index]()
{
m_ui->unmountingPointListView->treeView()->collapse(index);
});
contextMenu->addAction(action);
}
contextMenu->popup(m_ui->unmountingPointListView->treeView()->mapToGlobal(pos));
}
/*!
* \brief OverviewMountingPointListDialog::apply
* \return
*/
bool OverviewMountingPointListDialog::apply()
{
return true;
}
@@ -0,0 +1,99 @@
/**
* @RDE_HEADER@
* tbc
* $Id$
* $HeadURL$
* $Author$
* Created by
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <InfrastructureManagement/logger.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <LtsDataView/check_state_proxy_model.h>
#include <InfrastructureManagement/Gui/ResourceManagement/MountingPointMapSelection/ism_dds_selector.h>
#include <InfrastructureManagement/Gui/ResourceManagement/MountingPointMapSelection/ism_selector.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/ism_ftc.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <qtreeview.h>
#include "ism_overview_mounting_point_list_model.h"
namespace Ui {
class OverViewMountingPointListDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
class ViewMountingPointListModel;
class ViewMountingPointListSortModel;
class OverviewMountingPointListDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public: explicit OverviewMountingPointListDialog(const QString &menuGroup, QWidget *parent = nullptr);
~OverviewMountingPointListDialog();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<Interface::Ftc> &ftc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
int32_t scheduleId);
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) ;
private slots:
void onPrint(QAction *action);
void onScheduleIdChanged(int32_t scheduleId);
void onMountedCustomContextMenu(QPoint pos);
void onUnMountedCustomContextMenu(QPoint pos);
private: // methods
void retranslate() override;
void addMountingPointTypeFilter(MountingPointType mpt);
void addFloorFilter(int floor);
bool apply() override final;
bool isIncludedId(int32_t mountingPointId) const;
bool itemsHaveNoChildren(const QTreeView *view);
void tableColumnOrganiserSetting() override;
QStringList getUsedFilterTypes();
private:
QString m_menuGroup;
Ui::OverViewMountingPointListDialog *m_ui;
int32_t m_scheduleId;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<ForeignDataInterface> m_dataIfc;
ViewMountingPointListModel *m_sourceModel{nullptr};
ViewMountingPointListSortModel *m_mountedPointSortProxyModel{nullptr};
ViewMountingPointListSortModel *m_unmountedPointSortProxyModel{nullptr};
LtsSession::LtsSession *m_session{nullptr};
LOGGER_T m_logger;
QMenu *m_actionMenu;
QAction *m_printMountingAction;
QAction *m_printUnmountingAction;
}; // class OverViewMountingPointListDialog
} // namespace InfrastructureManagement
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OverViewMountingPointListDialog</class>
<widget class="QWidget" name="OverViewMountingPointListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>868</width>
<height>490</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="grpTypeFilters">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>221</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Type filter</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QListWidget" name="lwMountingPointType">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="umntLbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>To Unmount</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="LtsDataView::LtsDataView" name="mountingPointListView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
<property name="toolButtonsVisible" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mntLbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>To Mount</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="LtsDataView::LtsDataView" name="unmountingPointListView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
<property name="toolButtonsVisible" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>566</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,542 @@
/**
* @RDE_HEADER@
* tbc
* $Id$
* $HeadURL$
* $Author$
* Created by
*/
#include "ism_overview_mounting_point_list_model.h"
#include <InfrastructureManagement/ism_translation.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <QDebug>
#include <QTimer>
// #define BENCHMARK
#ifdef BENCHMARK
# include <QElapsedTimer>
# include <QDebug>
#endif
namespace InfrastructureManagement
{
static const int maxIntValue = std::numeric_limits<int>::max();
ViewMountingPointListModel::ViewMountingPointListModel(QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), { tr("Name"), tr("Type"), tr("Aim State") })
, m_visRoot(new NGLTreeItem(tr("Mounting Points")))
, m_dtc(nullptr)
, m_logger(getLogger("ViewMountingPointListModel"))
, m_dataChangedTimer(new QTimer(this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_dataChangedTimer->setSingleShot(true);
m_dataChangedTimer->setInterval(100);
connect(m_dataChangedTimer, &QTimer::timeout, this, &ViewMountingPointListModel::emitDataChanged);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
QVariant ViewMountingPointListModel::data(const QModelIndex &index, int role) const
{
if (!(index.isValid() && (role == Qt::DisplayRole || role == Qt::UserRole || role == (Qt::UserRole + 1) || role == Qt::CheckStateRole)))
return QVariant();
NGLTreeItem *item = privateData(index);
if (role == Qt::DisplayRole)
{
if (index.column() != NAME && !item->data().canConvert<OverviewSimpleMountingPointData>())
return QVariant();
const OverviewSimpleMountingPointData itemData = item->data().value<OverviewSimpleMountingPointData>();
switch (index.column())
{
case NAME:
if (item->data().canConvert<OverviewSimpleMountingPointData>())
return item->data().value<OverviewSimpleMountingPointData>().name;
if (item->data().canConvert<OverviewSimpleStructureElementData>())
return item->data().value<OverviewSimpleStructureElementData>().name;
if (item->data().canConvert<OverviewSimpleBuildingGroupData>())
return item->data().value<OverviewSimpleBuildingGroupData>().name;
return tr("all");
case STATE:
if (itemData.seType == StructureElementType::MountingPoint)
return toString(itemData.aimState);
break;
case TYPE:
if (itemData.seType == StructureElementType::MountingPoint)
{
const MountingPointType mpType = (itemData.mpType == MountingPointType_def::OutdoorIPS) ? MountingPointType_def::IndoorIPS : itemData.mpType;
return toString(mpType);
}
break;
}
}
// else if (role == Qt::CheckStateRole)
// {
// if (index.column() != NAME)
// return QVariant();
// bool isLeaf = item->data().canConvert<OverviewSimpleMountingPointData>();
// if (isLeaf)
// {
// auto cs = item->data().value<OverviewSimpleMountingPointData>().aimState.underlying();
// switch (cs)
// {
// case MountingPointState::Equipped:
// return Qt::Checked;
// case MountingPointState::Idle:
// return Qt::PartiallyChecked;
// case MountingPointState::Empty:
// return Qt::Unchecked;
// }
// }
// }
else if (role == Qt::UserRole && item->data().canConvert<OverviewSimpleMountingPointData>())
return item->data().value<OverviewSimpleMountingPointData>().id;
else if (role == (Qt::UserRole + 1) && item->data().canConvert<OverviewSimpleMountingPointData>())
return item->data().value<OverviewSimpleMountingPointData>().aimState.underlying();
return QVariant();
}
bool ViewMountingPointListModel::initModel(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
int32_t requestedScheduleId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, scheduleId=" << requestedScheduleId;
if (m_dtc == dtc)
return true;
if (!(dtc->enableMainStructureElement() &&
dtc->enableMountingPointAsset()))
{
ERROR_LOG(m_logger) << "Could not enable Datatopics";
return false;
}
m_dtc = dtc;
m_dataInterface = dataInterface;
m_scheduleId = requestedScheduleId;
// !!! Maybe this is critical !!!
// !!! Maybe this is critical !!!
// !!! Maybe this is critical !!!
// m_dataInterface::setScheduleId will update the MountingPoints (aimState) according schedule!!!
// // m_dataInterface->setScheduleId(m_scheduleId);
// connect(m_dataInterface.get(), &ForeignDataInterface::scheduleIdChanged,
// this, &MountingPointListDialogModel::onScheduleIdChanged);
connect(m_dataInterface.get(), &ForeignDataInterface::mountingPointChanged,
this, &ViewMountingPointListModel::onMountingPointChanged);
DEBUG_LOG(m_logger) << "initModel successful";
initData();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
QModelIndex ViewMountingPointListModel::getIndexOfVisableRootItem() const
{
return indexFromItem(m_visRoot);
}
/**
* @brief setBuildingGroup: create fake structure element of building group
* @param groupId
* @return
*/
inline StructureElement setBuildingGroup(int groupId)
{
StructureElement se;
InfrastructureManagement::BuildingGroup_def::type buildingGroup = static_cast<InfrastructureManagement::BuildingGroup_def::type>(groupId);
if(buildingGroup == 0)
{
buildingGroup = InfrastructureManagement::BuildingGroup_def::UnknownGroup;
}
se.id() = maxIntValue - static_cast<int>(buildingGroup);
se.name() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.displayName() = InfrastructureManagement::toString(buildingGroup).toStdString();
se.structureElementTypeId() = InfrastructureManagement::StructureElementType::Section;
return se;
}
/**
* @brief getFakeBuildingGroupId: idi will only be use for treeview
* @param seId
* @return
*/
inline int getFakeBuildingGroupId(int seId)
{
InfrastructureManagement::BuildingGroup_def::type buildingGroup = static_cast<InfrastructureManagement::BuildingGroup_def::type>(seId);
if(buildingGroup == 0)
{
buildingGroup = InfrastructureManagement::BuildingGroup_def::UnknownGroup;
}
return (maxIntValue - static_cast<int>(buildingGroup));
}
void ViewMountingPointListModel::initData()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_scheduleId=" << m_scheduleId;
// #define BENCHMARK
#ifdef BENCHMARK
QElapsedTimer elapsedTimer1;
elapsedTimer1.start();
#endif // BENCHMARK
const int32_t loadedScheduleId = m_dataInterface->scheduleId();
m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId = (m_scheduleId == loadedScheduleId);
// scenario: load plan 1, open checkDialog (OverviewMountingPointListDialog)
// (m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId==true)
// load another plan.... --> dialog should be closed
NGLTreeModel::resetModel();
m_rootItem->appendChild(m_visRoot);
const QMap<int, InfrastructureManagement::MainStructureElement> &mainStructEles = m_dtc->mainStructureElements();
// how do we get the aimState?
// via m_dataInterface->mountingPoint() (loaded schedule)
// or via schedule?
QHash<int32_t, MountingPointPlan> mountingPointPlanCont;
if (!m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId)
{
// prepare MountingPointPlan of schedule to speed up access:
const InfrastructureManagement::MainSchedule &currentSchedule = m_dtc->mainSchedule(m_scheduleId);
for (const MountingPointPlan &mpp : qAsConst(currentSchedule.elements()))
mountingPointPlanCont.insert(mpp.structureElementId(), mpp);
}
// QSet<int> includedMountingPointIds;
// includedMountingPointIds.reserve(currentSchedule.elements().size());
// for (const InfrastructureManagement::MountingPointPlan &currentPlan : currentSchedule.elements())
// includedMountingPointIds.insert(currentPlan.structureElementId());
// qCritical() << " includedMountingPointIds " << includedMountingPointIds.size();
// cfroebel 2018-11-07:
// The algorithm of building the tree structure assumes that
// the StructureElements are hierarchically ordered, i.e. that the
// MountingPoint comes after its Room, Level and Building.
// Is that guaranteed by the service?
for (const MainStructureElement &mse : mainStructEles)
{
// only consider buildings
if (mse.structureElementTypeId() != StructureElementType::Building)
continue;
// 1- if a buildingGroup modelIndex for current building dosen't exist
// a new one will be first added and used as parentIndex for the blg_Index.
QModelIndex groupIndex;
const StructureElement bse= setBuildingGroup(mse.groupId());
if (m_availableBuildingGroups.contains(bse.id()) == false)
{
OverviewSimpleBuildingGroupData buildingGroup;
buildingGroup.name = QString::fromStdString(bse.displayName());
buildingGroup.id = bse.id();
NGLTreeItem *groupItem = new NGLTreeItem(QVariant::fromValue(buildingGroup));
QModelIndex groupParentIndex;
groupParentIndex = indexFromItem(m_visRoot);
insertRow(rowCount(groupParentIndex), groupParentIndex, groupItem);
groupIndex = index(groupItem->row(), 0, groupParentIndex);
m_mountingPointIndexes.insert(bse.id(), groupIndex);
m_availableBuildingGroups.insert(bse.id());
}
else
{
groupIndex = m_mountingPointIndexes.value(bse.id(), indexFromItem(m_visRoot));
}
for (const StructureElement &currentElement : mse.elements())
{
NGLTreeItem *item = nullptr;
if (currentElement.structureElementTypeId() == StructureElementType::MountingPoint)
{
MountingPoint mountingPoint = m_dataInterface->mountingPoint(currentElement.id());
if (!mountingPoint.isValid())
continue;
if (mountingPoint.type() == MountingPointType::Unknown ||
mountingPoint.type() == MountingPointType::BuildingControlUnit ||
mountingPoint.type() == MountingPointType::VirtualIPS ||
mountingPoint.type() == MountingPointType::MeteoDataUnit)
continue;
OverviewSimpleMountingPointData mpData;
mpData.seType = currentElement.structureElementTypeId();
mpData.id = mountingPoint.id();
mpData.name = mountingPoint.name();
mpData.mpType = mountingPoint.type();
mpData.hasAsset = mountingPoint.hasAssociatedAsset();
if (m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId)
{
mpData.aimState = mountingPoint.aimState(); // mountingPoint.aimState was set according the loaded schedule!!!
} else {
// neu:
const int32_t mpId_StructEleId = mountingPoint.id();
if (mountingPointPlanCont.contains(mpId_StructEleId))
{
const MountingPointPlan &mpp = mountingPointPlanCont.value(mpId_StructEleId);
mpData.aimState = mpp.mountingPointState();
} else {
mpData.aimState = MountingPointState_def::Idle;
}
}
item = new NGLTreeItem(QVariant::fromValue(mpData));
}
else
{
OverviewSimpleStructureElementData ssed;
if (currentElement.structureElementTypeId() == StructureElementType::Floor)
ssed.floor = QString::fromStdString(currentElement.name()).split(QLatin1Literal("_")).value(1, QLatin1String("-10")).toInt();
else
ssed.floor = -20;
ssed.name = currentElement.displayName().empty() ? QString::fromStdString(currentElement.name()) : QString::fromStdString(currentElement.displayName());
item = new NGLTreeItem(QVariant::fromValue(ssed));
}
const auto &path = currentElement.path();
QModelIndex parentIndex;
if (path.size() > 1)
{
parentIndex = m_mountingPointIndexes.value(path.at(path.size() - 2), indexFromItem(m_visRoot)); //default sollte nie erreicht werden
if (!parentIndex.isValid())
{
ERROR_LOG(m_logger) << "Did not find parent for structure element with id " << currentElement.id() << " mseid: " << mse.id();
for (const StructureElement &se : mse.elements())
ERROR_LOG(m_logger) << " se: " << se.id() << ", " << se.displayName() << ", " << se.name();
}
}
else
{
if (groupIndex.isValid())
{
parentIndex = groupIndex;
}
else
{
parentIndex = indexFromItem(m_visRoot);
}
}
insertRow(rowCount(parentIndex), parentIndex, item);
m_mountingPointIndexes.insert(currentElement.id(), index(item->row(), 0, parentIndex));
}
}
m_availableFloors << -10;
#ifdef BENCHMARK
const InfrastructureManagement::MainSchedule &currentSchedule = m_dtc->mainSchedule(m_scheduleId);
qCritical() << " ViewMountingPointListModel::initData-BENCHMARK: m_scheduleId=" << currentSchedule.id();
qCritical() << " ViewMountingPointListModel::initData-BENCHMARK: m_scheduleId=" << currentSchedule.name().c_str();
qCritical() << " ViewMountingPointListModel::initData-BENCHMARK: m_scheduleId=" << m_scheduleId << " took " << elapsedTimer1.elapsed() << " [ms]";
#endif // BENCHMARK
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool ViewMountingPointListModel::mountingPointHasAssetMounted(int32_t mountingPointId, const QMap<qint32, MountingPointAsset> &mountingPointAssetMap)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
for (const MountingPointAsset &mpa : mountingPointAssetMap)
{
if (mpa.structureElementId() == mountingPointId)
return true;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return false;
}
Qt::ItemFlags ViewMountingPointListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags fl = NGLTreeModel::flags(index);
if (!index.isValid())
return fl;
NGLTreeItem *item = privateData(index);
bool isLeaf = item->data().canConvert<OverviewSimpleMountingPointData>();
if (isLeaf && index.column() == Columns::NAME)
return fl | Qt::ItemIsUserCheckable | Qt::ItemIsUserTristate;
return fl;
}
void ViewMountingPointListModel::onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType)
{
if (modType != DataModification::eModified)
return;
QModelIndex index = m_mountingPointIndexes.value(mountingPoint.id());
if (!index.isValid())
return;
NGLTreeItem *item = privateData(index);
if (!(item && item->data().canConvert<OverviewSimpleMountingPointData>()))
return;
OverviewSimpleMountingPointData mpData = item->data().value<OverviewSimpleMountingPointData>();
mpData.name = mountingPoint.name();
if (m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId)
mpData.aimState = mountingPoint.aimState();
item->setData(QVariant::fromValue(mpData));
m_dataChangedTimer->start();
}
void ViewMountingPointListModel::emitDataChanged()
{
QModelIndex vri = getIndexOfVisableRootItem();
emit dataChanged(vri, index(rowCount(vri) -1, Columns::STATE, vri), {Qt::DisplayRole, Qt::CheckStateRole});
}
void ViewMountingPointListSortModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<ViewMountingPointListModel*>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
}
void ViewMountingPointListSortModel::setTypeFilter(const QSet<MountingPointType> &visibleTypes)
{
if (m_visibleTypes == visibleTypes)
return;
m_visibleTypes = visibleTypes;
invalidateFilter();
}
void ViewMountingPointListSortModel::addToTypeFilter(MountingPointType mpt, bool bAdd)
{
auto visibleTypes = m_visibleTypes;
if (bAdd)
{
// TODO: outdoor / indoor ips should be unified
if(mpt == MountingPointType::IndoorIPS)
{
visibleTypes.insert(MountingPointType::OutdoorIPS);
}
visibleTypes.insert(mpt);
}
else
{
if(mpt == MountingPointType::IndoorIPS)
{
visibleTypes.remove(MountingPointType::OutdoorIPS);
}
visibleTypes.remove(mpt);
}
setTypeFilter(visibleTypes);
}
bool ViewMountingPointListSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel)
return true;
bool isRootItem = !source_parent.isValid();
if (isRootItem)
{
Q_ASSERT(source_row == 0);
return true; // root item shall always be visible
}
const QModelIndex childIdx = m_sourceModel->index(source_row, 0, source_parent);
const NGLTreeItem *itemChild = m_sourceModel->privateData(childIdx);
Q_ASSERT(itemChild);
bool isLeaf = itemChild->data().canConvert<OverviewSimpleMountingPointData>();
if (isLeaf)
{
const OverviewSimpleMountingPointData data = itemChild->data().value<OverviewSimpleMountingPointData>();
Q_ASSERT(data.isMountingPoint());
bool visible = false;
if (data.aimState == m_mnpState && m_mnpState == MountingPointState::Equipped)
{
if (!data.hasAsset)
visible = true;
}
else if (data.aimState == m_mnpState && m_mnpState == MountingPointState::Empty)
{
if (data.hasAsset)
visible = true;
}
return m_visibleTypes.contains(data.mpType) && visible;//(data.aimState == m_mnpState);
}
else
{
if (!itemChild->data().canConvert<OverviewSimpleStructureElementData>() &&
!itemChild->data().canConvert<OverviewSimpleBuildingGroupData>())
return true;
}
// Qt5.11: setRecursiveFilteringEnabled(true);
for (int i = 0; i < itemChild->childCount(); ++i)
{
if (filterAcceptsRow(i, childIdx))
return true;
}
return false;
}
bool ViewMountingPointListSortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel || source_left.column() != source_right.column())
return BaseClass::lessThan(source_left, source_right);
const NGLTreeItem *itemLeft = m_sourceModel->privateData(source_left);
const NGLTreeItem *itemRight = m_sourceModel->privateData(source_right);
if (!itemLeft || !itemRight)
return BaseClass::lessThan(source_left, source_right);
if (itemLeft->data().canConvert<OverviewSimpleBuildingGroupData>())
{
const OverviewSimpleBuildingGroupData left = itemLeft->data().value<OverviewSimpleBuildingGroupData>();
const OverviewSimpleBuildingGroupData right = itemRight->data().value<OverviewSimpleBuildingGroupData>();
if (left.name != right.name)
return left.name < right.name;
}
else if (itemLeft->data().canConvert<OverviewSimpleStructureElementData>())
{
const OverviewSimpleStructureElementData left = itemLeft->data().value<OverviewSimpleStructureElementData>();
const OverviewSimpleStructureElementData right = itemRight->data().value<OverviewSimpleStructureElementData>();
if (left.name != right.name)
return left.name < right.name;
}
const OverviewSimpleMountingPointData left = itemLeft->data().value<OverviewSimpleMountingPointData>();
const OverviewSimpleMountingPointData right = itemRight->data().value<OverviewSimpleMountingPointData>();
if (left.name != right.name)
return left.name < right.name;
return left.id < right.id;
}
}// namespace InfrastructureManagement
@@ -0,0 +1,184 @@
/**
* @RDE_HEADER@
* tbc
* $Id$
* $HeadURL$
* $Author$
* Created by
*/
#pragma once
#include <InfrastructureManagement/ism_dtc.h>
#include <InfrastructureManagement/logger.h>
#include <QSet>
#include <nglwidgets/ngltreemodel.h>
#include <nglwidgets/ngltreeitem.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsDataView/check_state_proxy_model.h>
namespace LtsSession
{
class LtsSession;
}
namespace InfrastructureManagement
{
struct OverviewSimpleMountingPointData
{
QString name;
int32_t id = 0; // StructureElementId
StructureElementType seType;
MountingPointType mpType;
MountingPointState aimState;
bool hasAsset = false;
bool isMountingPoint() const { return seType == StructureElementType::MountingPoint; }
};
struct OverviewSimpleBuildingGroupData
{
QString name;
int id;
};
struct OverviewSimpleStructureElementData
{
QString name;
int floor;
};
class ViewMountingPointListModel final : public NGLTreeModel
{
Q_OBJECT
public:
public:
enum Columns
{
NAME,
TYPE,
STATE
};
explicit ViewMountingPointListModel(QObject *parent = nullptr);
/**
* Handles the representation of data.
* In case of CheckStateRole only leafs will be handled.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] role role to which the data relates
*
*/
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignDataInterface> &dataInterface,
int32_t requestedScheduleId);
QModelIndex getIndexOfVisableRootItem() const;
/**
* Sets only the leafs of the tree view to Qt::ItemIsUserCheckable.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
*
*/
Qt::ItemFlags flags(const QModelIndex &index) const override final;
/**
* Sets the check state data according to their check box in the internal model.
* CheckState data can be set for leafs only.
* Nodes are handled in the upstream CheckStateProxyModel class.
* @param[in] index item index to be handled
* @param[in] value value to be set
* @param[in] role role to which the data relates (here especially Qt::CheckStateRole)
*
*/
//bool setData(const QModelIndex &index, const QVariant &value, int role) override;
bool mountingPointHasAssetMounted(int32_t mountingPointId, const QMap<qint32, MountingPointAsset> &mountingPointAssetMap);
static const int maxIntValue = std::numeric_limits<int>::max();
public Q_SLOTS:
void onMountingPointChanged(const MountingPoint &mountingPoint, DataModification modType);
private Q_SLOTS:
// void onScheduleIdChanged(int32_t scheduleId);
void emitDataChanged();
private:
void initData();
void initMountedData();
void initUnmountedData();
friend class ViewMountingPointListSortModel;
QSet<int> m_availableBuildingGroups;
NGLTreeItem *m_visRoot;
NGLTreeItem *m_mountedParent;
NGLTreeItem *m_unmountedParent;
std::shared_ptr<Interface::Dtc> m_dtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_dataInterface;
int32_t m_scheduleId{-1};
bool m_bIsRequestedScheduleId_EqualTo_LoadedScheduleId{false};
QHash<int, QModelIndex> m_mountingPointIndexes;
QHash<int, QModelIndex> m_mountedPointIndexes;
QHash<int, QModelIndex> m_unmountedPointIndexes;
QHash<int32_t, bool> m_mountingPointHasAssetMounted;
QSet<int> m_availableFloors;
LOGGER_T m_logger;
QTimer *m_dataChangedTimer{nullptr};
}; // class OverViewDialogMountingPointListModel
//class ViewMountingPointListCheckStateModel final : public LtsDataView::CheckStateProxyModel
//{
// Q_OBJECT
//public:
// bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
//};
class ViewMountingPointListSortModel final : public LtsWidgets::LtsColumnFilterProxyModel
{
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel ) override;
void setTypeFilter(const QSet<MountingPointType> &visibleTypes);
void addToTypeFilter(MountingPointType mpt, bool bAdd);
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
using LtsWidgets::LtsColumnFilterProxyModel::invalidateFilter;
void setVisibleState(MountingPointState visibleState){m_mnpState = visibleState;}
private:
ViewMountingPointListModel *m_sourceModel = nullptr;
QSet<MountingPointType> m_visibleTypes;
QSet<int> m_visibleFloors;
MountingPointState m_mnpState;
};
} // namespace InfrastructureManagement
Q_DECLARE_METATYPE(InfrastructureManagement::OverviewSimpleMountingPointData)
Q_DECLARE_METATYPE(InfrastructureManagement::OverviewSimpleStructureElementData)
Q_DECLARE_METATYPE(InfrastructureManagement::OverviewSimpleBuildingGroupData)
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff. Show more