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

+17
View File
@@ -0,0 +1,17 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Jörg Turla, SPDG, 2017-06-29
#
ADD_SUBDIRECTORY(Gui)
#
# Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PlanOverlaysGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/plan_overlays_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
+54
View File
@@ -0,0 +1,54 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Jörg Turla, SPDG, 2017-06-29
#
ADD_SUBDIRECTORY(Test)
SET (PlanOverlaysGuiPlugin_SRCS
flm_reply_handler.cpp
flm_reply_handler.h
plan_overlay_dialog.cpp
plan_overlay_dialog.h
plan_overlay_model.cpp
plan_overlay_model.h
plan_overlay_view.cpp
plan_overlay_view.h
plan_overlays_gui_plugin.cpp
plan_overlays_gui_plugin.h
TopicEditor/topic_editor.h
TopicEditor/topic_editor.cpp
)
SET(EXE_UICS
TopicEditor/topic_editor.ui
)
QT5_WRAP_UI(EXE_SRCS ${EXE_UICS})
SOURCE_GROUP(PlanOverlaysPlugin FILES ${PlanOverlaysGuiPlugin_SRCS})
NGL_ADD_LIBRARY(WS PlanOverlaysGuiPlugin MODULE ${PlanOverlaysGuiPlugin_SRCS} ${EXE_SRCS})
NGL_TARGET_LINK_LIBRARIES( PlanOverlaysGuiPlugin
LtsSession
LtsSessionData
PlanOverlaysGuiPluginInterface
situationMap
situationMapObjects
GuiPluginInterface
FlmDataPluginInterface
OpmDataPluginInterface
ExmDataPluginInterface
LtsFileDialog
LtsUtilsGuiDds
LtsWidgets
NGLLogger
Qt5::Widgets
TopicEditorBase
LtsScriptTimeline
)
NGL_INSTALL_TARGET(PlanOverlaysGuiPlugin)
+68
View File
@@ -0,0 +1,68 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# PlanOverlays Test Application
SET(EXE_SRCS
main.cpp
../plan_overlay_dialog.cpp
../plan_overlay_dialog.h
../plan_overlay_view.cpp
../plan_overlay_view.h
../plan_overlay_model.cpp
../plan_overlay_model.h
log4cxx_planOverlaysTest.props
)
SET(EXE_HDRS
)
SET(EXE_UICS
)
NGL_WRAP_UI(EXE_SRCS ${EXE_UICS})
SET(LOG4CXX_PROPS_FILE log4cxx_planOverlaysTest.props)
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION planOverlaysTest ${EXE_SRCS} ${EXE_HDRS} ${EXE_UICS})
NGL_TARGET_LINK_LIBRARIES(
planOverlaysTest
NGLLogger
LtsSession
LtsSessionData
LtsWidgets
nglapplication
LtsPluginManager
GuiPluginInterface
FlmDataPluginInterface
OpmDataPluginInterface
ExmDataPluginInterface
LtsFileDialog
# ArcGIS::ArcGIS
LtsPluginLoader
LtsUtilsGuiDds
Qt5::Gui
)
IF(TARGET planOverlaysTest)
if(BUILD_PlanEditorCopyConfig)
ADD_CUSTOM_COMMAND( TARGET planOverlaysTest POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${LOG4CXX_PROPS_FILE} $<TARGET_FILE_DIR:planOverlaysTest>/${LOG4CXX_PROPS_FILE}
)
ENDIF()
ENDIF()
IF(MSVC)
# Configure the template file
SET(VS_USER_FILE planOverlaysTest.vcxproj.user)
configure_file( PlanOverlaysTest.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/${VS_USER_FILE} @ONLY)
ENDIF(MSVC)
NGL_INSTALL_TARGET_DEVEL(planOverlaysTest)
NGL_INSTALL(FILES WS ${CMAKE_CURRENT_SOURCE_DIR}/${LOG4CXX_PROPS_FILE} DESTINATION "bin" COMPONENT Devel)
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|Win32'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|Win32'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'">
<LocalDebuggerEnvironment>PATH=C:\ExtFW\bin;%PATH%</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
@@ -0,0 +1,138 @@
log4j.reset=true
log4j.rootLogger=WARN, file
# SituationMap
###########################################################
log4j.logger.PlanEditor=DEBUG
log4j.logger.PlanEditor.SymbolAdjustDialog=TRACE
log4j.logger.SituationMap.SitMapTestApp=ERROR
log4j.logger.SituationMap.SitMap=ERROR
log4j.logger.SituationMap.MapImpl=ERROR
log4j.logger.SituationMap.MapSettings=WARN
log4j.logger.SituationMap.MapInitializer=WARN
log4j.logger.SituationMap.LayerFactoryImpl=ERROR
log4j.logger.SituationMap.CoordTranslationFunctorImpl=ERROR
log4j.logger.SituationMap.GridImpl=ERROR
log4j.logger.SituationMap.ObjectFactory=ERROR
log4j.logger.SituationMap.IdGenerator=ERROR
log4j.logger.SituationMap.ObjectContainer=ERROR
log4j.logger.SituationMap.ObjectContainerCTC=ERROR
log4j.logger.SituationMap.SymbolDictionary=ERROR
log4j.logger.SituationMap.SymbolDictionaryImpl=ERROR
log4j.logger.SituationMap.SymbolDictionaryExtendedImpl=ERROR
log4j.logger.SituationMap.Sidc2525Delta=ERROR
log4j.logger.SituationMap.AbstractMapObjectImpl=ERROR
log4j.logger.SituationMap.AbstractEffectSimulationImpl=ERROR
log4j.logger.SituationMap.OriginTranslated=ERROR
log4j.logger.SituationMap.PositionsTranslated=ERROR
log4j.logger.SituationMap.AbstractMultiPointMapObjectImpl=ERROR
log4j.logger.SituationMap.AbstractSinglePointMapObjectImpl=ERROR
log4j.logger.SituationMap.BasicPathObjectImpl=ERROR
log4j.logger.SituationMap.PolygonImpl=ERROR
log4j.logger.SituationMap.PolylineImpl=ERROR
log4j.logger.SituationMap.TextImpl=ERROR
log4j.logger.SituationMap.AreaFireImpl=ERROR
log4j.logger.SituationMap.BiologicalAgentImpl=ERROR
log4j.logger.SituationMap.BuildingOutlineImpl=ERROR
log4j.logger.SituationMap.ChemicalAgentImpl=ERROR
log4j.logger.SituationMap.DangerAreaImpl=ERROR
log4j.logger.SituationMap.FunctionalAreaImpl=ERROR
log4j.logger.SituationMap.HitLineImpl=ERROR
log4j.logger.SituationMap.MineImpl=ERROR
log4j.logger.SituationMap.ParticipantImpl=ERROR
log4j.logger.SituationMap.SingleFireImpl=ERROR
log4j.logger.SituationMap.IndicationContainer=ERROR
log4j.logger.SituationMap.AbstractGraphicalObject=ERROR
log4j.logger.SituationMap.GraphicalObjectEllipse=ERROR
log4j.logger.SituationMap.GraphicalObjectPath=ERROR
log4j.logger.SituationMap.GraphicalObjectMultiPath=ERROR
log4j.logger.SituationMap.GraphicalObjectPictureMarker=ERROR
log4j.logger.SituationMap.GraphicalObjectRange=ERROR
log4j.logger.SituationMap.GraphicalObjectText=ERROR
log4j.logger.SituationMap.TacticalAppearance=ERROR
log4j.logger.SituationMap.MessageBase=ERROR
log4j.logger.SituationMap.EventDispatcher=ERROR
log4j.logger.SituationMap.RubberbandFactory=DEBUG
# Appnd_File
###########################################################
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=9
log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_SituationMapTestApp.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
# Appnd_Console
###########################################################
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d %-5p %c{1} |#| %m (%-.30F:%L) %n
#log4j.appender.stdout.layout.ConversionPattern= %d %-5p %-30c |#| %m (%-.30F:%L) %n
# Appnd_Syslog
###########################################################
log4j.appender.syslog=org.apache.log4j.SyslogAppender
log4j.appender.syslog.Threshold=ERROR
log4j.appender.syslog.SysLogHost=localhost
log4j.appender.syslog.Facility=LOCAL7
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
log4j.appender.syslog.LevelRangeFilter.LevelMin=FATAL
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
###########################################################
###########################################################
###########################################################
# 1) Available Levels in LOG4CXX Version 0.10.0:
# TRACE,
# DEBUG,
# INFO,
# WARN,
# ERROR
# FATAL
#
# d = date/time
# p = priority (Level)
# c = category/channel
# m = message
# F = file
# L = line
# n = platform dependent line separator character or characters.
# ....
#
# Examples for console:
# a)
# %d %p %c #%m# (%.50F:%L)%n
# date/time
# priority
# category/channel
# #message#
# (Maximal 50Character des Filename von rechts:Line)
# line separator
#
# b)
# %d (%.15F:%L) %-5p %c |#| %m%n
# date/time
# (Maximal 15Character des Filename von rechts:Line)
# priority, Right pad with spaces if the priority name is less than 5 characters long.
# category/channel
# message
# line separator
#
+182
View File
@@ -0,0 +1,182 @@
/**
* @RDE_HEADER@
* main
* $Id$
* $HeadURL$
* $Author$
*/
#include <nglapplication/nglapplication.h>
#include <NGLLogger/INGLLogger.h>
#include "../plan_overlay_dialog.h"
#include "../plan_overlay_model.h"
#include "../plan_overlay_view.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsPluginManager/lts_plugin_loader.h>
#include <PluginInterfaces/style_plugin_interface.h>
#include <PluginInterfaces/project_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <QtCore/QDir>
#include <QtCore/QPointer>
#include <QtCore/QStandardPaths>
#include <QtGui/QSurface>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QDialog>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QLabel>
#include <iostream>
#include <memory>
// -------------------------------------------------------------------
int main (int argc, char* argv[])
{
// ESRI :
#ifdef Q_OS_WIN
// Force usage of OpenGL ES through ANGLE on Windows
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
// : ESRI
NGLApplication app ( argc, argv );
app.createLogger("planOverlayTest", "log4cxx_planOverlayTest.props");
TRACE_LOG(app.baseLogger()) << LOGFUNCTION << " START";
STARTUP_LOG(app.baseLogger());
app.setOrganizationName(QLatin1String("RME"));
app.setApplicationName(QLatin1String("Plan Overlay Test Application"));
LtsPluginManager::LtsPluginLoader *pluginLoader = LtsPluginManager::LtsPluginLoader::getInstance();
pluginLoader->loadPlugins( LtsPluginManager::PluginType::STYLE , nullptr, QStringList() << QStringLiteral("rme.light") );
pluginLoader->loadPlugins( LtsPluginManager::PluginType::PROJECT, nullptr, QStringList() << QStringLiteral("legatus") );
// .. to keep some compatibility to old resource structure TODO: rm !
QDir::setSearchPaths( QLatin1String( "icon" ), QStringList( QLatin1String( ":/style/icons/" ) ) );
QDir::setSearchPaths( QLatin1String( "icon" ), QStringList( QLatin1String( ":/style/" ) ) ); // FIXME: does qt check for recursion ??
#ifdef BUILD_STATIC_LIBRARIES
// For static linking under windows:
Q_INIT_RESOURCE(lts_resources);
#endif
#define USE_QDIALOG
//#define USE_LTSFRAMELESS
//#define CHECK_ERROR
PlanOverlaysPlugin::PlanOverlayModel * planOverlayModel = new PlanOverlaysPlugin::PlanOverlayModel();
#ifdef USE_QDIALOG
PlanOverlaysPlugin::PlanOverlayDialog<QDialog> * dialog = new PlanOverlaysPlugin::PlanOverlayDialog<QDialog>( nullptr, planOverlayModel, nullptr, nullptr );
#endif
#ifdef USE_LTSFRAMELESS
PlanOverlaysPlugin::PlanOverlayDialog<LtsWidgets::LtsFramelessDialog> * dialog = new PlanOverlaysPlugin::PlanOverlayDialog<LtsWidgets::LtsFramelessDialog>( nullptr, planOverlayModel, nullptr );
#endif
#ifdef CHECK_ERROR
PlanOverlaysPlugin::PlanOverlayDialog<QWidget> * dialog = new PlanOverlaysPlugin::PlanOverlayDialog<QWidget>( nullptr, planOverlayModel, nullptr ); // test static_assert
#endif
unsigned int counter = 1;
auto doReadFile = [dialog,&counter]( int /*selectedFileId*/ )
{
PlanOverlaysPlugin::PlanOverlayModel::PlanItem planItem = dialog->dialogWidget()->planOverlayModel()->planItem(counter++);
planItem.m_folderId = 6;
planItem.m_fileId = 42;
planItem.m_dirPath = QString();
planItem.m_fileName = QStringLiteral("Hugo_%1").arg(planItem.m_fileId);
planItem.m_minScale = 250000;
planItem.m_maxScale = 12000;
planItem.m_opacity = 1;
planItem.m_visibility = true;
dialog->dialogWidget()->planOverlayModel()->updatePlanItem( planItem );
};
auto doReloadPlan = [](unsigned int planId)
{
Q_UNUSED(planId);
QMessageBox::information(nullptr,QObject::tr("Reload Plan"),QObject::tr("doReloadPlan has been called"),QMessageBox::StandardButton::Ok);
};
auto doUnloadPlan = [dialog](unsigned int planId)
{
dialog->dialogWidget()->planOverlayModel()->removeOverlay(planId);
};
dialog->dialogWidget()->initFileManagement( nullptr, nullptr, nullptr, doReadFile, doReloadPlan, doUnloadPlan );
//QDialog * dialog = new QDialog();
//QVBoxLayout * layout = new QVBoxLayout(dialog);
//PlanOverlaysPlugin::PlanOverlayModel * planOverlayModel = new PlanOverlaysPlugin::PlanOverlayModel(nullptr);
//PlanOverlaysPlugin::PlanOverlayView * planOverlayView = new PlanOverlaysPlugin::PlanOverlayView( planOverlayModel, dialog );
//
//PlanOverlaysPlugin::PlanOverlayModel::PlanItem planItem = planOverlayModel->planItem(1);
//
//planItem.m_folderId = 6;
//planItem.m_fileId = 42;
//planItem.m_dirPath = QStringLiteral("");
//planItem.m_fileName = QStringLiteral("Hugo");
//planItem.m_planName = QStringLiteral("Hugo");
//planItem.m_minScale = 250000;
//planItem.m_maxScale = 12000;
//planItem.m_opacity = 1;
//planItem.m_visibilty = true;
//planOverlayModel->updatePlanItem( planItem );
//planItem.m_id = 2;
//planItem.m_fileId = 43;
//planItem.m_fileName = QStringLiteral("Soda");
//planItem.m_planName = QStringLiteral("Soda");
//planOverlayModel->updatePlanItem( planItem );
//planItem.m_id = 3;
//planItem.m_fileId = 44;
//planItem.m_fileName = QStringLiteral("0815");
//planItem.m_planName = QStringLiteral("0815");
//planOverlayModel->updatePlanItem( planItem );
//layout->addWidget(planOverlayView);
dialog->show();
app.setQuitOnLastWindowClosed(true);
int retval = app.exec();
SHUTDOWN_LOG(app.baseLogger());
return retval;
}
+178
View File
@@ -0,0 +1,178 @@
/**
* @RDE_HEADER@
* Topic Editor for the Plan Topic in the Script Editor
* $Id: topic_editor.cpp 48499 2019-09-26 07:56:34Z ojog_i $
* $HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Plugins/FileManagement/Gui/Explorer/TopicEditor/topic_editor.cpp $
* $Author: ojog_i $
*
* Created by Mike Wille, NLE, 2019-11-11
*/
#include "topic_editor.h"
#include "ui_topic_editor.h"
#include "../plan_overlays_gui_plugin.h"
#include <LtsSession/lts_session_data.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <TopicEditorBase/topic_previewer.h>
#include <QInputDialog>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
#include <QPushButton>
namespace PlanOverlaysPlugin
{
PlanTopicEditor::PlanTopicEditor(
ForeignGuiInterface **ifc, const std::shared_ptr<FileManagement::Interface::Dtc> &flmDtc, QWidget *parent
)
: TopicEditorBase::TopicEditor(parent)
, m_ifc(ifc)
, m_flmDtc(flmDtc)
, m_model(nullptr)
, m_ui(new Ui::PlanTopicEditor)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PlanTopicEditor"))
{
// init UI
m_ui->setupUi(this);
init(m_ui->widget);
m_buttonBox->setText(LtsWidgets::DialogButton::Edit, tr("Manage Plan Overlays"));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &PlanTopicEditor::onOpenPlanOverlayDialog);
if ((*m_ifc) == nullptr)
{
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
return;
}
else
m_ui->lblReadOnly->hide();
m_model = (*m_ifc)->planOverlayModel();
#ifndef LTS_DEBUG
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("PlanOverlays.TopicEditor.ShowFakeButton")) == QVariant(true))
#endif
{
QPushButton *pb = new QPushButton(QStringLiteral("[fake compatibility mode data]"));
layout()->addWidget(pb);
connect(pb, &QPushButton::clicked,
this, [this]()
{
// fake data to test compatibility mode:
m_topicData.properties = QJsonObject();
bool k = true;
int fileId = QInputDialog::getInt(this, QStringLiteral("fileId"), QStringLiteral("Enter the file id of an existing plan overlay"), 1003, 0, 999999, 1, &k);
if (!k)
{
QMessageBox::critical(this, QStringLiteral("nan"), QStringLiteral("nan!"));
return;
}
m_topicData.properties[QStringLiteral("FileId")] = fileId;
updateInternalData();
});
}
setOnlineHelpFilename(QStringLiteral("Script_Editor-Add_Tactical_Plan_Topic"));
}
PlanTopicEditor::~PlanTopicEditor()
{
delete m_ui;
}
///////////////////////////////////////////////////////////////////////////////
// PRIVATE
void PlanTopicEditor::updateInternalData()
{
if (!hasTopicDataProperties())
return;
m_planItems = QJsonArray(); // reset
// compatibility for old plan type topics (old topic only had ONE plan and was determined by only its 'FileId')
int fileId = getTopicDataValue(QStringLiteral("FileId")).toInt(-1);
if (fileId != -1)
{
DEBUG_LOG(m_logger) << "topic compatibility mode - converting..";
QJsonObject fakePlanItem;
fakePlanItem[QStringLiteral("keyId")] = 0;
fakePlanItem[QStringLiteral("fileId")] = fileId;
QString fileName;
if (m_flmDtc)
fileName = QString::fromStdString(m_flmDtc->fileContent(fileId).name());
if (fileName.isEmpty())
fileName = tr("Plan file id %1").arg(fileId);
fakePlanItem[QStringLiteral("fileName")] = fileName;
fakePlanItem[QStringLiteral("opacity")] = 1.0; // otherwise opacity is 0 and the user can't see it
m_planItems += fakePlanItem;
}
else
m_planItems = getTopicDataValue(QStringLiteral("PlanItems")).toArray();
if (m_planItems.isEmpty())
{
WARNING_LOG(m_logger) << "topic empty";
return;
}
retable();
}
void PlanTopicEditor::retranslate()
{
translate(m_ui, tr("Plan Topic Editor"));
}
void PlanTopicEditor::retable()
{
while (m_ui->plans->rowCount())
m_ui->plans->removeRow(m_ui->plans->rowCount() - 1);
for (auto i = m_planItems.constBegin(); i != m_planItems.constEnd(); ++i)
{
m_ui->plans->insertRow(0);
m_ui->plans->setItem(0, 0, new QTableWidgetItem((*i).toObject()[QStringLiteral("fileName")].toString(tr("(unknown)"))));
}
}
///////////////////////////////////////////////////////////////////////////////
// PRIVATE SLOTS
bool PlanTopicEditor::apply2()
{
m_topicData.properties.remove(QStringLiteral("FileId")); // remove old plan file id (if available)
setTopicDataProperty(QStringLiteral("PlanItems"), m_planItems);
setDescription(m_ui->widget->description());
m_ui->widget->previewer()->setTopicData(m_topicData);
return true;
}
void PlanTopicEditor::onOpenPlanOverlayDialog()
{
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false); // disable until already opened plan overlay dialog was closed or fully disable because essentials view was closed
if ((*m_ifc) == nullptr)
{
new LtsWidgets::LtsMessageDialogNew(this, tr("Plans can't be edited because essentials view was closed"));
return;
}
connect((*m_ifc)->openPlanOverlayDialog(m_planItems, true), &QWidget::destroyed, this, [this]()
{
m_planItems = m_model->toJson();
retable();
slotChangesMade();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit);
});
}
} // namespace PlanOverlaysPlugin
+67
View File
@@ -0,0 +1,67 @@
/**
* @RDE_HEADER@
* Topic Editor for the Situation Topic in the Script Editor
* $Id: topic_editor.h 47904 2019-08-09 09:11:38Z ehrlicher $
* $HeadURL: svn://slssvn/TDS/branches/product/devel/trunk/Lts/Plugins/FileManagement/Gui/Explorer/TopicEditor/topic_editor.h $
* $Author: ehrlicher $
*
* Created by Mike Wille, NLE, 2019-11-11
*/
#pragma once
#include <FileManagement/logger.h>
#include <FileManagement/Data/flm_data_plugin.h>
#include <LtsSession/lts_session.h>
#include <TopicEditorBase/topic_editor_base.h>
#include <QJsonArray>
namespace Ui { class PlanTopicEditor; }
namespace PlanOverlaysPlugin
{
class ForeignGuiInterface;
class PlanOverlayModel;
class PlanTopicEditor : public TopicEditorBase::TopicEditor
{
Q_OBJECT
public:
explicit PlanTopicEditor(
ForeignGuiInterface **ifc, const std::shared_ptr<FileManagement::Interface::Dtc> &flmDtc, QWidget *parent = nullptr
);
~PlanTopicEditor();
// void updatePreview();
private:
void updateInternalData() override final;
void retranslate() override final;
void retable();
void enaDisa();
private slots:
bool apply2() override final;
void onOpenPlanOverlayDialog();
private:
ForeignGuiInterface **m_ifc { nullptr };
std::shared_ptr<FileManagement::Interface::Dtc> m_flmDtc { nullptr };
QJsonArray m_planItems;
PlanOverlayModel *m_model { nullptr };
Ui::PlanTopicEditor *m_ui { nullptr };
NGL::INGLLogger &m_logger;
};
} // namespace PlanOverlaysPlugin
+92
View File
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PlanTopicEditor</class>
<widget class="QWidget" name="PlanTopicEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>623</width>
<height>357</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">File Topic Editor</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="TopicEditorBase::TopicPreviewWidget" name="widget" native="true"/>
</item>
<item row="3" column="1">
<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="2" column="0" colspan="2">
<widget class="QTableWidget" name="plans">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Plan name</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Selected Plans:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="lblReadOnly">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#d69545;&quot;&gt;Start the essentials view before opening this topic editor to be able to edit plans.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TopicEditorBase::TopicPreviewWidget</class>
<extends>QWidget</extends>
<header>TopicEditorBase/topic_preview_widget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+57
View File
@@ -0,0 +1,57 @@
/**
**
** @RDE_HEADER@
** plan_editor.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 09.05.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "flm_reply_handler.h"
#include <LtsUtilsGuiDds/request_helper.h>
namespace PlanOverlaysPlugin
{
FileManagementReplyHandler::FileManagementReplyHandler( LtsUtils::RequestHelper * requestHelper )
: m_requestHelper(requestHelper)
{
qRegisterMetaType<Core::FunctionReply>("Core::FunctionReply");
} // FileManagementReplyHandler::FileManagementReplyHandler( LtsUtils::RequestHelper * requestHelper )
void FileManagementReplyHandler::requestReply( const Core::FunctionReplyObject & replyObject )
{
m_requestHelper->requestReply(replyObject);
} // void FileManagementReplyHandler::requestReply( const Core::FunctionReplyObject & replyObject )
void FileManagementReplyHandler::onGetFileContentDataReply( const FileManagement::GetFileContentDataReply & replyObject )
{
m_content = replyObject.content();
m_requestHelper->requestReply(replyObject);
} // void FileManagementReplyHandler::onGetFileContentDataReply( const FileManagement::GetFileContentDataReply & replyObject )
} // namespace PlanOverlaysPlugin
+80
View File
@@ -0,0 +1,80 @@
/**
**
** @RDE_HEADER@
** flm_reply_handler.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 09.05.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <FileManagement/flm_ftc.h>
#include <FileManagement/flm_ftc_types.h>
#include <DDS/DDSConnector/dds_connector.h>
#include <QtCore/QObject>
namespace LtsUtils
{
class RequestHelper;
}
namespace PlanOverlaysPlugin
{
class FileManagementReplyHandler
: public QObject
, public FileManagement::Interface::Ftc::FileContentModifyReplyHandler
, public FileManagement::Interface::Ftc::FileContentChangeStatusReplyHandler
, public FileManagement::Interface::Ftc::FileContentRemoveReplyHandler
, public FileManagement::Interface::Ftc::GetFileContentDataReplyHandler
{
Q_OBJECT
public:
explicit FileManagementReplyHandler( LtsUtils::RequestHelper * );
~FileManagementReplyHandler() = default;
const std::vector<uint8_t> &getContent() const { return m_content; }
protected:
// file content
void onFileContentModifyReply ( const Core::FunctionReplyObject & replyObject) override final { requestReply(replyObject); }
void onFileContentRemoveReply ( const Core::FunctionReplyObject & replyObject) override final { requestReply(replyObject); }
void onFileContentChangeStatusReply ( const Core::FunctionReplyObject & replyObject) override final { requestReply(replyObject); }
void onGetFileContentDataReply( const FileManagement::GetFileContentDataReply & replyObject) override final;
private:
void requestReply(const Core::FunctionReplyObject &replyObject);
LtsUtils::RequestHelper *m_requestHelper;
std::vector<uint8_t> m_content;
}; // FileManagementReplyHandler
} // namespace PlanOverlaysPlugin
+336
View File
@@ -0,0 +1,336 @@
/**
**
** @RDE_HEADER@
** plan_overlay_dialog.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 14.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "plan_overlay_dialog.h"
#include "plan_overlay_model.h"
#include "plan_overlay_view.h"
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsWidgets/lts_drag_icon.h>
#include <LtsWidgets/lts_dialog_button_box.h>
#include <Viewer/LtsFileDialog/lts_file_dialog_widget.h>
#include <QDebug>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QDialog>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSplitter>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QHBoxLayout>
namespace PlanOverlaysPlugin
{
//const int PlanFolderID = 30;
struct PlanOverlayDialogWidget::InternalData
{
LtsSession::LtsSession *m_session = nullptr;
LtsWidgets::LtsFileDialogWidget *m_fileDialogWidget = nullptr;
PlanOverlaysPlugin::PlanOverlayModel *m_planOverlayModel = nullptr;
PlanOverlaysPlugin::PlanOverlayView *m_planOverlayView = nullptr;
SituationMap::ForeignGuiInterface *m_situationMapGui = nullptr;
QWidget *m_overlaySection = nullptr;
bool m_isInModalDialog = false;
}; // PlanOverlayDialog::InternalData
PlanOverlayDialogWidget::PlanOverlayDialogWidget(LtsSession::LtsSession *session,
SituationMap::ForeignGuiInterface *situationMapGui,
PlanOverlayModel *planOverlayModel,
QWidget *parent)
: QWidget(parent), m_internal(new InternalData())
{
m_internal->m_session = session;
m_internal->m_situationMapGui = situationMapGui;
m_internal->m_planOverlayModel = planOverlayModel;
const QString &title = tr("Managing Plan Overlays");
setObjectName(QLatin1String("PlanOverlaysPlugin::PlanOverlayDialog"));
QSplitter *splitter = new QSplitter(this);
QWidget *overlays = new QWidget(this);
QWidget *ctrlArea = new QWidget(overlays);
QVBoxLayout *layout = new QVBoxLayout(this);
QLabel *titleWidget = new QLabel(title, this);
m_internal->m_fileDialogWidget = new LtsWidgets::LtsFileDialogWidget(this);
m_internal->m_planOverlayView = new PlanOverlayView(m_internal->m_planOverlayModel, overlays);
m_internal->m_planOverlayModel->setFileDialogMimeType(m_internal->m_fileDialogWidget->dragMimeType());
connect(m_internal->m_planOverlayView, &PlanOverlayView::requestMinScale, this, &PlanOverlayDialogWidget::onRequestMinScaleFromUser);
connect(m_internal->m_planOverlayView, &PlanOverlayView::requestMaxScale, this, &PlanOverlayDialogWidget::onRequestMaxScaleFromUser);
titleWidget->setAlignment(Qt::AlignCenter);
// titleWidget->setStyleSheet(QStringLiteral("font-size: 18pt;"));
QFont boldFont;
boldFont.setBold(true);
boldFont.setPointSize(18);
titleWidget->setFont(boldFont);
layout->addWidget(titleWidget);
#ifdef LTS_DEBUG
if ((session) && (session->exerciseId() > 0))
{
const QString &subtitle = tr("Exercise: %1 / Phase: %2").arg(session->exerciseId()).arg(session->exerciseData()->phId);
QLabel *subtitleWidget = new QLabel(subtitle, this);
subtitleWidget->setAlignment(Qt::AlignCenter);
layout->addWidget(subtitleWidget);
}
#endif
layout->addWidget(splitter, 2);
layout->setMargin(0);
splitter->setOrientation(Qt::Orientation::Vertical); // or is Horizontal better here
splitter->addWidget(m_internal->m_fileDialogWidget);
splitter->addWidget(overlays);
splitter->setStretchFactor(0, 2);
splitter->setStretchFactor(1, 4);
QPixmap icon(QLatin1String("icon:overlay_load_plan.svg")); // better use left and right buttons
LtsWidgets::LtsDragIcon *pbAddOverlay = new LtsWidgets::LtsDragIcon(ctrlArea);
pbAddOverlay->setIcon(QIcon(icon));
pbAddOverlay->setText(QString());
pbAddOverlay->setIconSize(LtsWidgets::ButtonSize::eDefault);
pbAddOverlay->setButtonStyle(LtsWidgets::ButtonStyle::eIconOnly);
pbAddOverlay->setToolTip(tr("Load selected plan file and create new plan overlayer at end of display order"));
connect(pbAddOverlay, &LtsWidgets::LtsDragIcon::clicked, this, &PlanOverlayDialogWidget::onLoadPlan);
#ifdef DISABLE_ADD_OVERLAY
pbAddOverlay->setDisabled(true);
connect(m_internal->m_fileDialogWidget, &LtsWidgets::LtsFileDialogWidget::readyToAccept, pbAddOverlay, [pbAddOverlay]()
{
pbAddOverlay->setDisabled(false);
});
#endif
QVBoxLayout *layoutOverlays = new QVBoxLayout(overlays); // or is QHBoxLayout better here
QHBoxLayout *layoutCtrl = new QHBoxLayout();
layoutOverlays->addSpacing(5);
layoutOverlays->addLayout(layoutCtrl, 0);
layoutOverlays->addSpacing(5);
layoutOverlays->addWidget(m_internal->m_planOverlayView, 2);
layoutCtrl->addStretch(2);
layoutCtrl->addSpacing(20);
layoutCtrl->addWidget(pbAddOverlay);
layoutCtrl->addSpacing(20);
layoutCtrl->addStretch(2);
m_internal->m_overlaySection = overlays;
if (m_internal->m_situationMapGui)
{
auto mapIsReady = [this]() { onEnableOverlaySection(true); };
if (!m_internal->m_situationMapGui->setMapReadyCallback(this, mapIsReady))
qCritical() << " setMapReadyCallback failed";
}
onEnableOverlaySection(true);
// setMinimumHeight(int(QApplication::desktop()->availableGeometry().height()*0.9));
} // PlanOverlayDialogWidget::PlanOverlayDialogWidget( QWidget * parent )
PlanOverlayDialogWidget::~PlanOverlayDialogWidget()
{
delete m_internal;
} // PlanOverlayDialogWidget::~PlanOverlayDialogWidget()
bool PlanOverlayDialogWidget::isInModalDialog() const { return m_internal->m_isInModalDialog; }
void PlanOverlayDialogWidget::setIsInModalDialog(bool on) { m_internal->m_isInModalDialog = on; }
bool PlanOverlayDialogWidget::initFileManagement(const std::shared_ptr<FileManagement::Interface::Dtc> &dtc
, const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc
, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc
, const std::function<void(int selectedFileId)> &doRead
, const std::function<void(int planId)> &doReload
, const std::function<void(int planId)> &doUnload
, bool isOc)
{
int parentFolderId = 0;
if (isOc)
{
//search for exercise folder instead of global plans
parentFolderId = dtc->getExerciseFolderId(m_internal->m_session->exerciseId());
}
int planFolderId = dtc->findFolder(parentFolderId, QStringLiteral("Tactical Plans"));
connect(m_internal->m_fileDialogWidget, &LtsWidgets::LtsFileDialogWidget::readSelectedFile, m_internal->m_fileDialogWidget, [doRead](int fileId)
{
doRead(fileId);
});
connect(m_internal->m_planOverlayView, &PlanOverlayView::requestUnloadPlan, this, [doUnload](int planId)
{
doUnload(planId);
});
connect(m_internal->m_planOverlayView, &PlanOverlayView::requestReloadPlanById, this, [doReload](int planId)
{
doReload(planId);
});
// TODO: init parameter with desired MainFolders
QVector<FileManagement::MainFolder> mainFolders;
// remove next comment to hide Globald File Structure on OC
if (!isOc)
mainFolders.append(FileManagement::MainFolder::GlobalDocuments);
mainFolders.append(FileManagement::MainFolder::ExerciseDocuments);
mainFolders.append(FileManagement::MainFolder::UserDocuments);
if (!m_internal->m_fileDialogWidget->init(m_internal->m_session, dtc, opmDtc, exmDtc, LtsWidgets::FileDialogMode::modeOpenFile,
mainFolders,{FileManagement::FileType::TacticalPlan}, planFolderId))
return false;
return true;
} // bool PlanOverlayDialogWidget::initFileManagement(...)
void PlanOverlayDialogWidget::onEnableOverlaySection(bool on)
{
m_internal->m_overlaySection->setEnabled(((m_internal->m_situationMapGui) ? m_internal->m_situationMapGui->isMapReady() : true) && on);
} // void PlanOverlayDialogWidget::onEnableOverlaySection(bool on)
void PlanOverlayDialogWidget::onLoadPlan()
{
m_internal->m_fileDialogWidget->requestReadingSelectedFile();
}
void PlanOverlayDialogWidget::onRequestMinScaleFromUser(int planId, const QString &planName)
{
if (isInModalDialog()) return;
QHash<LtsWidgets::Button, QString> btnTxt;
btnTxt[LtsWidgets::Button::Yes] = tr("Set to current");
btnTxt[LtsWidgets::Button::No] = tr("Clear");
btnTxt[LtsWidgets::Button::Cancel] = tr("Cancel");
const LtsWidgets::Button resultBNtn = LtsWidgets::LtsMessageDialog::showMessage(this
, tr("Set current scale of map as minimum scale of plan overlay %1?").arg(planName)
, tr("Redefine maximum scale of plan overlay")
, LtsWidgets::Behaviour::Modal
, LtsWidgets::Button::Yes | LtsWidgets::Button::No | LtsWidgets::Button::Cancel
, btnTxt);
if (resultBNtn == LtsWidgets::Button::Yes)
{
double minScale = m_internal->m_situationMapGui->getCurrentMapScale();
if (minScale > 0.0)
{
const auto maxScale = m_internal->m_situationMapGui->planOverlayMaxScale(planId);
if (minScale < maxScale || qFuzzyIsNull(maxScale))
{
int row = m_internal->m_planOverlayModel->getRowOfId(planId);
m_internal->m_planOverlayModel->setMinScale(row, minScale);
}
else
{
QString msg = tr("The value of %1 is not allowed as minimum scale").arg(minScale);
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Illegal value of minimum scale"));
}
}
}
else if (resultBNtn == LtsWidgets::Button::No)
{
// clear / undefined
int row = m_internal->m_planOverlayModel->getRowOfId(planId);
m_internal->m_planOverlayModel->setMinScale(row, 0); // 0 == undefined
}
emit requestDialogShow();
} // void PlanOverlayDialogWidget::onSetMinScale( int planId )
void PlanOverlayDialogWidget::onRequestMaxScaleFromUser(int planId, const QString &planName)
{
if (isInModalDialog()) return;
QHash<LtsWidgets::Button, QString> btnTxt;
btnTxt[LtsWidgets::Button::Yes] = tr("Set to current");
btnTxt[LtsWidgets::Button::No] = tr("Clear");
btnTxt[LtsWidgets::Button::Cancel] = tr("Cancel");
const LtsWidgets::Button resultBNtn = LtsWidgets::LtsMessageDialog::showMessage(this
, tr("Set current scale of map as maximum scale of plan overlay %1?").arg(planName)
, tr("Redefine maximum scale of plan overlay")
, LtsWidgets::Behaviour::Modal
, LtsWidgets::Button::Yes | LtsWidgets::Button::No | LtsWidgets::Button::Cancel
, btnTxt);
if (resultBNtn == LtsWidgets::Button::Yes)
{
double maxScale = m_internal->m_situationMapGui->getCurrentMapScale();
if (maxScale > 0)
{
if (maxScale > m_internal->m_situationMapGui->planOverlayMinScale(planId))
{
int row = m_internal->m_planOverlayModel->getRowOfId(planId);
m_internal->m_planOverlayModel->setMaxScale(row, maxScale);
}
else
{
QString msg = tr("The value of %1 is not allowed as maximum scale").arg(maxScale);
LtsWidgets::LtsMessageDialog::showMessage(this, msg, tr("Illegal Value of Maximum Scale"));
}
}
}
else if (resultBNtn == LtsWidgets::Button::No)
{
// clear / undefined
int row = m_internal->m_planOverlayModel->getRowOfId(planId);
m_internal->m_planOverlayModel->setMaxScale(row, 0); // 0 == undefined
}
emit requestDialogShow();
}// void PlanOverlayDialogWidget::onSetMaxScale( int planId )
PlanOverlayModel *PlanOverlayDialogWidget::planOverlayModel() const { return m_internal->m_planOverlayModel; }
} // namespace PlanOverlaysPlugin
+235
View File
@@ -0,0 +1,235 @@
/**
**
** @RDE_HEADER@
** plan_overlay_dialog.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 14.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <Services/FileManagement/flm_dtc.h>
#include <Services/OperatorManagement/opm_dtc.h>
#include <Services/ExerciseManagement/exm_dtc.h>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>
namespace SituationMap
{
class ForeignGuiInterface;
}
namespace PlanOverlaysPlugin
{
class PlanOverlayModel;
//
// class PlanOverlayDialogWidget
//
class PlanOverlayDialogWidget : public QWidget
{
Q_OBJECT
public:
explicit PlanOverlayDialogWidget(LtsSession::LtsSession *session, SituationMap::ForeignGuiInterface *situationMapGui, PlanOverlayModel *planOverlayModel, QWidget *parent);
virtual ~PlanOverlayDialogWidget();
bool initFileManagement(const std::shared_ptr<FileManagement::Interface::Dtc> &dtc
, const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc
, const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc
, const std::function<void(int selectedFileId)> &doRead
, const std::function<void(int planId)> &doReload
, const std::function<void(int planId)> &doUnload
, bool isOc = false);
PlanOverlayModel *planOverlayModel() const;
bool isInModalDialog() const;
void setIsInModalDialog(bool on = true);
private slots:
void onLoadPlan();
void onRequestMinScaleFromUser(int planId, const QString &planName);
void onRequestMaxScaleFromUser(int planId, const QString &planName);
void onEnableOverlaySection(bool on);
signals:
void requestDialogShow();
private:
struct InternalData;
InternalData *m_internal;
}; // PlanOverlayDialogWidget
//
// Dialog
//
class Dialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent, LtsWidgets::ButtonCombination buttonCombination = LtsWidgets::ButtonCombination::CloseOnly, bool closeable = true)
: LtsWidgets::LtsDialog(parent, buttonCombination, closeable)
{
setUnchangeable();
} // Dialog
virtual ~Dialog() = default;
void retranslate() {;}
}; // Dialog
template<class DialogClass> void createPlanOverlayDialog(DialogClass *&dlgPtr, QWidget *parent);
template<> inline void createPlanOverlayDialog<QDialog>(QDialog *&dlgPtr, QWidget *parent)
{
dlgPtr = new QDialog(parent);
dlgPtr -> setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowStaysOnTopHint | Qt::Dialog);
dlgPtr -> setWindowTitle(QObject::tr("Plan Overlays"));
} // template<> void createPlanOverlayDialog<QDialog>( QDialog *& dlgPtr, QWidget * parent )
template<> inline void createPlanOverlayDialog<LtsWidgets::LtsFramelessDialog>(LtsWidgets::LtsFramelessDialog *&dlgPtr, QWidget *parent)
{
dlgPtr = new LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal);
} // template<> void createPlanOverlayDialog<LtsWidgets::LtsFramelessDialog>( LtsWidgets::LtsFramelessDialog *&dlgPtr, QWidget * parent )
//
// PlanOverlayDialog
//
template<class DialogClass> class PlanOverlayDialog
{
DialogClass *m_dialog;
PlanOverlayDialogWidget *m_dialogWidget;
LtsSession::LtsSession *m_session;
public:
// explicit PlanOverlayDialog(LtsSession::LtsSession *session, SituationMap::ForeignGuiInterface *situationMapGui, PlanOverlayModel *planOverlayModel, QWidget *parent)
// : m_dialog(nullptr), m_dialogWidget(nullptr), m_session(session)
// {
// static_assert(std::is_same<DialogClass, LtsWidgets::LtsDialog>::value, "This ctor of template class PlanOverlayDialog can only be used with LtsWidgets::LtsDialog");
// Dialog *dlg = new Dialog(parent);
// PlanOverlayDialogWidget *m_dialogWidget = new PlanOverlayDialogWidget(session, situationMapGui, planOverlayModel, dlg);
// //QObject::connect(situationMapGui->map(), &QObject::destroyed, m_dialogWidget, &QObject::deleteLater);
// session->addWidget(dlg, m_dialogWidget->windowTitle(), QLatin1String("PlanOverlayDialog"), LtsWidgets::LayoutArea::eDialogTab, false);
// m_dialog = dlg;
// QObject::connect(m_dialogWidget, &PlanOverlayDialogWidget::requestDialogShow, m_dialog, &DialogClass::show);
// m_dialogWidget->setIsInModalDialog(false);
// m_dialog->setAttribute(Qt::WA_DeleteOnClose, true);
// } // PlanOverlayDialog( LtsSession::LtsSession * session, SituationMap::ForeignGuiInterface * situationMapGui, PlanOverlayModel * planOverlayModel, QWidget * parent)
explicit PlanOverlayDialog(SituationMap::ForeignGuiInterface *situationMapGui, PlanOverlayModel *planOverlayModel, QWidget *parent, LtsSession::LtsSession *session)
: m_dialog(nullptr), m_dialogWidget(nullptr), m_session(session)
{
static_assert(std::is_same<DialogClass, LtsWidgets::LtsFramelessDialog>::value || std::is_same<DialogClass, QDialog>::value
, "This ctor of template class PlanOverlayDialog can only be used with QDialog and LtsWidgets::LtsFramelessDialog");
createPlanOverlayDialog(m_dialog, parent);
m_dialogWidget = new PlanOverlayDialogWidget(m_session, situationMapGui, planOverlayModel, m_dialog);
//QObject::connect(situationMapGui->map(), &QObject::destroyed, m_dialogWidget, &QObject::deleteLater);
QVBoxLayout *layout = new QVBoxLayout(m_dialog);
LtsWidgets::LtsDialogButtonBox *buttonBox = new LtsWidgets::LtsDialogButtonBox(parent);
QPushButton *btn = buttonBox->getButton(LtsWidgets::DialogButton::Help);
if (btn && m_session)
{
QObject::connect(btn, &QPushButton::clicked, m_dialog, [this]() // 'this' can´t be used as 3rd para. So use m_dialog instead
{
if (m_session)
m_session->slotShowOnlineHelp(QStringLiteral("Situation-Plan_Overlays"));
});
btn->setVisible(true);
}
layout->addWidget(m_dialogWidget, 2);
layout->addWidget(buttonBox);
buttonBox->setButtonVisible(LtsWidgets::DialogButton::Apply, false);
buttonBox->setButtonVisible(LtsWidgets::DialogButton::Ok, false);
QObject::connect(buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, m_dialog, &DialogClass::close);
m_dialog->setMinimumHeight(int(QApplication::desktop()->availableGeometry(m_dialogWidget).height() * 0.9));
QObject::connect(m_dialogWidget, &PlanOverlayDialogWidget::requestDialogShow, m_dialog, &DialogClass::show);
m_dialogWidget->setIsInModalDialog(std::is_same<DialogClass, LtsWidgets::LtsFramelessDialog>::value);
m_dialog->setAttribute(Qt::WA_DeleteOnClose, true);
} // PlanOverlayDialog( SituationMap::ForeignGuiInterface * situationMapGui, PlanOverlayModel * planOverlayModel, QWidget * parent )
virtual ~PlanOverlayDialog() = default;
PlanOverlayDialog(const PlanOverlayDialog &) = delete;
PlanOverlayDialog &operator = (const PlanOverlayDialog &) = delete;
PlanOverlayDialogWidget *dialogWidget() const { return m_dialogWidget; }
void show() { if (m_dialog) m_dialog->show(); }
}; // PlanOverlayDialog
} // namespace PlanOverlaysPlugin
+616
View File
@@ -0,0 +1,616 @@
/**
**
** @RDE_HEADER@
** plan_overlay_model.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 10.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "plan_overlay_model.h"
#include <QByteArray>
#include <QDataStream>
#include <QMimeData>
#include <QJsonArray>
#include <FileManagement/flm_dtc.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
template<class _Ty, class _Other = _Ty> inline _Ty doExchange(_Ty &_Val, _Other && _New_val)
{
// assign _New_val to _Val, return previous _Val
_Ty _Old_val = std::move(_Val);
_Val = std::forward<_Other>(_New_val);
return (_Old_val);
}
namespace PlanOverlaysPlugin
{
const QLatin1String REORDER_MIMETYPE("application/LtsPlanOverlayItemData/Reorder");
class PlanOverlayModel::InternalData
{
public:
QMap<unsigned int, PlanOverlayModel::PlanItem> m_planStore;
QVector<int> m_planOrder;
QString m_fileDialogMimeType;
InternalData()
: m_planStore(), m_planOrder(), m_fileDialogMimeType()
{
} // InternalData(const std::shared_ptr<SituationMap::ForeignGuiInterface> & sitMapGui)
~InternalData() = default;
}; // PlanOverLayModel::InternalData
PlanOverlayModel::PlanOverlayModel() : QAbstractItemModel(), m_internal(new InternalData())
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PlanOverlayModel"))
{;}
PlanOverlayModel::~PlanOverlayModel()
{
delete m_internal;
} // PlanOverlayModel::~PlanOverlayModel
#ifdef LTS_DEBUG
// show exercise id and phase id, last 2 columns in Debug mode
int PlanOverlayModel::columnCount(const QModelIndex &) const { return int(ColumnSection::CustomSection) + 3; }
#else
int PlanOverlayModel::columnCount(const QModelIndex &) const { return int(ColumnSection::CustomSection) + 1; }
#endif
int PlanOverlayModel::rowCount(const QModelIndex &) const { return m_internal->m_planStore.size(); }
int PlanOverlayModel::size() const { return m_internal->m_planStore.size(); }
QMap<unsigned int, PlanOverlayModel::PlanItem> PlanOverlayModel::planStore() const { return m_internal->m_planStore; }
bool PlanOverlayModel::isEmpty() const { return m_internal->m_planStore.isEmpty(); }
QVariant PlanOverlayModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole ||
orientation == Qt::Orientation::Vertical)
return QVariant();
switch (static_cast<ColumnSection>(section))
{
case ColumnSection::OrderButtons:
return QVariant();
case ColumnSection::PlanName:
return tr("Plan");
case ColumnSection::MinScale:
return tr("Min. Scale");
case ColumnSection::MaxScale:
return tr("Max. Scale");
case ColumnSection::Opacity:
return tr("Opacity");
case ColumnSection::CustomSection:
return QVariant();
case ColumnSection::ExerciseId:
return tr("Exercise");
case ColumnSection::PhaseId:
return tr("Phase");
}
return QVariant();
} // QVariant PlanOverlayModel::headerData( int section, Qt::Orientation orientation, int role ) const
QVariant PlanOverlayModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_internal->m_planOrder.size())
return QVariant();
if (Qt::ItemDataRole::TextAlignmentRole == role)
{
switch (static_cast<ColumnSection>(index.column()))
{
case ColumnSection::PlanName:
return QVariant(Qt::Alignment::enum_type::AlignCenter);
case ColumnSection::MinScale:
return QVariant(Qt::Alignment::enum_type::AlignRight | Qt::Alignment::enum_type::AlignHCenter);
case ColumnSection::MaxScale:
return QVariant(Qt::Alignment::enum_type::AlignRight | Qt::Alignment::enum_type::AlignHCenter);
case ColumnSection::OrderButtons:
case ColumnSection::Opacity:
case ColumnSection::CustomSection:
case ColumnSection::ExerciseId:
case ColumnSection::PhaseId:
return QVariant();
}
}
if (Qt::ItemDataRole::DisplayRole == role)
{
const PlanItem &planItem = m_internal->m_planStore[m_internal->m_planOrder.at(index.row())];
switch (static_cast<ColumnSection>(index.column()))
{
case ColumnSection::OrderButtons:
return QString();
case ColumnSection::PlanName:
return planItem.m_fileName;
case ColumnSection::MinScale:
return (planItem.m_minScale > 0) ? QStringLiteral("1:%1").arg(planItem.m_minScale) : tr("undefined");
case ColumnSection::MaxScale:
return (planItem.m_maxScale > 0) ? QStringLiteral("1:%1").arg(planItem.m_maxScale) : tr("undefined");
case ColumnSection::Opacity:
return planItem.m_opacity;
case ColumnSection::CustomSection:
return QString();
case ColumnSection::ExerciseId:
return planItem.m_exerciseId > 0 ? QVariant(planItem.m_exerciseId) : QVariant();
case ColumnSection::PhaseId:
return planItem.m_phaseId > 0 ? QVariant(planItem.m_phaseId) : QVariant();
}
}
return QVariant();
} // QVariant PlanOverlayModel::data( const QModelIndex & index, int role ) const
QStringList PlanOverlayModel::mimeTypes() const
{
QStringList typeList;
typeList << REORDER_MIMETYPE;
if (!m_internal->m_fileDialogMimeType.isEmpty())
typeList << m_internal->m_fileDialogMimeType;
return typeList;
} // QStringList PlanOverlayModel::mimeTypes() const
void PlanOverlayModel::setFileDialogMimeType(const QString &mimeType)
{
m_internal->m_fileDialogMimeType = mimeType;
} // void PlanOverlayModel::setFileDialogMimeType( const QString & mimeType )
QMimeData *PlanOverlayModel::mimeData(const QModelIndexList &indexes) const
{
if (indexes.isEmpty()) return nullptr;
int row = indexes.first().row();
unsigned int keyId = m_internal->m_planOrder.at(row);
QMimeData *mimeData = new QMimeData();
QByteArray encodedData;
mimeData->setData(REORDER_MIMETYPE, encodedData.setNum(keyId));
return mimeData;
} // QMimeData * PlanOverlayModel::mimeData( const QModelIndexList & indexes ) const
bool PlanOverlayModel::canDropMimeData(const QMimeData *data, Qt::DropAction, int row, int, const QModelIndex &) const
{
if ((row >= 0) && (row < m_internal->m_planOrder.size()))
{
if (data->hasFormat(REORDER_MIMETYPE))
{
QByteArray encodedData = data->data(REORDER_MIMETYPE);
bool ok = false;
unsigned int keyId = encodedData.toUInt(&ok);
if (ok) return (m_internal->m_planOrder.indexOf(keyId) != row);
}
if ((!m_internal->m_fileDialogMimeType.isEmpty()) && (data->hasFormat(m_internal->m_fileDialogMimeType)))
{
QByteArray encodedData = data->data(m_internal->m_fileDialogMimeType);
bool ok = false;
int keyId = encodedData.toUInt(&ok);
if (ok) return (keyId > 0);
}
}
return false;
} // bool PlanOverlayModel::canDropMimeData( const QMimeData * data, Qt::DropAction, int, int, const QModelIndex & ) const
bool PlanOverlayModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
if (!canDropMimeData(data, action, row, column, parent)) return false;
if (action == Qt::IgnoreAction) return true;
emit dropPlanAccepted();
if (data->hasFormat(REORDER_MIMETYPE))
{
QByteArray encodedData = data->data(REORDER_MIMETYPE);
bool ok = false;
int keyId = encodedData.toInt(&ok);
if (!ok) return false;
int rowToMove = m_internal->m_planOrder.indexOf(keyId);
if (row != rowToMove)
{
if (row < rowToMove)
{
for (; row <= rowToMove; ++row)
{
unsigned int idSwap = m_internal->m_planOrder[row];
m_internal->m_planOrder[row] = keyId;
keyId = idSwap;
}
}
else
{
for (--row; row >= rowToMove; --row)
{
unsigned int idSwap = m_internal->m_planOrder[row];
m_internal->m_planOrder[row] = keyId;
keyId = idSwap;
}
}
emit dataChanged(createIndex(0, 0), createIndex(m_internal->m_planOrder.size() - 1, columnCount(QModelIndex()) - 1));
emit layoutChanged();
emit planOrderChanged(m_internal->m_planOrder);
}
return true;
}
if ((!m_internal->m_fileDialogMimeType.isEmpty()) && (data->hasFormat(m_internal->m_fileDialogMimeType)))
{
QByteArray encodedData = data->data(m_internal->m_fileDialogMimeType);
bool ok = false;
int fileId = encodedData.toInt(&ok);
if ((ok) && (fileId > 0))
{
emit requestLoadPlan(fileId);
// so the plan is now loaded at end of overlay list, move it a the right position
int rowToMove = m_internal->m_planOrder.size() - 1;
int keyId = m_internal->m_planOrder[rowToMove];
if (row != rowToMove)
{
for (; row <= rowToMove; ++row)
keyId = doExchange(m_internal->m_planOrder[row], keyId);
emit dataChanged(createIndex(0, 0), createIndex(m_internal->m_planOrder.size() - 1, columnCount(QModelIndex()) - 1));
emit layoutChanged();
emit planOrderChanged(m_internal->m_planOrder);
}
return true;
}
}
return false;
}
QJsonArray PlanOverlayModel::toJson() const
{
QJsonArray result;
if (m_internal->m_planStore.count() != m_internal->m_planOrder.count())
{
Q_ASSERT(m_internal->m_planStore.count() == m_internal->m_planOrder.count());
return result;
}
// save in reverse order, because loadPlan appends plans instead of prepending
for (int i = m_internal->m_planStore.count() - 1; i >= 0; i--)
{
PlanItem planItem = m_internal->m_planStore[m_internal->m_planOrder.at(i)];
result += planItem.toJson();
}
return result;
}
PlanOverlayModel::PlanItem PlanOverlayModel::planItem(int keyId)
{
if (keyId < 1)
{
static int nextKey = 1;
keyId = nextKey++;
}
PlanItem &planItem = m_internal->m_planStore[keyId];
planItem.m_keyId = keyId;
return planItem;
}
PlanOverlayModel::PlanItem &PlanOverlayModel::planItemRef(int keyId)
{
return m_internal->m_planStore[keyId];
}
PlanOverlayModel::PlanItem PlanOverlayModel::planItemValue(int keyId)
{
QMap<unsigned int, PlanOverlayModel::PlanItem>::Iterator found = m_internal->m_planStore.find(keyId);
return (found == m_internal->m_planStore.end()) ? PlanItem() : found.value();
}
PlanOverlayModel::PlanItem PlanOverlayModel::planItemAtRow(int row)
{
if ((row < 0) || (row >= m_internal->m_planOrder.size())) return PlanItem();
unsigned int planKeyId = m_internal->m_planOrder.at(row);
return m_internal->m_planStore[planKeyId];
}
PlanOverlayModel::PlanItem PlanOverlayModel::findPlanItemByFileId(int fileId)
{
if (fileId < 1)
return PlanItem();
QMap<unsigned int, PlanOverlayModel::PlanItem>::const_iterator it;
for (it = m_internal->m_planStore.constBegin(); it != m_internal->m_planStore.constEnd(); ++it)
{
if (it.value().m_fileId == fileId)
return it.value();
}
return PlanItem();
}
Qt::ItemFlags PlanOverlayModel::flags(const QModelIndex &modelIndex) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(modelIndex) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
switch (static_cast<ColumnSection>(modelIndex.column()))
{
case ColumnSection::OrderButtons:
case ColumnSection::PlanName:
case ColumnSection::MinScale:
case ColumnSection::MaxScale:
case ColumnSection::Opacity:
flags |= Qt::ItemIsEditable;
break;
case ColumnSection::CustomSection:
case ColumnSection::ExerciseId:
case ColumnSection::PhaseId:
break;
}
return flags;
} // Qt::ItemFlags PlanOverlayModel::flags( const QModelIndex & modelIndex ) const
void PlanOverlayModel::updatePlanItem(const PlanItem &planItem)
{
if (!planItem.isValid())
{
ERROR_LOG(m_logger) << "planItem has invalid key";
return;
}
m_internal->m_planStore[planItem.m_keyId] = planItem;
beginResetModel();
{
if (!m_internal->m_planOrder.contains(planItem.m_keyId))
m_internal->m_planOrder.prepend(planItem.m_keyId);
}
endResetModel();
int row = m_internal->m_planOrder.size() - 1;
emit dataChanged(index(row, 0, QModelIndex()), index(row, columnCount(QModelIndex()) - 1, QModelIndex()));
emit layoutChanged();
} // void PlanOverlayModel::updatePlanItem(PlanItem & planItem)
void PlanOverlayModel::swapRow(int row1, int row2)
{
if (row1 < 0) return;
if (row2 < 0) return;
if (row1 >= m_internal->m_planOrder.size()) return;
if (row2 >= m_internal->m_planOrder.size()) return;
m_internal->m_planOrder[row2] = doExchange(m_internal->m_planOrder[row1], m_internal->m_planOrder[row2]);
QModelIndex topLeftIndex;
QModelIndex bottomRightIndex;
if (row1 < row2)
{
topLeftIndex = createIndex(row1, 0);
bottomRightIndex = createIndex(row2, columnCount(QModelIndex()) - 1);
}
else
{
topLeftIndex = createIndex(row2, 0);
bottomRightIndex = createIndex(row1, columnCount(QModelIndex()) - 1);
}
emit dataChanged(topLeftIndex, bottomRightIndex);
emit planOrderChanged(m_internal->m_planOrder);
} // void PlanOverlayModel::swapRow(int row1, int row2)
int PlanOverlayModel::getRowOfId(int keyId) const
{
return m_internal->m_planOrder.indexOf(keyId);
} // PlanOverlayModel::getRowOfId( int id )
void PlanOverlayModel::setMinScale(int row, double scale)
{
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
const int id = m_internal->m_planOrder[row];
planItemRef(id).m_minScale = scale;
emit planMinScaleChanged(id, scale);
const QModelIndex &modelIndex = createIndex(row, int(ColumnSection::MinScale));
emit dataChanged(modelIndex, modelIndex);
} // void PlanOverlayModel::setMinScale( int row, double scale )
void PlanOverlayModel::setMaxScale(int row, double scale)
{
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
const int id = m_internal->m_planOrder[row];
planItemRef(id).m_maxScale = scale;
emit planMaxScaleChanged(id, scale);
const QModelIndex &modelIndex = createIndex(row, int(ColumnSection::MaxScale));
emit dataChanged(modelIndex, modelIndex);
} // void PlanOverlayModel::setMaxScale( int row, double scale )
void PlanOverlayModel::setOpacity(int row, double opacity)
{
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
if (opacity < 0) opacity = 0.0;
if (opacity > 1) opacity = 1.0;
const int id = m_internal->m_planOrder[row];
planItemRef(id).m_opacity = opacity;
emit planOpacityChanged(id, opacity);
const QModelIndex &modelIndex = createIndex(row, int(ColumnSection::Opacity));
emit dataChanged(modelIndex, modelIndex);
} // void PlanOverlayModel::setAlpha( int row, double alpha )
void PlanOverlayModel::updateOverlay(int keyId)
{
// keep in mimd fileId is same as planId here
int row = m_internal->m_planOrder.indexOf(keyId);
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
emit dataChanged(createIndex(row, 0), createIndex(row, columnCount(QModelIndex()) - 1));
emit requestUpdatePlan(keyId);
} // void PlanOverlayModel::updateOverlay(int fileId)
void PlanOverlayModel::renewPlanItem(const PlanItem &planItem)
{
int row = m_internal->m_planOrder.indexOf(planItem.m_keyId);
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
m_internal->m_planStore[planItem.m_keyId] = planItem;
emit dataChanged(createIndex(row, 0), createIndex(row, columnCount(QModelIndex()) - 1));
} // void PlanOverlayModel::renewPlanItem( const PlanItem & planItem )
void PlanOverlayModel::removeOverlay(int keyId)
{
int row = m_internal->m_planOrder.indexOf(keyId);
if (row < 0) return;
if (row >= m_internal->m_planOrder.size()) return;
emit requestRemovePlan(keyId); // Important: remove first from situation map and there for we need information from model entry
beginResetModel();
{
m_internal->m_planStore.remove(keyId);
m_internal->m_planOrder.remove(row);
}
endResetModel();
emit dataChanged(createIndex(0, 0), createIndex(m_internal->m_planOrder.size() - 1, columnCount(QModelIndex()) - 1));
emit layoutChanged();
} // void PlanOverlayModel::removeOverlay( int keyId )
bool PlanOverlayModel::reInitModel(int exerciseId, int phaseId)
{
DEBUG_LOG(m_logger) << "ReInit Model for exerciseId = " << exerciseId << ", phaseId = " << phaseId;
if ((exerciseId < 1) || (phaseId < 1))
{
// what's to do here??
WARNING_LOG(m_logger) << LOGFUNCTION << " has been called with undefined exercise and/or phaseId";
return false;
}
QVector<int> removeList;
removeList.reserve(m_internal->m_planOrder.size());
QMap<unsigned int, PlanOverlayModel::PlanItem>::const_iterator it;
for (it = m_internal->m_planStore.constBegin(); it != m_internal->m_planStore.constEnd(); ++it)
{
int planExId = it.value().m_exerciseId;
int planPhId = it.value().m_phaseId;
DEBUG_LOG(m_logger) << "Plan name = " << it.value().m_fileName << " exercise = " << planExId << " phase = " << planPhId;
if ((planExId < 1) || (planPhId < 1) || ((planExId == exerciseId) && (planPhId == phaseId)))
{
// nothing to do, exercise and phase did not change or it is a global or user plan
continue;
}
bool removeFromModel(false);
emit requestReloadPlanByName(it.value(), exerciseId, phaseId, &removeFromModel);
if (removeFromModel) removeList << it.value().m_keyId;
} // for m_planOder
// remove all plans which doesn't exist any more from model
for (auto id : qAsConst(removeList)) removeOverlay(id);
emit dataChanged(createIndex(0, 0), createIndex(m_internal->m_planOrder.size() - 1, columnCount(QModelIndex()) - 1));
emit layoutChanged();
return true;
} // void PlanOverlayModel::reInitModel(int exerciseId, int phaseId)
void PlanOverlayModel::updateOrderOfPlans() const
{
emit const_cast<PlanOverlayModel *>(this)->planOrderChanged(m_internal->m_planOrder);
} // void PlanOverlayModel::updateOrderOfPlans() const
} // namespace PlanOverlaysPlugin
+215
View File
@@ -0,0 +1,215 @@
/**
**
** @RDE_HEADER@
** plan_overlay_model.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 10.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <NGLLogger/INGLLogger.h>
#include <QAbstractItemModel>
#include <QJsonObject>
namespace PlanOverlaysPlugin
{
class PlanOverlayModel final : public QAbstractItemModel
{
Q_OBJECT
public:
enum class ColumnSection
{
OrderButtons = 0,
PlanName,
MinScale,
MaxScale,
Opacity,
CustomSection,
ExerciseId,
PhaseId
};
PlanOverlayModel();
~PlanOverlayModel();
/**
@name Overloaded function from AbstractItemModel
@{
*/
int columnCount(const QModelIndex &) const override;
int rowCount(const QModelIndex &) const override;
int size() const;
bool isEmpty() const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::ItemDataRole::DisplayRole) const override;
QVariant data(const QModelIndex &index, int role = Qt::ItemDataRole::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &) const override { return createIndex(row, column); }
QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); }
Qt::ItemFlags flags(const QModelIndex &modelIndex) const override;
QModelIndex index(int row, int column) const { return index(row, column, QModelIndex()); }
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
Qt::DropActions supportedDragActions() const override { return Qt::CopyAction | Qt::MoveAction; }
Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; }
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &) override;
/**
@}
*/
struct PlanItem
{
int m_keyId = -1;
int m_folderId = -1;
int m_fileId = -1;
int m_exerciseId = -1;
int m_phaseId = -1;
QString m_dirPath;
QString m_fileName;
double m_minScale = 0.0;
double m_maxScale = 0.0;
double m_opacity = 0.0;
bool m_visibility = true;
bool isValid() const { return m_keyId > 0; }
QJsonObject toJson() const
{
QJsonObject obj;
obj[QStringLiteral("keyId")] = m_keyId;
obj[QStringLiteral("folderId")] = m_folderId;
obj[QStringLiteral("fileId")] = m_fileId;
obj[QStringLiteral("fileName")] = m_fileName;
obj[QStringLiteral("exerciseId")] = m_exerciseId;
obj[QStringLiteral("phaseId")] = m_phaseId;
obj[QStringLiteral("opacity")] = m_opacity;
obj[QStringLiteral("maxScale")] = m_maxScale;
obj[QStringLiteral("minScale")] = m_minScale;
obj[QStringLiteral("visibility")] = m_visibility;
return obj;
}
static PlanItem fromJson(const QJsonObject &obj)
{
PlanItem pi;
pi.m_keyId = obj[QStringLiteral("keyId")].toInt();
pi.m_folderId = obj[QStringLiteral("folderId")].toInt();
pi.m_fileId = obj[QStringLiteral("fileId")].toInt();
pi.m_fileName = obj[QStringLiteral("fileName")].toInt();
pi.m_exerciseId = obj[QStringLiteral("exerciseId")].toInt();
pi.m_phaseId = obj[QStringLiteral("phaseId")].toInt();
pi.m_opacity = obj[QStringLiteral("opacity")].toDouble();
pi.m_maxScale = obj[QStringLiteral("maxScale")].toDouble();
pi.m_minScale = obj[QStringLiteral("minScale")].toDouble();
pi.m_visibility = obj[QStringLiteral("visibility")].toBool();
return pi;
}
}; // PlanItem
QMap<unsigned int, PlanItem> planStore() const;
PlanItem planItem(int keyId);
PlanItem planItemValue(int keyId);
PlanItem planItemAtRow(int row);
PlanItem findPlanItemByFileId(int fileId);
int getRowOfId(int keyId) const;
void updatePlanItem(const PlanItem &planItem);
void renewPlanItem(const PlanItem &planItem);
void setMinScale(int row, double scale);
void setMaxScale(int row, double scale);
void setOpacity(int row, double opacity);
void swapRow(int row1, int row2);
void removeOverlay(int keyId);
void setFileDialogMimeType(const QString &mimeType);
void updateOverlay(int keyId);
bool reInitModel(int exerciseId, int phaseId);
void updateOrderOfPlans() const;
QJsonArray toJson() const;
signals:
void requestLoadPlan(int keyId);
void requestReloadPlan(int keyId);
void requestUpdatePlan(int keyId);
void requestRemovePlan(int keyId);
void requestReloadPlanByName(const PlanOverlaysPlugin::PlanOverlayModel::PlanItem &planItem, int exerciseId, int phaseId, bool *removeFromModel);
void planMinScaleChanged(int keyId, double minScale);
void planMaxScaleChanged(int keyId, double maxScale);
void planOpacityChanged(int keyId, double opacity);
void planOrderChanged(const QVector<int> &newIdOrder);
void dropPlanAccepted();
private:
PlanItem &planItemRef(int keyId);
class InternalData;
InternalData *m_internal;
NGL::INGLLogger &m_logger;
}; // PlanOverlayModel
} // namespace PlanOverlaysPlugin
+621
View File
@@ -0,0 +1,621 @@
/**
**
** @RDE_HEADER@
** plan_overlay_view.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 11.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "plan_overlay_view.h"
#include "plan_overlay_model.h"
#include <LtsWidgets/lts_drag_icon.h>
#include <QtCore/QByteArray>
#include <QtGui/QGuiApplication>
#include <QtGui/QPainter>
#include <QtGui/QTransform>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSlider>
#include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
namespace PlanOverlaysPlugin
{
class WidgetItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
private:
PlanOverlayView *m_planOverlayView;
mutable QMap<QByteArray, QWidget *> m_widgetMap;
mutable QMap<QByteArray, QSize> m_sizeHints;
QByteArray buildKey(const QModelIndex &index) const
{
return QByteArray::number(index.row()) + ',' + QByteArray::number(index.column());
} // QByteArray buildKey(const QModelIndex & index) const
void removeKey(const QByteArray &indexKey, QObject *qobj) const
{
QWidget *widget = qobject_cast<QWidget *>(qobj);
if (nullptr == widget) return;
if (!m_widgetMap.contains(indexKey)) return;
if (widget != m_widgetMap[indexKey]) return;
// qCritical() << "remove key " << indexKey << " --> " << widget;
m_sizeHints.remove(indexKey);
m_widgetMap.remove(indexKey);
} // removeKey
public:
explicit WidgetItemDelegate(PlanOverlayView *planOverlayView) : QStyledItemDelegate(planOverlayView), m_planOverlayView(planOverlayView) {;}
~WidgetItemDelegate() = default;
void destroyEditor(QWidget *editor, const QModelIndex &index) const override
{
if (!index.isValid()) return;
if (m_planOverlayView->model()->rowCount() <= index.row()) return; // do not destroy will be needed again
const QByteArray &indexKey = buildKey(index);
removeKey(indexKey, editor);
if (editor) editor-> deleteLater();
// qCritical() << "Destroy widget " << indexKey << " --> " << editor;
} // void destroyEditor(QWidget* editor, const QModelIndex & index) const
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
const QByteArray &indexKey = buildKey(index);
const QVariant &modelData = index.model()->data(index, Qt::DisplayRole);
if (m_widgetMap.contains(indexKey))
{
QWidget *w = m_widgetMap[indexKey];
removeKey(indexKey, w);
if (w) w->deleteLater();
}
const QString &backgroundStyle = QStringLiteral("background-color: %1; color: %2; border:none;").arg(QGuiApplication::palette().color(QPalette::ColorRole::Base).name(),
m_planOverlayView->palette().text().color().name());
const QString &backgroundDisabledStyle = QStringLiteral("background-color: %1; color: %2; border:none;").arg(QGuiApplication::palette().color(QPalette::ColorGroup::Disabled, QPalette::ColorRole::Base).name(),
m_planOverlayView->palette().text().color().name());
const QString &buttonStyleSheet = QStringLiteral("QPushButton:!disabled {%1}\nQPushButton:disabled {%2}").arg(backgroundStyle, backgroundDisabledStyle);
switch (static_cast<PlanOverlayModel::ColumnSection>(index.column()))
{
case PlanOverlayModel::ColumnSection::OrderButtons:
{
if (index.model()->rowCount() > 1)
{
QWidget *orderButtons = new QWidget(parent);
QVBoxLayout *orderLayout = new QVBoxLayout(orderButtons);
QPixmap icon(QStringLiteral("icon:media-vcr-normal.svg")); // better use up and down buttons
LtsWidgets::LtsDragIcon *up = nullptr;
if (index.row() > 0)
{
up = new LtsWidgets::LtsDragIcon(orderButtons);
//up->setIcon(QIcon(QStringLiteral("icon:overlay_up.svg"))); // looks not very nice --> use simple arrow
up->setIcon(QIcon(icon.transformed(QTransform().rotate(-90).scale(0.5, 0.5))));
up->setText(QString());
up->setIconSize(LtsWidgets::ButtonSize::eDefault);
up->setButtonStyle(LtsWidgets::ButtonStyle::eIconOnly);
up->setProperty("row", index.row());
up->setToolTip(tr("Move layer up in display order"));
connect(up, &LtsWidgets::LtsDragIcon::clicked, m_planOverlayView, &PlanOverlayView::onChangeLayerOrderUp);
}
LtsWidgets::LtsDragIcon *down = nullptr;
if ((index.row() + 1) < index.model()->rowCount())
{
down = new LtsWidgets::LtsDragIcon(orderButtons);
//down->setIcon(QIcon(QStringLiteral("icon:overlay_down.svg"))); // looks not very nice --> use simple arrow
down->setIcon(QIcon(icon.transformed(QTransform().rotate(90).scale(0.5, 0.5))));
down->setText(QString());
down->setIconSize(LtsWidgets::ButtonSize::eDefault);
down->setButtonStyle(LtsWidgets::ButtonStyle::eIconOnly);
down->setProperty("row", index.row());
down->setToolTip(tr("Move layer down in display order"));
connect(down, &LtsWidgets::LtsDragIcon::clicked, m_planOverlayView, &PlanOverlayView::onChangeLayerOrderDown);
}
orderLayout->addStretch();
orderLayout->addSpacing(5);
if (up) orderLayout->addWidget(up);
if (down) orderLayout->addWidget(down);
orderLayout->addSpacing(5);
orderLayout->addStretch();
orderButtons->setAutoFillBackground(true);
connect(orderButtons, &QObject::destroyed, orderButtons, [this, indexKey](QObject * qobj) { removeKey(indexKey, qobj); });
m_sizeHints[indexKey] = orderButtons->sizeHint();
m_widgetMap[indexKey] = orderButtons;
// qCritical() << "setup " << indexKey << " --> " << orderButtons;
return orderButtons;
}
break;
};
case PlanOverlayModel::ColumnSection::PlanName:
{
QLabel *laName = new QLabel(modelData.toString(), parent);
laName->setAlignment(Qt::AlignCenter);
laName->setStyleSheet(QStringLiteral("QLabel:!disabled {%1}\nQLabel:disabled {%2}").arg(backgroundStyle, backgroundDisabledStyle));
m_sizeHints[indexKey] = laName->sizeHint();
m_widgetMap[indexKey] = laName;
return laName;
};
case PlanOverlayModel::ColumnSection::MinScale:
{
QPushButton *pbScaleMin = new QPushButton(parent);
pbScaleMin->setStyleSheet(buttonStyleSheet);
pbScaleMin->setPalette(m_planOverlayView->palette());
pbScaleMin->setAutoFillBackground(true);
pbScaleMin->setProperty("row", index.row());
pbScaleMin->setText(modelData.toString());
pbScaleMin->setToolTip(tr("Get minimum scale from current map settings to limit zoom out"));
connect(pbScaleMin, &QPushButton::clicked, m_planOverlayView, &PlanOverlayView::onSetMinScale);
connect(pbScaleMin, &QObject::destroyed, pbScaleMin, [this, indexKey](QObject * qobj) { removeKey(indexKey, qobj); });
m_sizeHints[indexKey] = pbScaleMin->sizeHint();
m_widgetMap[indexKey] = pbScaleMin;
// qCritical() << "setup " << indexKey << " --> " << pbScaleMin;
return pbScaleMin;
};
case PlanOverlayModel::ColumnSection::MaxScale:
{
QPushButton *pbScaleMax = new QPushButton(parent);
pbScaleMax->setStyleSheet(buttonStyleSheet);
pbScaleMax->setAutoFillBackground(true);
pbScaleMax->setProperty("row", index.row());
pbScaleMax->setText(modelData.toString());
pbScaleMax->setToolTip(tr("Get maximum scale from current map settings to limit zoom in"));
connect(pbScaleMax, &QPushButton::clicked, m_planOverlayView, &PlanOverlayView::onSetMaxScale);
connect(pbScaleMax, &QObject::destroyed, pbScaleMax, [this, indexKey](QObject * qobj) { removeKey(indexKey, qobj); });
m_sizeHints[indexKey] = pbScaleMax->sizeHint();
m_widgetMap[indexKey] = pbScaleMax;
// qCritical() << "setup " << indexKey << " --> " << pbScaleMax;
return pbScaleMax;
};
case PlanOverlayModel::ColumnSection::Opacity:
{
QSlider *slOpacity = new QSlider(parent);
slOpacity->setAutoFillBackground(true);
slOpacity->setOrientation(Qt::Horizontal);
slOpacity->setRange(0, 100);
slOpacity->setValue(int(modelData.toDouble() * 100));
slOpacity->setProperty("row", index.row());
slOpacity->setToolTip(tr("Adjust overlays opacity"));
connect(slOpacity, &QSlider::sliderMoved, m_planOverlayView, &PlanOverlayView::onChangeLayerOpacity);
connect(slOpacity, &QObject::destroyed, slOpacity, [this, indexKey](QObject * qobj) { removeKey(indexKey, qobj); });
m_sizeHints[indexKey] = slOpacity->sizeHint();
m_widgetMap[indexKey] = slOpacity;
return slOpacity;
};
case PlanOverlayModel::ColumnSection::CustomSection:
{
QWidget *containerWidget = new QWidget(parent);
QVBoxLayout *layout = new QVBoxLayout(containerWidget);
QHBoxLayout *layoutBtnRow = new QHBoxLayout();
LtsWidgets::LtsDragIcon *pbReload = new LtsWidgets::LtsDragIcon(containerWidget);
pbReload->setIcon(QPixmap(QStringLiteral("icon:overlay_reload_plan.svg")));
pbReload->setText(QString());
pbReload->setIconSize(LtsWidgets::ButtonSize::eDefault);
pbReload->setButtonStyle(LtsWidgets::ButtonStyle::eIconOnly);
pbReload->setProperty("row", index.row());
pbReload->setAutoFillBackground(true);
pbReload->setToolTip(tr("Reload plan"));
LtsWidgets::LtsDragIcon *pbUnload = new LtsWidgets::LtsDragIcon(containerWidget);
pbUnload->setIcon(QPixmap(QStringLiteral("icon:overlay_unload_plan.svg")));
pbUnload->setText(QString());
pbUnload->setIconSize(LtsWidgets::ButtonSize::eDefault);
pbUnload->setButtonStyle(LtsWidgets::ButtonStyle::eIconOnly);
pbUnload->setProperty("row", index.row());
pbUnload->setAutoFillBackground(true);
pbUnload->setToolTip(tr("Unload plan and remove overlayer"));
layoutBtnRow->addWidget(pbReload);
layoutBtnRow->addWidget(pbUnload);
layout->addStretch(2);
layout->addLayout(layoutBtnRow);
layout->addStretch(2);
containerWidget->setAutoFillBackground(true);
connect(pbReload, &LtsWidgets::LtsDragIcon::clicked, m_planOverlayView, &PlanOverlayView::onReloadOverlayById);
connect(pbUnload, &LtsWidgets::LtsDragIcon::clicked, m_planOverlayView, &PlanOverlayView::onUnloadOverlay);
m_sizeHints[indexKey] = containerWidget->sizeHint();
m_widgetMap[indexKey] = containerWidget;
return containerWidget;
};
case PlanOverlayModel::ColumnSection::ExerciseId:
case PlanOverlayModel::ColumnSection::PhaseId:
break;
} // switch
const QString &labelText = m_planOverlayView->model()->data(index, Qt::ItemDataRole::DisplayRole).toString();
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
int labelWidth = option.fontMetrics.width(labelText);
#else
int labelWidth = option.fontMetrics.horizontalAdvance(labelText);
#endif
labelWidth = (option.rect.width() > labelWidth) ? option.rect.width() : labelWidth + labelWidth / 5;
m_sizeHints[indexKey] = QSize(labelWidth, option.rect.height());
return nullptr;
} // QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
const QByteArray &indexKey = buildKey(index);
if (m_widgetMap.contains(indexKey))
{
QWidget *w = m_widgetMap[indexKey];
if (w)
{
w->setGeometry(option.rect);
painter->drawPixmap(option.rect.x(), option.rect.y(), w->grab());
return;
}
}
QStyledItemDelegate::paint(painter, option, index);
} // void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
Q_UNUSED(option);
const QByteArray &indexKey = buildKey(index);
return (m_sizeHints.contains(indexKey)) ? m_sizeHints[indexKey] : QSize();
} // QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
void setEditorData(QWidget *editor, const QModelIndex &index) const override
{
const QVariant &modelData = index.model()->data(index, Qt::ItemDataRole::DisplayRole);
switch (static_cast<PlanOverlayModel::ColumnSection>(index.column()))
{
case PlanOverlayModel::ColumnSection::PlanName:
{
QLabel *laName = qobject_cast<QLabel *>(editor);
if (laName) laName->setText(modelData.toString());
break;
}
case PlanOverlayModel::ColumnSection::MinScale:
{
QPushButton *pbMinScale = qobject_cast<QPushButton *>(editor);
if (pbMinScale) pbMinScale->setText(modelData.toString());
break;
}
case PlanOverlayModel::ColumnSection::MaxScale:
{
QPushButton *pbMaxScale = qobject_cast<QPushButton *>(editor);
if (pbMaxScale) pbMaxScale->setText(modelData.toString());
break;
}
case PlanOverlayModel::ColumnSection::Opacity:
{
QSlider *slOpacity = qobject_cast<QSlider *>(editor);
if (slOpacity) slOpacity->setValue(int(modelData.toDouble() * 100));
break;
}
case PlanOverlayModel::ColumnSection::ExerciseId:
case PlanOverlayModel::ColumnSection::PhaseId:
case PlanOverlayModel::ColumnSection::OrderButtons:
case PlanOverlayModel::ColumnSection::CustomSection:
break;
}
} // void setEditorData(QWidget * editor, const QModelIndex & index) const
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
{
Q_UNUSED(editor);
Q_UNUSED(model);
Q_UNUSED(index);
} // void setModelData(QWidget * editor, QAbstractItemModel * model; const QModelIndex & index) const
}; // WidgetItemDelegate
PlanOverlayView::PlanOverlayView(PlanOverlayModel *model, QWidget *parent)
: QTableView(parent)
{
setModel(model);
connect(model, &PlanOverlayModel::dropPlanAccepted, this, [this]()
{
setCurrentIndex(QModelIndex());
PlanOverlayView::clearSelection();
});
connect (model, &PlanOverlayModel::layoutChanged, this, &PlanOverlayView::onLayoutChanged);
setSelectionMode(SelectionMode::SingleSelection); // selection have to be enabled to get drag working
setSelectionBehavior(SelectionBehavior::SelectRows);
setItemDelegate(new WidgetItemDelegate(this));
setEditTriggers(QAbstractItemView::AllEditTriggers);
setDragEnabled(true);
setAcceptDrops(true);
setDragDropMode(QAbstractItemView::DragDrop);
setDragDropOverwriteMode(false);
setDropIndicatorShown(true);
setSortingEnabled(false);
setShowGrid(false);
horizontalHeader()->setSectionResizeMode(int(PlanOverlayModel::ColumnSection::PlanName), QHeaderView::ResizeMode::Stretch);
resizeColumnsToContents();
resizeRowsToContents();
horizontalHeader()->reset();
//allways persistent editor
onLayoutChanged();
} // PlanOverlayView::PlanOverlayView()
PlanOverlayView::~PlanOverlayView()
{
} // PlanOverlayView::~PlanOverlayView()
void PlanOverlayView::onLayoutChanged()
{
clearSelection();
if (model() != nullptr)
{
for (int row = 0; row < model()->rowCount(); ++row)
{
for (int col = 0; col < model()->columnCount(); ++col)
openPersistentEditor(model()->index(row, col, QModelIndex()));
}
}
resizeRowsToContents();
resizeColumnsToContents();
horizontalHeader()->setSectionResizeMode(int(PlanOverlayModel::ColumnSection::PlanName), QHeaderView::ResizeMode::Stretch);
} // void PlanOverlayView::updateGeometries()
int PlanOverlayView::getPlanKeyIdOfRow(int row) const
{
PlanOverlayModel *poModel = dynamic_cast<PlanOverlayModel *>(model());
if (nullptr == poModel) return -1;
if (row < 0) return -1;
if (row >= poModel->rowCount(QModelIndex())) return -1;
const PlanOverlayModel::PlanItem &planItem = poModel->planItemAtRow(row);
return (planItem.isValid()) ? planItem.m_keyId : -1;
} // int PlanOverlayView::getPlanKeyIdOfRow(int row) const
QString PlanOverlayView::getPlanNameOfRow(int row) const
{
PlanOverlayModel *poModel = dynamic_cast<PlanOverlayModel *>(model());
if (nullptr == poModel) return QString();
if (row < 0) return QString();
if (row >= poModel->rowCount(QModelIndex())) return QString();
const PlanOverlayModel::PlanItem &planItem = poModel->planItemAtRow(row);
return (planItem.isValid()) ? planItem.m_fileName : QString();
} // int PlanOverlayView::getPlanNameOfRow(int row) const
void PlanOverlayView::onSetMinScale()
{
QPushButton *senderButton = qobject_cast<QPushButton *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
int keyId = getPlanKeyIdOfRow(row);
if (keyId < 0) return;
emit requestMinScale(keyId, model()->data(model()->index(row, int(PlanOverlayModel::ColumnSection::PlanName), QModelIndex()), Qt::ItemDataRole::DisplayRole).toString());
} // void PlanOverlayView::onSetMinScale()
void PlanOverlayView::onSetMaxScale()
{
QPushButton *senderButton = qobject_cast<QPushButton *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
int keyId = getPlanKeyIdOfRow(row);
if (keyId < 0) return;
emit requestMaxScale(keyId, model()->data(model()->index(row, int(PlanOverlayModel::ColumnSection::PlanName), QModelIndex()), Qt::ItemDataRole::DisplayRole).toString());
} // void PlanOverlayView::onSetMaxScale()
void PlanOverlayView::onReloadOverlayById()
{
LtsWidgets::LtsDragIcon *senderButton = qobject_cast<LtsWidgets::LtsDragIcon *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
int keyId = getPlanKeyIdOfRow(row);
if (keyId < 0) return;
emit requestReloadPlanById(keyId);
} // void PlanOverlayView::onReloadOverlayById()
void PlanOverlayView::onReloadOverlayByName()
{
LtsWidgets::LtsDragIcon *senderButton = qobject_cast<LtsWidgets::LtsDragIcon *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
QString planName = getPlanNameOfRow(row);
if (planName.isEmpty()) return;
emit requestReloadPlanByName(planName);
} // void PlanOverlayView::onReloadOverlayById()
void PlanOverlayView::onUnloadOverlay()
{
LtsWidgets::LtsDragIcon *senderButton = qobject_cast<LtsWidgets::LtsDragIcon *>(sender());
if (nullptr == senderButton) return;
int keyId = getPlanKeyIdOfRow(senderButton->property("row").toInt());
if (keyId >= 0)
emit requestUnloadPlan(keyId);
} // void PlanOverlayView::onUnloadOverlay()
void PlanOverlayView::onChangeLayerOpacity(int sliderValue)
{
QSlider *senderSlider = qobject_cast<QSlider *>(sender());
if (nullptr == senderSlider) return;
int row = senderSlider->property("row").toInt();
PlanOverlayModel *poModel = dynamic_cast<PlanOverlayModel *>(model());
if (nullptr == poModel) return;
if (row < 0) return;
if (row >= poModel->rowCount(QModelIndex())) return;
poModel->setOpacity(row, double(sliderValue) / 100.0);
} // void PlanOverlayView::onChangeLayerOpacity(int sliderValue)
void PlanOverlayView::onChangeLayerOrderUp()
{
LtsWidgets::LtsDragIcon *senderButton = qobject_cast<LtsWidgets::LtsDragIcon *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
PlanOverlayModel *poModel = dynamic_cast<PlanOverlayModel *>(model());
if (nullptr == poModel) return;
if (row < 1) return;
if (row >= poModel->rowCount(QModelIndex())) return;
poModel->swapRow(row, row - 1);
} // void PlanOverlayView::onChangeLayerOrderUp()
void PlanOverlayView::onChangeLayerOrderDown()
{
LtsWidgets::LtsDragIcon *senderButton = qobject_cast<LtsWidgets::LtsDragIcon *>(sender());
if (nullptr == senderButton) return;
int row = senderButton->property("row").toInt();
PlanOverlayModel *poModel = dynamic_cast<PlanOverlayModel *>(model());
if (nullptr == poModel) return;
if (row < 0) return;
if (row + 1 >= poModel->rowCount(QModelIndex())) return;
poModel->swapRow(row, row + 1);
} // void PlanOverlayView::onChangeLayerOrderDown()
} // namespace PlanOverlaysPlugin
#include <plan_overlay_view.moc>
+77
View File
@@ -0,0 +1,77 @@
/**
**
** @RDE_HEADER@
** plan_overlay_view.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 11.07.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtWidgets/QTableView>
namespace PlanOverlaysPlugin
{
class PlanOverlayModel;
class PlanOverlayView final : public QTableView
{
Q_OBJECT
public:
explicit PlanOverlayView(PlanOverlayModel *model, QWidget *parent = nullptr);
~PlanOverlayView();
signals:
void requestReloadPlanById(int planId);
void requestReloadPlanByName(const QString &planName);
void requestUnloadPlan(int planId);
void requestMinScale(int planId, const QString &planName);
void requestMaxScale(int planId, const QString &planName);
public slots:
void onSetMinScale();
void onSetMaxScale();
void onChangeLayerOrderUp();
void onChangeLayerOrderDown();
void onChangeLayerOpacity(int);
void onReloadOverlayById();
void onReloadOverlayByName();
void onUnloadOverlay();
protected:
void onLayoutChanged();
int getPlanKeyIdOfRow(int row) const;
QString getPlanNameOfRow(int row) const;
}; // PlanOverlayView
} // namespace PlanOverlaysPlugin
+954
View File
@@ -0,0 +1,954 @@
/**
**
** @RDE_HEADER@
** plan_editor_gui_plugin.cpp
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 24.04.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "plan_overlays_gui_plugin.h"
#include "plan_overlay_model.h"
#include "plan_overlay_dialog.h"
#include "TopicEditor/topic_editor.h"
#include "flm_reply_handler.h"
#include <LtsUtilsCore/pgarray.h>
#include <LtsUtilsCore/dds_vector.h>
#include <NGLLogger/INGLLogger.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <PluginInterfaces/style_plugin_interface.h>
#include <PluginInterfaces/project_plugin_interface.h>
#include <Services/OperatorManagement/opm_dtc.h>
#include <Services/ExerciseManagement/exm_dtc.h>
#include <Services/PlanEditor/ped_operator_rights.h>
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/FileManagement/Gui/Explorer/TopicEditor/topic_editor.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Viewer/SituationMap/Map/map.h>
#include <Viewer/SituationMap/GeometryModel/geometry_model_factory.h>
#include <QCoreApplication>
#include <QDateTime>
#include <QFile>
#include <QPointer>
#include <QStandardPaths>
#include <QHBoxLayout>
#include <QMainWindow>
#include <QtGlobal>
#include <QDebug>
#include <iostream>
namespace PlanOverlaysPlugin
{
std::shared_ptr<GuiPluginBase::Interface> PlanOverlaysGuiPlugin::createGuiInterface(LtsSession::LtsSession * session)
{
return std::make_shared<InterfaceImpl>(session);
}
static NGL::INGLLogger &getLogger()
{
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PlanOverLaysPlugin");
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
class InterfaceImpl::InternalData
{
public:
FileManagement::FileContent m_planContent;
std::shared_ptr<FileManagement::Interface::Dtc> m_dtc;
std::shared_ptr<FileManagement::Interface::Ftc> m_ftc;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
LtsUtils::RequestHelper * m_requestHelper;
FileManagementReplyHandler * m_flmReplyHandler;
PlanOverlayModel * m_overlayModel;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_situationMapGui;
SituationMap::ForeignGuiInterface * m_foreignSitmapIfc;
QString m_messageBoxTitle;
InternalData()
: m_requestHelper(nullptr)
, m_flmReplyHandler(nullptr)
, m_overlayModel(nullptr)
, m_foreignSitmapIfc(nullptr)
{} // InternalData
~InternalData() = default;
};
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession * session)
: QObject()
, GuiPluginBase::Interface(session, getLogger())
, m_internal(new InternalData())
, m_foreignIfc(nullptr)
{
m_internal->m_requestHelper = new LtsUtils::RequestHelper(this);
m_internal->m_flmReplyHandler = new FileManagementReplyHandler(m_internal->m_requestHelper);
m_internal->m_messageBoxTitle = tr("Plan Overlays");
}
bool InterfaceImpl::fetchInterfaces()
{
// Initialize file mamangement
if (!m_session->getDtc<FileManagement::DataInterface>(m_internal->m_dtc))
{
DEBUG_LOG(m_logger) << "getDtc for FileManagement::DataInterface failed.";
return false;
}
if (!m_session->getDtc<OperatorManagement::DataInterface>(m_internal->m_opmDtc))
{
DEBUG_LOG(m_logger) << "getDtc for OperatorManagement::DataInterface failed.";
return false;
}
if (!m_session->getDtc<ExerciseManagement::DataInterface>(m_internal->m_exmDtc))
{
DEBUG_LOG(m_logger) << "getDtc for ExerciseManagement::DataInterface failed.";
return false;
}
if (!m_session->getFtc<FileManagement::DataInterface>(m_internal->m_ftc))
{
DEBUG_LOG(m_logger) << "getFtc for FileManagement::DataInterface failed.";
return false;
}
if (!m_session->getForeignGuiInterface(m_internal->m_situationMapGui))
{
DEBUG_LOG(m_logger) << "getForeignGuiInterface for SituationMap::ForeignGuiInterface failed.";
return false;
}
m_internal->m_foreignSitmapIfc = m_internal->m_situationMapGui.get();
delete m_internal->m_overlayModel;
m_internal->m_overlayModel = new PlanOverlayModel();
connect(m_internal->m_overlayModel, &PlanOverlayModel::requestLoadPlan , this, &InterfaceImpl::loadPlanByUser, Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::requestUpdatePlan , this, &InterfaceImpl::onUpdatePlan , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::requestRemovePlan , this, QOverload<int>::of(&InterfaceImpl::removePlan) , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::planMinScaleChanged , this, &InterfaceImpl::onChangePlanMinScaleOnMap , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::planMaxScaleChanged , this, &InterfaceImpl::onChangePlanMaxScaleOnMap , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::planOpacityChanged , this, &InterfaceImpl::onChangePlanOpacityOnMap , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::planOrderChanged , this, &InterfaceImpl::onChangePlanOrderOnMap , Qt::ConnectionType::DirectConnection);
connect(m_internal->m_overlayModel, &PlanOverlayModel::requestReloadPlanByName, this, &InterfaceImpl::onReloadPlanByName, static_cast<Qt::ConnectionType>(Qt::DirectConnection|Qt::UniqueConnection));
m_internal->m_ftc->enableFileContentModify();
m_internal->m_ftc->enableGetFileContentData();
connect(m_internal->m_dtc.get(), &FileManagement::Interface::Dtc::fileContentChanged, this, &InterfaceImpl::onPlanContentChanged, Qt::UniqueConnection);
connect(m_internal->m_exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged, this, &InterfaceImpl::onExerciseChanged, Qt::UniqueConnection);
return true;
}
void InterfaceImpl::setForeignSitMapGuiIfc(SituationMap::ForeignGuiInterface *foreignSitmapIfc)
{
//qWarning() << (void *)this << "setSitMapGuiIfc";
m_internal->m_foreignSitmapIfc = foreignSitmapIfc;
}
void InterfaceImpl::setForeignPlanOverlaysGuiIfc(ForeignGuiInterface *ifc)
{
m_foreignIfc = ifc;
}
void InterfaceImpl::clearInterfaces()
{
if (!m_internal)
return;
m_internal->m_dtc.reset();
m_internal->m_opmDtc.reset();
m_internal->m_exmDtc.reset();
m_internal->m_ftc.reset();
m_internal->m_situationMapGui.reset();
m_internal->m_foreignSitmapIfc = nullptr; // it's just a raw pointer
}
PlanOverlayModel *InterfaceImpl::planOverlayModel()
{
return m_internal->m_overlayModel;
}
bool InterfaceImpl::loadPlanByUser(int planFileId)
{
return loadPlan(planFileId, true, nullptr);
}
bool InterfaceImpl::loadPlan(int planFileId)
{
return loadPlan(planFileId, QJsonObject());
}
bool InterfaceImpl::loadPlan(int planFileId, const QJsonObject &planItemObject)
{
return loadPlan(planFileId, false, nullptr, planItemObject);
}
bool InterfaceImpl::loadPlan(int planFileId,
bool applyMinMaxScaleOfMetadata,
SituationMap::ForeignGuiInterface* overrideSitMapIfc,
const QJsonObject &planItemObject)
{
// Important: the parameter planFileId is the file id of the plan in FMS and NOT the planKeyId !!!!!
if (overrideSitMapIfc == nullptr)
overrideSitMapIfc = m_internal->m_foreignSitmapIfc;
if (overrideSitMapIfc == nullptr) // still paranoid
{
ERROR_LOG(m_logger) << "no sit map ifc to load a plan on!";
return false;
}
// NLDEVCTRL-1414:
// Pläne/Overlays wiederherstellen schlug fehl nach Aus-/Einloggen
m_internal->m_dtc->waitForHistoricalDataFileContent(5000);
FileManagement::FileContent fileContent = m_internal->m_dtc->fileContent(planFileId);
// TODO: FIXME: but normally 0 is a valid id ?!
if (fileContent.id() <= 0) // not found
{
ERROR_LOG(m_logger) << "Could not find plan with id " << planFileId << " in filemanagement - removing";
return false;
}
QString nameOfPlan = QString::fromStdString(fileContent.name());
std::function<void(const Core::FunctionReply &baseReply)> handleContent = [this, fileContent, applyMinMaxScaleOfMetadata, nameOfPlan, overrideSitMapIfc, planItemObject](const Core::FunctionReply &)
{
const QByteArray &planXMLContent = LtsUtils::toQByteArray(m_internal->m_flmReplyHandler->getContent());
int planFileId = fileContent.id();
// use 'planId' as 'id' (internal name: key)
if (!overrideSitMapIfc->planOverlaySetContent(planFileId, nameOfPlan, planXMLContent))
{
ERROR_LOG(m_logger) << "no sit map ifc to load a plan on!";
return false;
}
PlanOverlaysPlugin::PlanOverlayModel::PlanItem planItem = m_internal->m_overlayModel->findPlanItemByFileId(planFileId);
if (!planItem.isValid())
planItem = m_internal->m_overlayModel->planItem(-1);
planItem.m_folderId = fileContent.folderId();
if (fileContent.exerciseId().is_set())
{
planItem.m_exerciseId = fileContent.exerciseId().get();
if (fileContent.phaseId().is_set())
planItem.m_phaseId = fileContent.phaseId().get();
}
planItem.m_fileId = planFileId;
planItem.m_fileName = nameOfPlan;
if (applyMinMaxScaleOfMetadata)
{
QScopedPointer<SituationMap::GeometryModel> geoModel(SituationMap::GeometryModelFactory::singleton()->create());
if (geoModel->fromByteArray(planXMLContent))
{
const QString &minScaleStr = geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataMinScale).toString();
const QString &maxScaleStr = geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataMaxScale).toString();
bool ok = false;
double minScale = minScaleStr.toDouble(&ok);
if (ok)
planItem.m_minScale = minScale;
else
planItem.m_minScale = 0.0;
double maxScale = maxScaleStr.toDouble(&ok);
if (ok)
planItem.m_maxScale = maxScale;
else
planItem.m_maxScale = 0.0;
DEBUG_LOG(m_logger) << " load plan and set minMaxScale:"
<< " minScaleStr = " << minScaleStr
<< " maxScaleStr = " << maxScaleStr
<< " planItem.m_minScale = " << planItem.m_minScale
<< " planItem.m_maxScale = " << planItem.m_maxScale;
overrideSitMapIfc->setPlanOverlayMinScale(planFileId, planItem.m_minScale);
overrideSitMapIfc->setPlanOverlayMaxScale(planFileId, planItem.m_maxScale);
}
}
if (planItemObject.isEmpty())
{
// Get plan settings from SituationMap and store them as initial value in plan item
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
planItem.m_opacity = overrideSitMapIfc->planOverlayOpacity(planFileId);
planItem.m_maxScale = overrideSitMapIfc->planOverlayMaxScale(planFileId);
planItem.m_minScale = overrideSitMapIfc->planOverlayMinScale(planFileId);
planItem.m_visibility = overrideSitMapIfc->planOverlayVisibility(planFileId);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
else
{
planItem.m_opacity = planItemObject[QStringLiteral("opacity")].toDouble(0.);
planItem.m_maxScale = planItemObject[QStringLiteral("maxScale")].toDouble(0.);
planItem.m_minScale = planItemObject[QStringLiteral("minScale")].toDouble(0.);
planItem.m_visibility = planItemObject[QStringLiteral("visibility")].toBool(true);
overrideSitMapIfc->setPlanOverlayOpacity(planFileId, planItem.m_opacity);
overrideSitMapIfc->setPlanOverlayMaxScale(planFileId, planItem.m_maxScale);
overrideSitMapIfc->setPlanOverlayMinScale(planFileId, planItem.m_minScale);
overrideSitMapIfc->setPlanOverlayVisibility(planFileId, planItem.m_visibility);
}
m_internal->m_overlayModel->updatePlanItem(planItem); // Write back plan item to model
return true;
};
bool ok = m_internal->m_requestHelper->startSingleRequest([this, planFileId]()
{
FileManagement::GetFileContentDataRequest req;
req.fileContentId(planFileId);
return m_internal->m_ftc->getFileContentDataRequest(req, m_internal->m_flmReplyHandler);
}, handleContent);
return ok;
}
bool InterfaceImpl::unloadAllPlans()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
const QMap<unsigned int, PlanOverlayModel::PlanItem> &planStore = m_internal->m_overlayModel->planStore();
QMapIterator<unsigned int, PlanOverlayModel::PlanItem> mapIt(planStore);
while (mapIt.hasNext())
{
mapIt.next();
unsigned int planId = mapIt.key();
DEBUG_LOG(m_logger) << LOGFUNCTION << " removeOverlay, planId=" << planId;
// update model, signal requestRemovePlan, slot removePlan
m_internal->m_overlayModel->removeOverlay(planId);
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void InterfaceImpl::onUpdatePlan(int planId)
{
PlanOverlaysPlugin::PlanOverlayModel::PlanItem planItem = m_internal->m_overlayModel->planItemValue(planId);
if (!planItem.isValid())
{
ERROR_LOG(m_logger) << "plan item with id " << planId << " not found in model";
return;
}
int planFileId = planItem.m_fileId;
FileManagement::FileContent fileContent = m_internal->m_dtc->fileContent(planFileId);
planItem.m_fileName = QString::fromStdString(fileContent.name());
std::function<void(const Core::FunctionReply &baseReply)> handleContent = [this,planFileId,planItem](const Core::FunctionReply &baseReply)
{
const FileManagement::GetFileContentDataReply &reply = static_cast<const FileManagement::GetFileContentDataReply &>(baseReply);
const QByteArray &planXMLContent = LtsUtils::toQByteArray(reply.content());
// use 'planId' as 'id' (internal name: key)
if (!m_internal->m_foreignSitmapIfc->planOverlaySetContent(planFileId, planItem.m_fileName, planXMLContent))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error rendering planContent [" << planItem.m_fileName << "]";
return false;
}
m_internal->m_overlayModel->renewPlanItem(planItem);
return true;
}; // std::function
bool ok = m_internal->m_requestHelper->startSingleRequest([this, planFileId]()
{
FileManagement::GetFileContentDataRequest req;
req.fileContentId(planFileId);
return m_internal->m_ftc->getFileContentDataRequest(req, m_internal->m_flmReplyHandler);
}, handleContent);
if (!ok)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error reading planContent [" << planItem.m_fileName << "]";
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Reading plan '%1' from database failed").arg(planItem.m_fileName), m_internal->m_messageBoxTitle);
}
}
InterfaceImpl::~InterfaceImpl()
{
delete m_internal->m_requestHelper;
delete m_internal->m_flmReplyHandler;
delete m_internal->m_overlayModel;
delete m_internal; m_internal = nullptr;
}
QString InterfaceImpl::menuGroup() const { return tr("Situation Map"); }
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> actionVector;
{
LtsWidgets::PluginData pluginAction;
pluginAction.menuGroup = menuGroup();
pluginAction.menuText = tr("Managing Plan Overlays");
pluginAction.menuIcon = QIcon(QStringLiteral("icon:overlay_plans.svg"));
pluginAction.identifier = QStringLiteral("manage_plan_overlay");
pluginAction.tooltip = tr("Loading plan overlays, changing order of plan overlays and modifying overlay settings");
pluginAction.operatorRight = OperatorRights::PlanEditor::TacticalPlansShow;
pluginAction.exercisePart = LtsWidgets::ExercisePart::eSpecial;
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
if (m_planOverlayDialog)
{
m_planOverlayDialog->show();
m_planOverlayDialog->raise();
} else {
m_planOverlayDialog = openPlanOverlayDialog();
}
};
actionVector << pluginAction;
}
return actionVector;
}
QWidget *InterfaceImpl::openPlanOverlayDialog(const QJsonArray &planItems, bool removePlansOnClose)
{
auto doReadFile = [this](int selectedFileId) // note: parameter is fileId@FileManagement
{
if (selectedFileId > 0)
loadPlanByUser(selectedFileId);
};
auto doUnloadPlan = [this](int planId) // note: planId != fileId@FileManagement
{
if (planId > 0)
m_internal->m_overlayModel->removeOverlay(planId);
};
auto doReloadPlan = [this](int planId) // note: planId != fileId@FileManagement
{
if (planId > 0)
onReloadPlanById(planId);
};
for (const QJsonValue &planItemValue : qAsConst(planItems))
{
if (!planItemValue.isObject())
{
WARNING_LOG(m_logger) << "planItem from json array is not an object! " << planItemValue.type();
continue;
}
QJsonObject planItemObj(planItemValue.toObject());
int planFileId = planItemObj[QStringLiteral("fileId")].toInt(-1);
if (!loadPlan(planFileId, planItemObj))
ERROR_LOG(m_logger) << "could not load plan with file id " << planFileId;
}
#define USE_QDIALOG 1
#ifdef USE_QDIALOG
PlanOverlayDialog<QDialog> * overlayDialog = new PlanOverlayDialog<QDialog>(m_internal->m_foreignSitmapIfc, m_internal->m_overlayModel, m_session->baseLayout(), m_session);
#else
PlanOverlayDialog<LtsWidgets::LtsDialog> * overlayDialog = new PlanOverlayDialog<LtsWidgets::LtsDialog>(m_session, sitMapIfc, m_internal->m_overlayModel, m_session->baseLayout());
#endif
overlayDialog->dialogWidget()->initFileManagement(m_internal->m_dtc, m_internal->m_opmDtc, m_internal->m_exmDtc, doReadFile, doReloadPlan, doUnloadPlan, appId() == LtsAppDescriptor::App::OC );
overlayDialog->show();
if (removePlansOnClose)
{
connect(overlayDialog->dialogWidget(), &QObject::destroyed,
this, [this]()
{
auto planStore = m_internal->m_overlayModel->planStore();
for (auto i = planStore.constBegin(); i != planStore.constEnd(); ++i)
{
//m_internal->m_overlayModel->removeOverlay(i.key());
removePlan(i.key());
}
});
}
connect(overlayDialog->dialogWidget(), &QObject::destroyed,
this, [overlayDialog]() { delete overlayDialog; });
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* The overlay dialog will be removed automatically when the user close the dialog or when underlying map will be destroyed.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
return overlayDialog->dialogWidget();
}
void InterfaceImpl::onReloadPlanById(int planId) // note: planId != fileId@FileManagement
{
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (planItem.isValid())
{
int fileId = planItem.m_fileId;
FileManagement::FileContent fileContent = m_internal->m_dtc->fileContent(fileId);
QString nameOfPlan = QString::fromStdString(fileContent.name());
std::function<void(const Core::FunctionReply &baseReply)> handleContent = [this,planId,nameOfPlan](const Core::FunctionReply &baseReply)
{
const FileManagement::GetFileContentDataReply &reply = static_cast<const FileManagement::GetFileContentDataReply &>(baseReply);
const QByteArray &planXMLContent = LtsUtils::toQByteArray(reply.content());
if (planXMLContent.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error plan [" << nameOfPlan << "] is empty";
return false;
}
PlanOverlaysPlugin::PlanOverlayModel::PlanItem planItem = m_internal->m_overlayModel->planItem(planId);
if (!m_internal->m_foreignSitmapIfc->planOverlaySetContent(planItem.m_fileId, planItem.m_fileName, planXMLContent))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error rendering planContent [" << nameOfPlan << "]";
return false;
}
planItem.m_fileName = nameOfPlan;
planItem.m_opacity = m_internal->m_foreignSitmapIfc->planOverlayOpacity(planItem.m_fileId);
planItem.m_maxScale = m_internal->m_foreignSitmapIfc->planOverlayMaxScale(planItem.m_fileId);
planItem.m_minScale = m_internal->m_foreignSitmapIfc->planOverlayMinScale(planItem.m_fileId);
planItem.m_visibility = m_internal->m_foreignSitmapIfc->planOverlayVisibility(planItem.m_fileId);
m_internal->m_overlayModel->updatePlanItem(planItem);
return true;
};
bool ok = m_internal->m_requestHelper->startSingleRequest([this,fileId]() -> bool
{
FileManagement::GetFileContentDataRequest req;
req.fileContentId(fileId);
return m_internal->m_ftc->getFileContentDataRequest(req, m_internal->m_flmReplyHandler);
}, handleContent);
if (!ok)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error reading planContent [" << nameOfPlan << "]";
const QString & msg = tr("Reading plan '%1' from database failed").arg(nameOfPlan);
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), msg, m_internal->m_messageBoxTitle);
return;
}
}
}
bool InterfaceImpl::removePlan(int planId)
{
return removePlan(planId, nullptr);
}
bool InterfaceImpl::removePlan(int planId, SituationMap::ForeignGuiInterface* overrideSitMapIfc)
{
if (overrideSitMapIfc == nullptr)
overrideSitMapIfc = m_internal->m_foreignSitmapIfc;
if (overrideSitMapIfc == nullptr) // still paranoid
{
ERROR_LOG(m_logger) << "no sit map ifc to remove a plan from for planId " << planId;
return false;
}
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (!planItem.isValid())
{
ERROR_LOG(m_logger) << "plan item invalid for planId " << planId;
return false;
}
if (!overrideSitMapIfc->planOverlayRemove(planItem.m_fileId))
{
// HACK: try removing the playn overlay by planId, finally
if (!overrideSitMapIfc->planOverlayRemove(planId))
return false;
}
return true;
}
void InterfaceImpl::onChangePlanMinScaleOnMap(int planId, double minScale)
{
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (planItem.isValid())
m_internal->m_foreignSitmapIfc->setPlanOverlayMinScale(planItem.m_fileId, minScale);
}
void InterfaceImpl::onChangePlanMaxScaleOnMap(int planId, double maxScale)
{
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (planItem.isValid())
m_internal->m_foreignSitmapIfc->setPlanOverlayMaxScale(planItem.m_fileId, maxScale);
}
void InterfaceImpl::onChangePlanOpacityOnMap(int planId, double opacity)
{
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (planItem.isValid())
m_internal->m_foreignSitmapIfc->setPlanOverlayOpacity(planItem.m_fileId, opacity);
}
void InterfaceImpl::onChangePlanOrderOnMap(const QVector<int> &newIdOrder)
{
QVector<int> layerOrder;
// The layer in SituationMap layer factory are ordered from bottom to top. To get the correct order
// we have to change the direction of ordering in the id list ...
layerOrder.reserve(newIdOrder.size());
for (int planId : newIdOrder)
{
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem & planItem = m_internal->m_overlayModel->planItem(planId);
if (planItem.isValid())
{
layerOrder.push_front(planItem.m_fileId);
}
}
m_internal->m_foreignSitmapIfc->planOverlayChangeOrder(layerOrder);
}
void InterfaceImpl::onPlanContentChanged(const FileManagement::FileContent &data, DataModification modType)
{
if (data.fileType() != FileManagement::FileType::TacticalPlan) return;
const PlanOverlaysPlugin::PlanOverlayModel::PlanItem &planItem = m_internal->m_overlayModel->findPlanItemByFileId(data.id());
if (planItem.isValid())
{
switch (modType)
{
case DataModification::eModified : m_internal->m_overlayModel->updateOverlay(planItem.m_keyId); break;
case DataModification::eRemoved : m_internal->m_overlayModel->removeOverlay(planItem.m_keyId); break;
default: return;
}
}
}
void InterfaceImpl::onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification modType)
{
switch (modType)
{
case DataModification::eModified:
{
DEBUG_LOG(m_logger) << "onExerciseChanged - Modified";
m_internal->m_overlayModel->reInitModel(data.id(), data.activePhaseId());
break;
}
default:
break;
}
}
void InterfaceImpl::onReloadPlanByName(const PlanOverlaysPlugin::PlanOverlayModel::PlanItem &planItem, int exerciseId, int phaseId, bool *removeFromModel)
{
if (removeFromModel)
*removeFromModel = false;
if (planItem.isValid())
{
int planFileId = m_internal->m_dtc->getFileId(FileManagement::FileType::TacticalPlan, planItem.m_fileName, exerciseId, phaseId);
DEBUG_LOG(m_logger) << "Plan File Id = " << planFileId;
if (planFileId < 1)
{
if (removeFromModel) *removeFromModel = true;
INFO_LOG(m_logger) << "Plan overlay will be removed: name = " << planItem.m_fileName;
return;
}
FileManagement::FileContent fileContent = m_internal->m_dtc->fileContent(planFileId);
QString nameOfPlan = QString::fromStdString(fileContent.name());
int planId = planItem.m_keyId;
std::function<void(const Core::FunctionReply &baseReply)> handleContent = [this, planId, nameOfPlan, fileContent](const Core::FunctionReply &baseReply)
{
const FileManagement::GetFileContentDataReply &reply = static_cast<const FileManagement::GetFileContentDataReply &>(baseReply);
const QByteArray &planXMLContent = LtsUtils::toQByteArray(reply.content());
if (planXMLContent.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error plan [" << nameOfPlan << "] is empty";
return false;
}
else
{
PlanOverlaysPlugin::PlanOverlayModel::PlanItem pi = m_internal->m_overlayModel->planItem(planId); // get copy of planItem from model
// file id has changed remove the old plan first
if (!m_internal->m_foreignSitmapIfc->planOverlayRemove(pi.m_fileId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error removing plan overlay from map failed [" << nameOfPlan << "]";
}
// now load the new version of the plan
if (!m_internal->m_foreignSitmapIfc->planOverlaySetContent(fileContent.id(), nameOfPlan, planXMLContent))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error rendering planContent [" << nameOfPlan << "]";
return false;
}
// re-write rest of properties, in case fileId changed, using same file name
pi.m_fileName = nameOfPlan;
pi.m_fileId = fileContent.id();
pi.m_folderId = fileContent.folderId();
if (fileContent.exerciseId().is_set())
{
pi.m_exerciseId = fileContent.exerciseId().get();
if (fileContent.phaseId().is_set())
pi.m_phaseId = fileContent.phaseId().get();
}
// don't change the attributes opacity, minScale, maxScale and visibility
m_internal->m_overlayModel->updatePlanItem(pi);
}
return true;
};
bool ok = m_internal->m_requestHelper->startSingleRequest([this,planFileId]() -> bool
{
FileManagement::GetFileContentDataRequest req;
req.fileContentId(planFileId);
return m_internal->m_ftc->getFileContentDataRequest(req, m_internal->m_flmReplyHandler);
}, handleContent);
m_internal->m_overlayModel->updateOrderOfPlans();
if (!ok)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Error reading planContent [" << nameOfPlan << "]";
const QString & msg = tr("Reading plan '%1' from database failed").arg(nameOfPlan);
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), msg, m_internal->m_messageBoxTitle);
}
}
}
TopicEditorBase::TopicEditor *InterfaceImpl::createTopicEditor(const TopicEditorBase::TopicData &data)
{
std::shared_ptr<FileManagement::Interface::Dtc> flmDtc;
if (!m_session->getDtc<FileManagement::DataInterface>(flmDtc))
WARNING_LOG(m_logger) << "flm dtc missing - plan topic compatibility mode file name resolution not available";
PlanTopicEditor *editor = new PlanTopicEditor(&m_foreignIfc, flmDtc);
editor->setTopicData(data);
return editor;
}
TopicReplay::Interface *InterfaceImpl::createInterface(TopicEditorBase::TopicType)
{
return new TopicReplayInterface(m_internal->m_foreignSitmapIfc, this);
}
InterfaceImpl::TopicReplayInterface::TopicReplayInterface(SituationMap::ForeignGuiInterface *foreignSitmapIfc, InterfaceImpl *ovr)
: m_ovr(ovr)
, m_foreignSitmapIfc(foreignSitmapIfc)
, m_logger(getLogger())
{}
InterfaceImpl::TopicReplayInterface::~TopicReplayInterface()
{
playbackStop();
}
bool InterfaceImpl::TopicReplayInterface::playbackInit(const QJsonObject &attributes)
{
if (!m_foreignSitmapIfc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "No foreign sitMapIfc, use PlanOverlaysPlugin::ForeignGuiInterface::setForeignSitMapGuiIfc() to define SituationMapGuiPlugin interface. Can't load tactical plan for playback ...";
return false;
}
// there exist one single plan per topic, get file id of plan from attributes
int planFileId = attributes[QStringLiteral("fileId")].toInt(-1);
if (planFileId != -1) // compatibility mode
{
WARNING_LOG(m_logger) << "Plan Overlays topic in compatibility mode!";
DEBUG_LOG(m_logger) << "Loading plan id = " << planFileId;
if (!m_ovr->loadPlan(planFileId, false, m_foreignSitmapIfc))
return false;
m_loadedPlanFileIds += planFileId; // store planFileId to remove plan when playback stops
return true;
}
else
{
const auto plans = attributes[QStringLiteral("PlanItems")].toArray();
for (const QJsonValue &planItemValue : plans)
{
if (!planItemValue.isObject())
{
ERROR_LOG(m_logger) << "PlanItem from json array is not an object! " << planItemValue.type();
continue;
}
const QJsonObject planItemObj(planItemValue.toObject());
planFileId = planItemObj[QStringLiteral("fileId")].toInt(-1);
if (!m_ovr->loadPlan(planFileId, planItemObj))
{
ERROR_LOG(m_logger) << "could not load plan with file id " << planFileId;
continue;
}
m_loadedPlanFileIds += planFileId;
}
return true;
}
}
bool InterfaceImpl::TopicReplayInterface::playbackStop()
{
if (nullptr == m_foreignSitmapIfc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Use PlanOverlaysPlugin::ForeignGuiInterface::setForeignSitMapGuiIfc() to define SituationMapGuiPlugin interface ...";
return false;
}
while (!m_loadedPlanFileIds.isEmpty())
{
int planFileId = m_loadedPlanFileIds.takeFirst();
DEBUG_LOG(m_logger) << " removePlan with file id " << planFileId;
if (!m_ovr->removePlan(planFileId, m_foreignSitmapIfc)) // remove plan created in playbackInit()
ERROR_LOG(m_logger) << "could not unload plan with file id " << planFileId;
}
return true;
}
QVector<TopicEditorBase::TopicData> InterfaceImpl::TopicReplayInterface::additionalTrackEntries(const QJsonObject &attributes, bool &keepOriginalTopic) const
{
keepOriginalTopic = false;
const auto plans = attributes[QStringLiteral("PlanItems")].toArray();
QVector<TopicEditorBase::TopicData> ret;
ret.reserve(plans.size());
for (const QJsonValue &ele : plans)
{
const auto pi = PlanOverlayModel::PlanItem::fromJson(ele.toObject());
if (!pi.isValid())
continue;
TopicEditorBase::TopicData data;
data.topicType = TopicEditorBase::TopicType::TacticalPlan;
data.properties = QJsonObject({{QStringLiteral("FileId"), pi.m_fileId}});
ret += data;
}
return ret;
}
} // namespace PlanOverlaysPlugin
+253
View File
@@ -0,0 +1,253 @@
/**
**
** @RDE_HEADER@
** plan_editor_gui_plugin.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 24.04.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "plan_overlay_model.h"
#include <PluginInterfaces/gui_plugin_interface.h>
#include <TopicEditorBase/topic_editor_interface.h>
#include <Common/ProjectConfig/project_defines.h>
#include <Plugins/PlanOverlays/plan_overlays_plugin_interface.h>
#include <Plugins/FileManagement/flm_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <QObject>
namespace Core
{
class FunctionReplyObject;
}
namespace SituationMap
{
class ScriptFilterForeignGuiInterface;
}
namespace PlanOverlaysPlugin
{
/**
@class PlanEOverlaysPlugin
Implementation of plugin base to create interface instance. To use the plugin it has to be configured
in apps.json configuration file. The Type and IID habe to be set to:
- "Type": "gui"
- "IID": "planoverlays"
The PlanEditorGuiPlugin uses the file manager data plugin to read and store data with file manager service.
@see InterfaceImpl, PlanEditor, SituationMap
*/
//------------------------------------------------------------------------------
// PlanOverlaysGuiPlugin
//------------------------------------------------------------------------------
class PlanOverlaysGuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:planoverlays")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit PlanOverlaysGuiPlugin() = default;
~PlanOverlaysGuiPlugin() = default;
QString pluginName() override { return QStringLiteral("PlanOverlaysPlugin"); }
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);
}
};
//------------------------------------------------------------------------------
// InterfaceImpl
//------------------------------------------------------------------------------
class InterfaceImpl final : public QObject, public ForeignGuiInterface, public GuiPluginBase::Interface
{
Q_OBJECT
class InternalData;
InternalData *m_internal;
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
~InterfaceImpl();
QVector<LtsWidgets::PluginData> getActions() override;
QString menuGroup() const override;
bool fetchInterfaces() override;
void clearInterfaces() override;
/**
Set SituationMapGuiPlugin interface from forgein session. Is used by ScriptEditor to define map view displaying plans.
@param foreignSitMapIfc Pointer to SituationMapGuiPlugin interface used to load plan into map when used by ScriptEditor
*/
void setForeignSitMapGuiIfc(SituationMap::ForeignGuiInterface *foreignSitmapIfc) override;
void setForeignPlanOverlaysGuiIfc(ForeignGuiInterface *ifc) override;
bool loadPlanByUser(int planFileId);
/**
@brief Load a plan as overlay into map
@param planFileId File-Id of plan in file management service
@return
*/
bool loadPlan(int planFileId) override; // TODO: move to slots
/**
Load a plan as overlay into map
@param planFileId File-Id of plan in file management service
@param applyMinMaxScaleOfMetadata The xmlContent may contain minScale, maxScale. Apply them?
*/
bool loadPlan(int planFileId, const QJsonObject &planItemObject) override;
/**
bool loadPlan(int planFileId) override;
Load a plan as overlay into map
@param planFileId File-Id of plan in file management service
@param applyMinMaxScaleOfMetadata The xmlContent may contain minScale, maxScale. Apply them?
@param overrideSitMapIfc Pointer to SituationMapGuiPlugin interface used to load plan into map
*/
bool loadPlan(int planFileId, bool applyMinMaxScaleOfMetadata, SituationMap::ForeignGuiInterface *overrideSitMapIfc, const QJsonObject &planItemObject = QJsonObject());
/**
* @brief unloadAllPlans
* Unload all plans: remove from update model (update GUI), removePlan from sitMap
* (Usefull for SnapshotDialog::showSnapshotInternal)
* @return true
*/
bool unloadAllPlans() override;
TopicEditorBase::TopicEditor *createTopicEditor(const TopicEditorBase::TopicData &data) override;
QWidget *openPlanOverlayDialog(const QJsonArray &planItems = QJsonArray(), bool removePlansOnClose = false) override;
PlanOverlayModel *planOverlayModel() override;
private:
/**
Reload an already loaded plan.
@param planId Id of the plan (keyId) from PlanOverlayModel
*/
void onReloadPlanById(int planId);
/**
Reload an already loaded plan.
@param planId Id of the plan (keyId) from PlanOverlayModel
*/
void onUpdatePlan(int planId);
/**
Remove a plan from map
@param planId Id of the plan (keyId) from PlanOverlayModel
*/
bool removePlan(int planId);
/**
Remove a plan from map
@param planId Id of the plan (keyId) from PlanOverlayModel
@param overrideSitMapIfc Pointer to SituationMapGuiPlugin interface used to remove plan from map
*/
bool removePlan(int planId, SituationMap::ForeignGuiInterface *overrideSitMapIfc);
void onChangePlanMinScaleOnMap(int planId, double minScale);
void onChangePlanMaxScaleOnMap(int planId, double maxScale);
/**
Change opacity of a plan
@param planId Id of the plan (keyId) from PlanOverlayModel
*/
void onChangePlanOpacityOnMap(int planId, double opacity);
/**
Change order of plans on map.
@param newIdOrder Order of plan ids
*/
void onChangePlanOrderOnMap(const QVector<int> & newIdOrder);
void onPlanContentChanged(const FileManagement::FileContent &data, DataModification modType);
void onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification modType);
void onReloadPlanByName(const PlanOverlayModel::PlanItem &planItem, int exerciseId, int phaseId, bool *removeFromModel);
// Script Player
class TopicReplayInterface : public TopicReplay::Interface
{
public:
TopicReplayInterface(SituationMap::ForeignGuiInterface* overrideSitmapIfc,
InterfaceImpl *ovr);
~TopicReplayInterface();
bool playbackInit(const QJsonObject &attributes) override;
bool playbackStop() override;
// overlays are treated special, not exported here atm
bool exportTopic(const QJsonObject &,
const QString &,
TopicEditorBase::ExportNotifier *) override
{
Q_ASSERT(false);
return false;
}
QVector<TopicEditorBase::TopicData> additionalTrackEntries(const QJsonObject &attributes, bool &keepOriginalTopic) const override;
private:
InterfaceImpl *m_ovr;
SituationMap::ForeignGuiInterface *m_foreignSitmapIfc;
//int m_planFileId;
QVector<int> m_loadedPlanFileIds;
NGL::INGLLogger &m_logger;
}; // TopicReplayInterface
TopicReplay::Interface *createInterface(TopicEditorBase::TopicType) override;
ForeignGuiInterface *m_foreignIfc;
QPointer<QWidget> m_planOverlayDialog;
};
} // namespace PlanOverlaysPlugin
+85
View File
@@ -0,0 +1,85 @@
/**
**
** @RDE_HEADER@
** plan_editor.h
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.7. ArcGIS 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 29.06.2017, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <PluginInterfaces/topic_replay_interface.h>
#include <TopicEditorBase/topic_editor_interface.h>
#include <QJsonArray>
#include <QJsonObject>
namespace SituationMap
{
class ForeignGuiInterface;
}
namespace PlanOverlaysPlugin
{
class PlanOverlayModel;
class ForeignGuiInterface : public TopicReplay::Factory, public TopicEditorBase::Interface
{
public:
ForeignGuiInterface() = default;
virtual ~ForeignGuiInterface() = default;
static QString pluginName() { return QStringLiteral("PlanOverlaysGuiPlugin"); }
/**
Set SituationMapGuiPlugin interface from forgein session. Is used by ScriptEditor to define map view displaying plans.
@param foreignSitMapIfc Pointer to SituationMapGuiPlugin interface used to load plan into map when used by ScriptEditor
*/
virtual void setForeignSitMapGuiIfc(SituationMap::ForeignGuiInterface *foreignSitMapIfc) = 0;
virtual void setForeignPlanOverlaysGuiIfc(ForeignGuiInterface *ifc) = 0;
virtual QWidget *openPlanOverlayDialog(const QJsonArray &planItems = QJsonArray(), bool removePlansOnClose = false) = 0;
/**
Load a plan as overlay into map
@param planFileId File-Id of plan in file management service
*/
virtual bool loadPlan(int planFileId, const QJsonObject &planItemObject) = 0;
virtual bool loadPlan(int planFileId) = 0;
/**
* @brief unloadAllPlans
* Unload all plans: remove from update model (update GUI), removePlan from sitMap
* (Usefull for SnapshotDialog::showSnapshotInternal)
* @return true
*/
virtual bool unloadAllPlans() = 0;
virtual PlanOverlayModel *planOverlayModel() = 0;
}; // ForeignGuiInterface
} // namespace PlanOverlaysPlugin