Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Plugins/PlanEditor/plan_editor.cpp
T
berrux-dev 598fc2560e Complete Qt6 migration: full clean build green across groups G1-G12 incl. runtime plugin set
new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
2026-10-20 09:36:57 +02:00

4950 lines
174 KiB
C++
Executable File

const char* const REVISION = "$Revision$";
#include "dialog.h"
#include <utility>
#include "drop_event_manager.h"
#include "icon_names.h"
#include "lookup_symbol_dlg.h"
#include "geometry_placer.h"
#include "selection_worker.h"
#include "plan_editor_utils.h"
#include "metadata_dialog.h"
#include "model_tree_widget.h"
#include "model_tree_widget_item.h"
#include "symbol_favourites.h"
#include <Rubberbands/rubberband_factory.h>
#include <Symbology/symbol_dictionary.h>
#include <Symbology/sidc_builder_base.h>
#include <Symbology/sidc_codec.h>
#include <SymbologyGui/base_symbol_lookup_dialog.h>
#include <SymbologyGui/symbol_modification_dialog.h>
#include <GeometryModel/geometry_node_visitor.h>
#include <Map/bounding_box.h>
#include <Map/layer_parameter.h>
#include <Map/party_id_to_color_functor.h>
#include <Map/pixel_based_textbox_handler.h>
#include <Map/sight_fan.h>
#include <MapObjects/polyline.h>
#include <MathUtils/math_const.h>
#include <MathUtils/simple_helper.h>
#include <MathUtils/matrix2d.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <LtsWidgets/lts_combo_box.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsWidgets/lts_tool_bar_area.h>
#include <LtsWidgets/lts_text_editor.h>
#include <LtsWidgets/lts_text_edit_dialog.h>
#include <QtCore/QAbstractItemModel>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QMimeData>
#include <QtCore/QString>
#include <QString>
#include <QtCore/QSettings>
#include <QtCore/QTemporaryFile>
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtCore/QUuid>
#include <QtGui/QCursor>
#include <QtGui/QGuiApplication>
#include <QtGui/QImage>
#include <QtGui/QMouseEvent>
#include <QtGui/QPixmap>
#include <QtGui/QTextTable>
#include <QtGui/QTextTableCell>
#include <QtGui/QAction>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QGraphicsProxyWidget>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QRadioButton>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QTextBrowser>
#include <QtWidgets/QToolButton>
#include <QtWidgets/QVBoxLayout>
#include <QtPrintSupport/QPrintDialog>
#include <QtGui/QPageLayout>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <SituationMap/LayerAggregation/layer_aggregation_widget.h>
#include <SituationMap/LayerAggregation/participant_aggregation_dialog.h>
#include <limits>
#include "plan_editor_internal.h"
#include "setting_keys.h"
#include <Map/viewshed.h>
namespace PlanEditor
{
const double PasteDistance = 20.0;
const int PLAN_EDITOR_TEXTBOX_PARENT_ID = -123;
class KeyPressDeleteFilter : public QObject
{
public:
explicit KeyPressDeleteFilter(PlanEditor *planEditor)
: QObject(planEditor) , m_planEditor(planEditor) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if ((keyEvent->key() == Qt::Key_Delete) && m_planEditor)
m_planEditor->onDelete();
return true;
}
return QObject::eventFilter(obj, event);
}
QPointer<PlanEditor> m_planEditor;
};
void PlanEditor::onGeoModelModified(unsigned int modifyCount)
{
if (!m_internal || !m_internal->m_modelTreeWidget)
return;
m_internal->m_modelTreeWidget->haveChanges((modifyCount > 0));
}
void PlanEditor::onNoticeGeoModelTypeError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model type error: " << errorMsg;
}
void PlanEditor::onNoticeGeoModelAttributeError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model attribute error: " << errorMsg;
}
void PlanEditor::onNoticeGeoModelModelError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model error: " << errorMsg;
}
void PlanEditor::onNoticeGeoModelError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model error: " << errorMsg;
QString msg = tr("Critical internal failure detected: %1").arg(errorMsg);
msg += QStringLiteral("<br>");
msg += tr("It is recommended to save the plan and restart the editor to avoid data loss");
QMessageBox::critical(topLevelWidget(), tr("Critical Internal Failure"), msg);
}
void PlanEditor::onNoticeGeoModelUpdate(const SituationMap::GeometryModel::Node &node
, SituationMap::GeometryModel::Attribute att
, bool coordsChanged)
{
Q_UNUSED(node);
Q_UNUSED(att);
Q_UNUSED(coordsChanged);
const QString &nodename = m_internal->m_geoModel->getNodeDisplayName(node);
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model has changed: "
<< " nodeDisplayName='" << nodename << "'"
<< " connectedId=" << node.connectedId()
<< " att=" << static_cast<int>(att)
<< " coordsChanged=" << coordsChanged;
switch (m_internal->m_updateViewMode)
{
case UpdateViewMode::Scheduled : m_internal->m_delayedUpdateTimer->start(10); break;
case UpdateViewMode::Immediately : onUpdateView(); break;
case UpdateViewMode::Manually : break;
}
if ((att == SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes) ||
(att == SituationMap::GeometryModel::Attribute::MaxAttributes) )
{
const QString &strRef =
m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
const SituationMap::PBTB_ID pbtbIdAsParent(PLAN_EDITOR_TEXTBOX_PARENT_ID);
const QVector<SituationMap::PBTB_ID> pbtbIdVec = pixelBasedTextBoxHandler.getAllIdsOfParent(pbtbIdAsParent);
if (ptbdCont.size() == pbtbIdVec.size())
{
QVectorIterator<SituationMap::PBTB_ID> pbtbIdVecIt(pbtbIdVec);
for (const SituationMap::PixelTextBoxData &ptbd : std::as_const(ptbdCont))
{
pbtbIdVecIt.hasNext();
const SituationMap::PBTB_ID &pbtbId = pbtbIdVecIt.next();
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " -------- ptbd.toDebugString = " << ptbd.toDebugString()
<< " UPDATE pbtbId = " << pbtbId;
pixelBasedTextBoxHandler.updateTextBox(pbtbId, ptbd);
}
} else {
initializePlanTextBoxPixel();
}
}
if (m_internal && m_internal->m_btnUndo)
m_internal->m_btnUndo->setEnabled((m_internal->m_geoModel->undoSteps() > 0));
if (m_internal && m_internal->m_btnRedo)
m_internal->m_btnRedo->setEnabled((m_internal->m_geoModel->redoSteps() > 0));
}
void PlanEditor::onUpdateView()
{
m_internal->m_delayedUpdateTimer->stop();
if (m_internal->m_teDebug)
m_internal->m_teDebug->setPlainText(QString::fromUtf8(m_internal->m_geoModel->toByteArrayDebug()));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map, *(m_internal->m_geoModel));
if (m_internal->m_map &&
m_internal->m_map->getQGraphicsView() &&
m_internal->m_map->getQGraphicsView()->viewport())
m_internal->m_map->getQGraphicsView()->viewport()->update();
m_internal->m_modelTreeWidget->showNeedSaveFlag( (m_internal->m_geoModel->modificationCounter() > 0) );
}
QString PlanEditor::planDefaultDirectory() const
{
return m_internal->m_defaultPlanDirectory;
}
void PlanEditor::setPlanDefaultDirectory(const QString &dir)
{
QFileInfo fileInfo(dir);
if ((fileInfo.isDir()) || (dir.isEmpty()))
m_internal->m_defaultPlanDirectory = dir;
else
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " failed: \"" << dir << "\" is not a directory.";
}
QWidget *PlanEditor::topLevelWidget() const { return m_internal->m_session.topLevelWidget(); }
void PlanEditor::setParticipantsSidcsInUse(const QSet<QString> &sidcs)
{
if (!m_internal->m_lookupSymbolManager)
return;
m_internal->m_lookupSymbolManager->setParticipantsSidcsInUse(sidcs);
}
static void importGuezXMLSymbolsFromFile(const AdvancedSymbology::SymbolDictionary &symbolDict);
PlanEditor::PlanEditor(SituationMap::Map *map, LtsSession::LtsSession *ltsSession)
: QObject()
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PlanEditor"))
, m_internal(new PlanEditor::InternalData(map, PlanEditorSession(ltsSession, this), this))
{
init();
}
PlanEditor::PlanEditor(SituationMap::Map *map, LtsWidgets::LtsBaseLayoutWidget *ltsbaseWidget)
: QObject()
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("PlanEditor"))
, m_internal(new PlanEditor::InternalData(map, PlanEditorSession(ltsbaseWidget, this), this))
{
init();
}
void PlanEditor::init()
{
if (!m_internal->m_map)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "SituationMap::Map instance is nullptr.";
return;
}
KeyPressDeleteFilter *kpFilter = new KeyPressDeleteFilter(this);
m_internal->m_map->installEventFilter(kpFilter);
SituationMap::RB::RubberbandFactory *rbndFactory = &m_internal->m_map->rubberbandFactory();
connect(rbndFactory, &SituationMap::RB::RubberbandFactory::rubberbandCreated, this, &PlanEditor::onRubberbandAction);
connect(rbndFactory, &SituationMap::RB::RubberbandFactory::rubberbandDestroyed, this, &PlanEditor::onRubberbandAction);
AdvancedSymbology::SymbolDictionary &symbolDict = m_internal->m_map->symbolDictionary();
AdvancedSymbology::LoadStatus dictStatus = symbolDict.loadStatus();
if ((AdvancedSymbology::LoadStatus::Loaded != dictStatus) && (AdvancedSymbology::LoadStatus::Loading != dictStatus))
symbolDict.load();
importGuezXMLSymbolsFromFile(symbolDict);
auto &layerFac = m_internal->m_map->layerFactory();
layerFac.setLayersVisible({SituationMap::LayerType::Undefined, SituationMap::LayerType::JumpPoint, SituationMap::LayerType::SnapshotOverlay,
SituationMap::LayerType::Overlay, SituationMap::LayerType::Operational
}, false);
if (m_internal->m_session.isSnapshot())
{
m_internal->initLogicalLayernameAndRenderer(m_internal->m_map->layerFactory().snapshotOverlayLayername(), this);
layerFac.addOverlayLayer(m_internal->m_logicalLayername, m_internal->m_logicalLayername, true);
}
else
layerFac.addOperationalLayer(m_internal->m_logicalLayername, tr("PlanEditor"));
if (nullptr == topLevelWidget())
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "top level widget is nullptr.";
}
buildFileBox(m_internal->m_session);
buildSelectionModeBox(m_internal->m_session);
buildEditBox(m_internal->m_session);
buildCreateBox(m_internal->m_session);
buildHelpBox(m_internal->m_session);
m_internal -> m_modelTreeWidget = new ModelTreeWidget(this, topLevelWidget());
#ifdef LTS_DEBUG
m_internal -> m_dlgDebug = buildDebugBox(topLevelWidget());
m_internal->m_session.addWidget(m_internal -> m_dlgDebug.data(), title(), QLatin1String("Debug"), LtsWidgets::LayoutArea::eInfoTab, false);
#endif
m_internal->m_session.addWidget(m_internal -> m_modelTreeWidget.data(), title(), m_internal->m_modelTreeWidget->objectName(), LtsWidgets::LayoutArea::eInfoTab, false);
m_internal->m_session.makeCurrentWidget(m_internal->m_modelTreeWidget, LtsWidgets::LayoutArea::eInfoTab);
onHideDialogTab();
if (m_internal->m_map)
{
connect(m_internal->m_map, &SituationMap::Map::mapObjectsClicked , this, &PlanEditor::onMapObjectClicked);
connect(m_internal->m_map, &SituationMap::Map::mapObjectsPickedByArea, this, &PlanEditor::onMapObjectClicked);
connect(m_internal->m_map, &SituationMap::Map::mapReady, this, &PlanEditor::onEnablePlanEditor);
if (!m_internal->m_session.isLtsSession())
{
connect(m_internal->m_map, &SituationMap::Map::mapReady, this, [this]()
{
connect(m_internal->m_map.data()
, &SituationMap::Map::contextMenuClicked
, this
, &PlanEditor::onContextMenuRequested);
});
}
if (!m_internal->m_map->isReady())
{
onDisablePlanEditor();
}
connect( qApp, &QCoreApplication::aboutToQuit, this, &PlanEditor::onQuit );
m_internal->m_map->installViewPortEventFilter(this);
}
else
onDisablePlanEditor();
m_internal->m_favouritesActionManager->initMainMenu();
const QString &tmp = QStringLiteral("/tmp/plan_") + QString::number(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
if (QFile::exists(tmp))
{
if (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
, tr("Autosaved file exists. Do you want to load it?")
, title() + QStringLiteral(" : ") + tr("Open autosaved file")
, LtsWidgets::Behaviour::Modal
, LtsWidgets::Button::Yes | LtsWidgets::Button::No))
loadFromFile(tmp);
}
m_internal->m_autosaveTimer->start(300000);
}
QString PlanEditor::title() const
{
return m_internal->m_title;
}
void PlanEditor::onEnableSymbolWidgets()
{
if (m_internal->m_symbolDictLoaded) return;
m_internal->m_symbolDictLoaded = true;
m_internal->m_favouritesActionManager->initFromDefaultSettings();
for (QWidget *w : std::as_const(m_internal->m_symbolWidgets))
w->setEnabled(true);
}
void PlanEditor::onEnablePlanEditor()
{
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eInfoTab, true);
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eDialogTab, true);
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eSpecialTab, true);
m_internal->m_session.setMenuEnabled(true);
m_internal->m_session.setToolBarEnabled(true);
}
void PlanEditor::onDisablePlanEditor()
{
if (nullptr == m_internal->m_currentBboxRubberband)
{
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eInfoTab, false);
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eDialogTab, false);
m_internal->m_session.setTabLayoutAreaEnabled(LtsWidgets::LayoutArea::eSpecialTab, false);
m_internal->m_session.setMenuEnabled(false);
m_internal->m_session.setToolBarEnabled(false);
}
}
bool PlanEditor::readyForUse() const
{
return ((m_internal->m_map) && (m_internal->m_map->isReady()));
}
PlanEditor::~PlanEditor()
{
if (m_internal->m_map)
m_internal->m_map->removeViewPortEventFilter(this);
if (m_internal->m_textBoxNotifyTimer)
m_internal->m_textBoxNotifyTimer->stop();
}
bool PlanEditor::event(QEvent *e)
{
if (e->type() == QEvent::LanguageChange)
{
buildFileBox(m_internal->m_session,true);
buildSelectionModeBox(m_internal->m_session,true);
buildEditBox(m_internal->m_session,true);
buildCreateBox(m_internal->m_session,true);
buildHelpBox(m_internal->m_session,true);
m_internal->m_favouritesActionManager->initMainMenu(true);
}
return QObject::event(e);
}
void PlanEditor::buildSelectionModeBox(const PlanEditorSession &session, bool retranslate)
{
LtsWidgets::PluginData pluginAction;
LtsWidgets::LtsDragIcon *currentDragIcon = nullptr;
QButtonGroup *selectButtonGroup = new QButtonGroup(this);
selectButtonGroup -> setExclusive(true);
pluginAction.menuGroup = tr("Selection");
pluginAction.identifier = QStringLiteral("Mouse_Pick_Selection");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_PICK_ICON_NAME));
pluginAction.menuText = tr("Mouse Pick Selection");
pluginAction.tooltip = tr("Selection with single mouse clicks");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Picking; };
currentDragIcon = session.addMenuAction(pluginAction);
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
if (currentDragIcon)
{
currentDragIcon->setCheckable(true);
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Picking);
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Picking));
}
pluginAction.identifier = QStringLiteral("Line_Selection");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_LINE_ICON_NAME));
pluginAction.menuText = tr("Line Selection");
pluginAction.tooltip = tr("Selection with a line");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Line; };
currentDragIcon = session.addMenuAction(pluginAction);
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
if (currentDragIcon)
{
currentDragIcon->setCheckable(true);
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Line);
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Line));
}
pluginAction.identifier = QStringLiteral("Lasso_Selection");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_LASSO_EDIT_ICON_NAME));
pluginAction.menuText = tr("Lasso Selection");
pluginAction.tooltip = tr("Selection with a lasso");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Lasso; };
currentDragIcon = session.addMenuAction(pluginAction);
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
if (currentDragIcon)
{
currentDragIcon->setCheckable(true);
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Lasso);
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Lasso));
}
pluginAction.identifier = QStringLiteral("Rectangle_Selection");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_RECT_EDIT_ICON_NAME));
pluginAction.menuText = tr("Rectangle Selection");
pluginAction.tooltip = tr("Selection with a rectangle");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::Rectangle; };
currentDragIcon = session.addMenuAction(pluginAction);
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
if (currentDragIcon)
{
currentDragIcon->setCheckable(true);
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::Rectangle);
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::Rectangle));
}
pluginAction.identifier = QStringLiteral("Mouse_Pick_Selection_and_Edit_Geometry");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SELECT_PICK_EDIT_ICON_NAME));
pluginAction.menuText = tr("Mouse Pick Selection and Edit Geometry");
pluginAction.tooltip = tr("Selection with single mouse clicks and starts proper rubberband to edit geometry");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { m_internal->m_selectionMode = SelectionMode::PickingAndEdit; };
currentDragIcon = session.addMenuAction(pluginAction);
if (!retranslate) m_internal->m_ltsItems += currentDragIcon;
if (currentDragIcon)
{
currentDragIcon->setCheckable(true);
currentDragIcon->setChecked(m_internal->m_selectionMode == SelectionMode::PickingAndEdit);
currentDragIcon->addToButtonGroup(selectButtonGroup, int(SelectionMode::PickingAndEdit));
}
}
void PlanEditor::buildFileBox(const PlanEditorSession &session, bool retranslate)
{
if (m_internal->m_session.isLtsSession())
{
return;
}
LtsWidgets::PluginData pluginAction;
pluginAction.menuGroup = tr("File");
pluginAction.identifier = QStringLiteral("New_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_NEW_ICON_NAME));
pluginAction.menuText = tr("New Plan");
pluginAction.tooltip = tr("Create empty plan");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanCreate(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Open_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_OPEN_ICON_NAME));
pluginAction.menuText = tr("Open Plan");
pluginAction.tooltip = tr("Load plan from file");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanLoad(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Import_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_IMPORT_ICON_NAME));
pluginAction.menuText = tr("Import Plan");
pluginAction.tooltip = tr("Import plan from file");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanImport(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Save_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVE_ICON_NAME));
pluginAction.menuText = tr("Save");
pluginAction.tooltip = tr("Save plan to file");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSave(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("SaveAs_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVEAS_ICON_NAME));
pluginAction.menuText = tr("Save As");
pluginAction.tooltip = tr("Save plan to file as");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSaveAs(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Export_Plan_File");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_SAVEAS_ICON_NAME));
pluginAction.menuText = tr("Export Selected");
pluginAction.tooltip = tr("Save selected plan parts to file as");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanSaveSelected(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Print_Plan");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_PRINT_ICON_NAME));
pluginAction.menuText = tr("Print");
pluginAction.tooltip = tr("Print plan");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPlanPrint(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#ifdef HAS_CLOSE_BUTTON
pluginAction.identifier = QStringLiteral("Close");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Close");
pluginAction.tooltip = tr("Close Plan Editor");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onQuit(); };
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_AGGREGATION
pluginAction.identifier = QStringLiteral("ParticipantAggregation");
pluginAction.menuIcon = QIcon(QLatin1String("icon:overlays.svg"));
pluginAction.menuText = tr("Participant Aggregation");
pluginAction.tooltip = tr("Aggregation settings for participants");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
QWidget *parent = this->topLevelWidget();
SituationMap::ParticipantAggregationDialog *pad = new SituationMap::ParticipantAggregationDialog(m_internal->m_map, parent);
m_internal->m_session.addWidget(pad, title(), tr("Participant Aggregation"), LtsWidgets::LayoutArea::eDialogTab);
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_RUBBERBAND_RECTANGLE_5X5
pluginAction.identifier = QStringLiteral("Make_Rectangle_Rubberband");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Make Rectangle Rubberband");
pluginAction.tooltip = tr("Make Rectangle Rubberband");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
SituationMap::RB::RubberbandRectangle *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_internal.get());
if (rubberband)
{
rubberband->setAutoDelete(true);
rubberband->buildRectangleRelativeToBottomLeftCorner( m_internal->m_map->centerPoint(), 5, 5, QPointF(0,1) );
}
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_SIGHT_FAN
pluginAction.identifier = QStringLiteral("Make_SIGHT_FAN");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Make Sight Fan");
pluginAction.tooltip = tr("Make Sight Fan");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
SituationMap::RB::RubberbandEllipse *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_internal.get());
if (rubberband)
{
rubberband->setAutoDelete(true);
rubberband->constrainQuadratic(true);
rubberband->constrainOrthogonal(true);
rubberband->enableSector(true);
static SituationMap::RefPointer<SituationMap::SightFan> sightFan;
std::function<bool(SituationMap::RB::RubberbandBase*)> updateSightFan = [this](SituationMap::RB::RubberbandBase* rbBase) -> bool
{
SituationMap::RB::RubberbandEllipse *rubberElli = dynamic_cast<SituationMap::RB::RubberbandEllipse*>(rbBase);
if (rubberElli)
{
QPointF center;
double diameter;
double dummy;
QPointF direction;
double startAngle = 0.0;
double dAngle = 2.0 / 180.0*MathConst::pi;
unsigned int noBeams = 180;
rubberElli->rectangleParameter(center, diameter, dummy, direction);
if (diameter > 0.0)
{
double radius = diameter * 0.5;
if (rubberElli->hasSector())
{
startAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorStart());
double endAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorEnd());
noBeams = floor((endAngle - startAngle) / dAngle);
}
if (nullptr == sightFan.get())
{
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
sightFan = objFac.create<SituationMap::SightFan>(QLatin1String("Tools"));
if (sightFan)
{
sightFan->initFan( SituationMap::Point3D(center.x(),center.y(),0.0), 1.5, radius, radius / 1000.0, startAngle, dAngle, noBeams, 0.6 );
}
}
else
{
sightFan->setInnerRadius(radius/1000.0);
sightFan->setRadius(radius);
sightFan->setStartAngle(startAngle);
sightFan->setNoOfFans(noBeams);
sightFan->move(center);
}
}
}
return true;
};
rubberband->installExternalUpdate(updateSightFan);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this](SituationMap::RB::RubberbandBase *rubberband)
{
if (nullptr != sightFan.get())
{
sightFan->removeMySelf();
sightFan = nullptr;
}
SituationMap::RB::RubberbandEllipse *rubberElli = dynamic_cast<SituationMap::RB::RubberbandEllipse*>(rubberband);
if (rubberElli)
{
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
SituationMap::RefPointer<SituationMap::SightFan> sightFan = objFac.create<SituationMap::SightFan>(QLatin1String("Tools"));
if (sightFan)
{
QPointF center = rubberElli->centerPoint();
double diameter;
double dummy;
QPointF direction;
double startAngle = 0.0;
double dAngle = 2.0/180.0*MathConst::pi;
unsigned int noBeams = 180;
rubberElli->rectangleParameter(center, diameter, dummy, direction);
if (rubberElli->hasSector())
{
startAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorStart());
double endAngle = SituationMap::MathUtils::getMathAngle(rubberElli->sectorEnd());
noBeams = ceil(((startAngle > endAngle) ? (endAngle - startAngle + MathConst::pi_two) : (endAngle - startAngle)) / dAngle);
}
double radius = diameter * 0.5;
sightFan->initFan(SituationMap::Point3D(center.x(),center.y(),0.0), 1.5, radius, radius / 1000.0, startAngle, dAngle, noBeams, 0.6 );
}
}
});
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this](SituationMap::RB::RubberbandBase *rubberband)
{
if (nullptr != sightFan.get())
{
sightFan->removeMySelf();
sightFan = nullptr;
}
onRubberbandAbort(rubberband);
});
}
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_SIGHT_FAN_DIALOG
pluginAction.identifier = QStringLiteral("Make_SIGHT_FAN_DIALOG");
pluginAction.menuIcon = QIcon();
pluginAction.menuText = tr("Make Sight Fan Dialog");
pluginAction.tooltip = tr("Make Sight Fan Dialog");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
ViewshedDialog *dlg = new ViewshedDialog(m_internal->m_session.topLevelWidget());
static double viewshedAlpha = 1.0;
static double viewshedInnerRadius = 100.0;
static double viewshedObserverHeight = 2.0;
static double viewshedTargetHeight = 2.0;
static double viewshedBeamAngle = 2.0;
dlg->initValues(viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
connect(dlg, &ViewshedDialog::createViewshed, this, [this, dlg]()
{
viewshedAlpha = dlg->alpha();
viewshedInnerRadius = dlg->innerRadius();
viewshedObserverHeight = dlg->observerHeight();
viewshedTargetHeight = dlg->targetHeight();
viewshedBeamAngle = dlg->beamAngle();
this->m_internal->m_map->viewshed().create(viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
});
connect(dlg, &ViewshedDialog::removeViewshed, this, [this]()
{
this->m_internal->m_map->viewshed().remove();
});
connect(dlg, &ViewshedDialog::parameterChanged, this, [this, dlg]()
{
viewshedAlpha = dlg->alpha();
viewshedInnerRadius = dlg->innerRadius();
viewshedObserverHeight = dlg->observerHeight();
viewshedTargetHeight = dlg->targetHeight();
viewshedBeamAngle = dlg->beamAngle();
this->m_internal->m_map->viewshed().modify(-1,viewshedAlpha, viewshedInnerRadius, viewshedObserverHeight, viewshedTargetHeight, viewshedBeamAngle);
});
m_internal->m_session.addWidget( dlg, tr("Situation Map"), QLatin1String("ViewshedDialog"), LtsWidgets::LayoutArea::eDialogTab, true );
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_PARTICIPANT_LIST
pluginAction.identifier = QStringLiteral("setParticipantsSidcList");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Test setParticipantsSidcList");
pluginAction.tooltip = tr("setParticipantsSidcList");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
if (isSymbolModelValid())
{
QStringList sidcList;
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10010100001205000000"));
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10010100001106000000"));
sidcList << AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::MIL2525D, QStringLiteral("10011500001202030000"));
setParticipantsSidcList(sidcList);
}
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("resetParticipantsSidcList");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Test resetParticipantsSidcList");
pluginAction.tooltip = tr("resetParticipantsSidcList");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
if (isSymbolModelValid())
{
setParticipantsSidcList(QStringList());
}
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
#ifdef TEST_PARALLEL_TRANSLATION
pluginAction.identifier = QStringLiteral("ParallelTranslation");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_CLOSE_ICON_NAME));
pluginAction.menuText = tr("Test Parallel Translation");
pluginAction.tooltip = tr("Test Parallel Translation");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
SituationMap::RB::RubberbandCorridor *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandCorridor>(m_internal.get());
if (rubberband)
{
static std::function<bool(SituationMap::RB::RubberbandBase*)> testParallel = [this](SituationMap::RB::RubberbandBase *r) -> bool
{
const QVector<QPointF> &line = static_cast<SituationMap::RB::RubberbandCorridor *>(r)->coordinateVector();
if (line.size() > 2)
{
double distance = static_cast<SituationMap::RB::RubberbandCorridor *>(r)->corridorWidth();
const QVector<QPointF> &pLine =
SituationMap::MathUtils::GeometryEngine::parallelTranslation( m_internal->m_map->coordTranslationFunctor(), line, distance );
static SituationMap::Polyline *pLineObjPtr = nullptr;
if (nullptr == pLineObjPtr)
{
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
pLineObjPtr = objFac.create<SituationMap::Polyline>( SituationMap::INVALID_MAP_ID
, QStringLiteral("PlanEditorLayer")
, QLatin1String("Test")).get();
}
if (pLineObjPtr)
{
if (pLine.size() > 1)
{
SituationMap::LineStyle lineStyle;
lineStyle.setLineWidth(5);
lineStyle.setLineColor(QColor(Qt::green));
pLineObjPtr->setLineStyle(lineStyle);
pLineObjPtr->setPositions(SituationMap::convert2D3D(pLine));
pLineObjPtr->updateView();
}
else
{
pLineObjPtr->removeMySelf();
pLineObjPtr = nullptr;
}
}
if (1)
{
const QVector<QPointF> &rLine =
SituationMap::MathUtils::GeometryEngine::parallelTranslation( m_internal->m_map->coordTranslationFunctor(), pLine, -distance );
static SituationMap::Polyline *rLineObjPtr = nullptr;
if (nullptr == rLineObjPtr)
{
SituationMap::ObjectFactory &objFac = m_internal->m_map->objectFactory();
rLineObjPtr = objFac.create<SituationMap::Polyline>(SituationMap::INVALID_MAP_ID
, QStringLiteral("PlanEditorLayer")
, QLatin1String("Test")).get();
}
if (rLineObjPtr)
{
if (rLine.size() > 1)
{
SituationMap::LineStyle lineStyle;
lineStyle.setLineWidth(10);
lineStyle.setLineColor(QColor(Qt::red));
rLineObjPtr->setLineStyle(lineStyle);
rLineObjPtr->setPositions(SituationMap::convert2D3D(rLine));
rLineObjPtr->updateView();
}
else
{
rLineObjPtr->removeMySelf();
rLineObjPtr = nullptr;
}
}
}
}
return true;
};
rubberband->setAutoDelete(true);
rubberband->installExternalUpdate(testParallel);
}
};
if (retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
}
void PlanEditor::buildEditBox(const PlanEditorSession &session, bool retranslate)
{
LtsWidgets::PluginData pluginAction;
pluginAction.menuGroup = tr("Edit");
pluginAction.identifier = QStringLiteral("Undo");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(UNDO_ICON_NAME));
pluginAction.menuText = tr("Undo");
pluginAction.tooltip = tr("Undo last actions. Undo is limited to the last %1 actions").arg(m_internal->m_geoModel->maxUndoSteps());
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onUndo(); };
LtsWidgets::LtsDragIcon *ltsButton = session.addMenuAction(pluginAction);
QMenu *undoMenu = new QMenu();
QAction *tmpAction = undoMenu->addAction(tr("Show Undo History"));
connect(tmpAction, &QAction::triggered, this, &PlanEditor::onUndoHistory);
if (ltsButton)
{
ltsButton -> setMenu(undoMenu);
ltsButton -> setEnabled(false);
if (!retranslate)
{
m_internal->m_ltsItems += ltsButton;
m_internal->m_btnUndo = ltsButton;
}
}
pluginAction.identifier = QStringLiteral("Redo");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(REDO_ICON_NAME));
pluginAction.menuText = tr("Redo");
pluginAction.tooltip = tr("Redo last Undo");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRedo(); };
ltsButton = session.addMenuAction(pluginAction);
QMenu *redoMenu = new QMenu(ltsButton);
tmpAction = redoMenu->addAction(tr("Show Redo History"));
connect(tmpAction, &QAction::triggered, this, &PlanEditor::onRedoHistory);
if (ltsButton)
{
ltsButton -> setMenu(redoMenu);
ltsButton -> setEnabled(false);
if (!retranslate)
{
m_internal->m_ltsItems += ltsButton;
m_internal->m_btnRedo = ltsButton;
}
}
pluginAction.identifier = QStringLiteral("Copy_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(COPY_ICON_NAME));
pluginAction.menuText = tr("Copy");
pluginAction.tooltip = tr("Copy selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onCopy(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Cut_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(CUT_ICON_NAME));
pluginAction.menuText = tr("Cut");
pluginAction.tooltip = tr("Cut selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onCut(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Paste_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(PASTE_ICON_NAME));
pluginAction.menuText = tr("Paste");
pluginAction.tooltip = tr("Paste selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPaste(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("MetaData");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DOCUMENT_METADATA_ICON_NAME));
pluginAction.menuText = tr("Meta Data");
pluginAction.tooltip = tr("Show Meta Data of Plan");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onMetaData(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Group_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(GROUP_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Group");
pluginAction.tooltip = tr("Group selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onGroup(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Ungroup_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(UNGROUP_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Ungroup");
pluginAction.tooltip = tr("Ungroup selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onUngroup(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Delete_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DELETE_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Delete");
pluginAction.tooltip = tr("Delete selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onDelete(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("GraphicAttributes");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ATTR_EDIT_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Graphic Attributes");
pluginAction.tooltip = tr("Edit Attributes of selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEditAttributes(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Edit_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(EDIT_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Edit");
pluginAction.tooltip = tr("Edit geometry of selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEditGraphicGeometry(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Move_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(MOVE_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Move");
pluginAction.tooltip = tr("Move geometry of selected features");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onMoveGraphicGeometry(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Rotate_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ROTATE_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Rotate");
pluginAction.tooltip = tr("Rotate geometry of selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRotateGraphicGeometry(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Scale_Feature");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(SCALE_SELECTED_ICON_NAME));
pluginAction.menuText = tr("Scale");
pluginAction.tooltip = tr("Scale geometry of selected feature");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onScaleGraphicGeometry(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
}
void PlanEditor::buildCreateBox(const PlanEditorSession &session, bool retranslate)
{
LtsWidgets::PluginData pluginAction;
pluginAction.menuGroup = tr("Create Graphics");
pluginAction.identifier = QStringLiteral("Draw_Line");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_LINE_ICON_NAME));
pluginAction.menuText = tr("Line");
pluginAction.tooltip = tr("Draw line");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateLine(this, m_internal.get()));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onLineCreateRubberband(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_Polyline");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_POLYLINE_ICON_NAME));
pluginAction.menuText = tr("Polyline");
pluginAction.tooltip = tr("Draw polyline");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPolylineCreateRubberband(); };
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolyLine(this, m_internal.get()));
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_Polygon");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_POLYGON_ICON_NAME));
pluginAction.menuText = tr("Polygon");
pluginAction.tooltip = tr("Draw polygon");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolygon(this, m_internal.get()));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onPolygonCreateRubberband(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_Rectangle");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_RECTANGLE_ICON_NAME));
pluginAction.menuText = tr("Rectangle");
pluginAction.tooltip = tr("Draw rectangle");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get()));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onRectangleCreateRubberband(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_SmoothLiné");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_SPLINE_ICON_NAME));
pluginAction.menuText = tr("Smooth Line");
pluginAction.tooltip = tr("Draw spline based smooth line");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreatePolyLine(this, m_internal.get(), true));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onSmoothLineCreateRubberband(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_Ellipse");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_ELLIPSE_ICON_NAME));
pluginAction.menuText = tr("Ellipse");
pluginAction.tooltip = tr("Draw ellipse");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onEllipseCreateRubberband(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_Symbol");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_SYMBOL_ICON_NAME));
pluginAction.menuText = tr("Symbol");
pluginAction.tooltip = tr("Draw symbol from symbol dictionary");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { onChooseSymbol(); };
LtsWidgets::LtsDragIcon *pbCreateSymbol = session.addMenuAction(pluginAction);
pbCreateSymbol->setEnabled(m_internal->m_symbolDictLoaded);
if (!retranslate)
{
m_internal->m_ltsItems += pbCreateSymbol;
m_internal->m_symbolWidgets += pbCreateSymbol;
}
pluginAction.identifier = QStringLiteral("Draw_Participants");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_PARTICIPANT_ICON_NAME));
pluginAction.menuText = tr("Participants");
pluginAction.tooltip = tr("Draw participants from symbol dictionary");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateRectangle(this, m_internal.get(), true));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
onClearSelection();
if (m_internal->m_symbolDictLoaded) m_internal->m_lookupSymbolManager -> onOpenParticipantDialog();
};
LtsWidgets::LtsDragIcon *pbCreateParticipants = session.addMenuAction(pluginAction);
pbCreateParticipants->setEnabled(m_internal->m_symbolDictLoaded);
if (!retranslate)
{
m_internal->m_ltsItems += pbCreateParticipants;
m_internal->m_symbolWidgets += pbCreateParticipants;
}
pluginAction.identifier = QStringLiteral("Draw_Text");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_TEXT_ICON_NAME));
pluginAction.menuText = tr("Text");
pluginAction.tooltip = tr("Draw single text line");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateTextLine(this, m_internal.get()));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
PlanEditor::onTextLineCreateRubberband();
};
if (!retranslate)
session.addMenuAction(pluginAction);
else
m_internal->m_ltsItems += session.addMenuAction(pluginAction);
pluginAction.identifier = QStringLiteral("Draw_TextBoxPixel");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(DRAW_TEXT_ICON_NAME));
pluginAction.menuText = tr("Pixel-based Text");
pluginAction.tooltip = tr("Draw textbox");
pluginAction.dropHandlerKey = m_internal->m_dropEventManager->add(new DropCreateTextLine(this, m_internal.get()));
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
PlanEditor::onTextBoxPixelCreateRubberband();
};
if (!retranslate)
session.addMenuAction(pluginAction);
else
m_internal->m_ltsItems += session.addMenuAction(pluginAction);
}
void PlanEditor::buildHelpBox(const PlanEditorSession &session, bool retranslate)
{
LtsWidgets::PluginData pluginAction;
pluginAction.menuGroup = tr("Help");
if (!m_internal->m_session.isLtsSession())
{
if (m_internal->m_viewHelp != nullptr)
{
pluginAction.identifier = QStringLiteral("Help");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(HELP_ICON_NAME));
pluginAction.menuText = tr("View Online Documentation");
pluginAction.tooltip = tr("Shows online documentation");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onViewHelp(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
}
pluginAction.identifier = QStringLiteral("About");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ABOUT_ICON_NAME));
pluginAction.menuText = tr("About");
pluginAction.tooltip = tr("Shows about information");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &) { PlanEditor::onViewAbout(); };
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
}
#ifdef TestSymbolDialog
pluginAction.identifier = QStringLiteral("SymbolDialog");
pluginAction.menuIcon = Utils::getIcon(QLatin1String(ABOUT_ICON_NAME));
pluginAction.menuText = tr("Symbol Dialog");
pluginAction.tooltip = tr("Selected a symbol");
pluginAction.directFunc = [this](const LtsWidgets::PluginData &)
{
qCritical() << "********************************* show symbol dialog ***************************************************************";
AdvancedSymbology::Gui::BaseSymbolLookupDialog *symbolDialog = new AdvancedSymbology::Gui::BaseSymbolLookupDialog(m_internal->m_map->symbolDictionary(), true, nullptr);
connect(symbolDialog, &AdvancedSymbology::Gui::BaseSymbolLookupDialog::lookupApplied, symbolDialog, [this](const QString & sidc)
{
qCritical() << "********************************* Selected Symbol : " << sidc << " ************************************************";
});
m_internal->m_session.addWidget(symbolDialog
, title()
, tr("Select Symbol")
, LtsWidgets::LayoutArea::eDialogTab
false);
};
if (!retranslate) session.addMenuAction(pluginAction);
else m_internal->m_ltsItems += session.addMenuAction(pluginAction);
#endif
}
LtsWidgets::LtsDialog *PlanEditor::buildDebugBox(QWidget *parent)
{
Dialog *gbLayer = new Dialog(parent, LtsWidgets::ButtonCombination::SeamlessDialog);
QVBoxLayout *tabLayout = new QVBoxLayout(gbLayer);
gbLayer -> setObjectName(QLatin1String("PlanEditor::PlanDebug"));
gbLayer -> setTitle(tr("Plan Debug"));
m_internal->m_teDebug = new QTextEdit(gbLayer);
m_internal->m_teDebug -> setReadOnly(true);
tabLayout->addWidget(m_internal->m_teDebug, 2);
return gbLayer;
}
bool PlanEditor::eventFilter(QObject *obj, QEvent *event)
{
if (QEvent::MouseButtonPress == event->type())
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (Qt::LeftButton == mouseEvent->button())
{
if (SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data()).isEmpty())
{
if (!(QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
switch (m_internal->m_selectionMode)
{
case SelectionMode::Picking: break;
case SelectionMode::PickingAndEdit: break;
case SelectionMode::Line:
case SelectionMode::Lasso:
case SelectionMode::Rectangle:
new SelectionWorker(this, m_internal->m_geoModel, m_internal->m_map.data(), m_internal->m_selectionMode, mouseEvent->pos());
return true;
}
}
}
}
}
return QObject::eventFilter(obj, event);
}
void PlanEditor::onRubberbandAction()
{
if (nullptr == m_internal) return;
const QList<SituationMap::RB::RubberbandBase *> &activeRbndList = SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data());
(activeRbndList.isEmpty()) ? onEnablePlanEditor() : onDisablePlanEditor();
}
void PlanEditor::onHideDialogTab()
{
m_internal->m_lookupSymbolManager -> onCloseDialog();
m_internal->m_attributeDialogManager -> onCloseDialog();
}
void PlanEditor::onShowDialogTab(const SituationMap::GeometryModel::Node &node)
{
onEnablePlanEditor();
m_internal->m_attributeDialogManager->onOpenDialog(node);
m_internal->m_attributeDialogManager->getStyleAttributes(node);
}
void PlanEditor::saveToFile(const QString &filePath)
{
QFile file(filePath);
if (file.open(QIODevice::WriteOnly))
{
file.write(m_internal->m_geoModel->toByteArray());
m_internal->m_geoModel->resetModificationCounter();
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Save plan to file \"%1\"failed").arg(filePath), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Saving plan model to file - " << filePath << " - failed.";
}
}
void PlanEditor::initializePlan()
{
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
m_internal->m_geoModelRenderer->render();
initializePlanTextBoxPixel();
if (m_internal->m_map &&
m_internal->m_map->getQGraphicsView() &&
m_internal->m_map->getQGraphicsView()->viewport())
m_internal->m_map->getQGraphicsView()->viewport()->update();
}
void PlanEditor::initializePlanTextBoxPixel()
{
const QString &strRef =
m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
const int parentId = PLAN_EDITOR_TEXTBOX_PARENT_ID;
pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId);
m_internal->resetTextBoxData();
m_internal->m_ourTextBoxIds.clear();
m_internal->m_ourTextBoxIds.reserve(ptbdCont.size());
for (const SituationMap::PixelTextBoxData &ptbd : std::as_const(ptbdCont))
{
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " -------- ptbd.toDebugString = " << ptbd.toDebugString();
if (!ptbd.isEmpty())
{
SituationMap::PBTB_ID pbtbId(parentId);
QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, true);
if (newTextEdit)
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " new TextBox created: newTextEdit = " << newTextEdit
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
else
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " createUpdateTextBox failed"
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
m_internal->m_ourTextBoxIds.append(pbtbId);
}
}
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxDoubleClickEvent,
this, &PlanEditor::onTextEditDialogRequested, Qt::UniqueConnection);
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxGeometryChanged,
this, &PlanEditor::onTextEditGeometryChanged, Qt::UniqueConnection);
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxRemoveRequestedEvent,
this, &PlanEditor::onTextEditRemoveRequested, Qt::UniqueConnection);
}
void PlanEditor::checkFromEmptyPlan()
{
if (m_internal->m_modelTreeWidget->isEmpty())
{
#ifdef SHOW_MODAL_DIALOG_WHEN_OTHER_MODAL_DIALOG_IS_ACTIVE
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Warning loading empty plan to PlanEditor."), title());
#endif
WARNING_LOG(m_internal->m_logger) << LOGFUNCTION << "Warning loading empty plan to PlanEditor.";
}
}
void PlanEditor::setNameOfPlan(const QString & planName)
{
m_internal->m_modelTreeWidget->setNameOfPlan(planName);
}
bool PlanEditor::setPlan(const QByteArray &xmlContent)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START, xmlContent.size()" << xmlContent.size();
if (xmlContent.isEmpty())
{
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " xmlContent is Empty";
onPlanCreate();
return true;
}
if (!m_internal->m_geoModel->fromByteArray(xmlContent))
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " fromByteArray failed... -> clearModel";
m_internal->m_geoModel->clearModel();
return false;
}
initializePlan();
return true;
}
bool PlanEditor::importPlan(const QByteArray &xmlContent)
{
bool importPlanEmpty = xmlContent.isEmpty();
bool status = true;
SituationMap::GeometryModel *importedModel = SituationMap::GeometryModelFactory::singleton()->create();
if (!importedModel)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Memory out of range"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Memory allocation failure. Can't create GeometryModel to import file";
return false;
}
if (!importPlanEmpty)
{
importedModel->cleanModel();
status = importedModel->fromByteArray(xmlContent);
if (status)
{
importPlanEmpty = importedModel->isEmpty();
if (!importPlanEmpty)
{
m_internal->m_geoModel->startUndoBlock();
m_internal->m_geoModel->merge(importedModel, true, true);
m_internal->m_geoModel->endUndoBlock(tr("Import from file"));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
m_internal->m_geoModelRenderer->render();
m_internal->m_map->getQGraphicsView()->viewport()->update();
}
}
}
delete importedModel;
if (importPlanEmpty)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Imported plan is empty."), title());
}
return status;
}
void PlanEditor::loadFromFile(const QString &filePath)
{
QFile file(filePath);
m_internal->m_geoModel->clearModel();
if (file.open(QIODevice::ReadOnly))
{
if (m_internal->m_geoModel->fromDevice(&file))
{
initializePlan();
checkFromEmptyPlan();
}
else
{
m_internal->m_geoModel->clearModel();
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Read plan from file '%1' failed").arg(filePath), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Parsing plan model data - " << filePath << " - failed.";
}
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Open file '%1' failed").arg(filePath), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Open file for reading plan model - " << filePath << " - failed.";
}
}
void PlanEditor::saveSelectedToFile(const QString &filePath)
{
QFile file(filePath);
if (file.open(QIODevice::WriteOnly))
{
SituationMap::GeometryModel * exportModel = SituationMap::GeometryModelFactory::singleton()->clone( m_internal->m_geoModel );
Q_ASSERT(exportModel);
class MapObjectsVisitor : public SituationMap::GeometryNodeVisitor
{
QList<SituationMap::UniqueMapId> m_exportedNodes;
QList<SituationMap::GeometryModel::Node> m_removeNodeList;
QList<SituationMap::GeometryModel::Node> m_removeGroupList;
public:
MapObjectsVisitor(SituationMap::GeometryModel *geoModel, const QList<SituationMap::UniqueMapId> &exportedNodes)
: SituationMap::GeometryNodeVisitor(geoModel)
, m_exportedNodes(exportedNodes)
{
}
bool apply(SituationMap::GeometryModel *geoModel
, const SituationMap::GeometryModel::Node &node
, SituationMap::GeometryModel::PrimitiveType primitiveType) override
{
switch (primitiveType)
{
case SituationMap::GeometryModel::PrimitiveType::RootNode : break;
case SituationMap::GeometryModel::PrimitiveType::Node:
{
if (!node.hasChildNodes())
{
m_removeGroupList << node;
}
} break;
default:
{
if (geoModel->hasUserData(node))
{
bool ok = false;
SituationMap::UniqueMapId uid = geoModel->getUserData(node, &ok);
if (ok && m_exportedNodes.contains(uid))
{
return true;
}
}
m_removeNodeList << node;
} break;
}
return true;
}
void cleanup()
{
for (const auto &node : std::as_const(m_removeNodeList))
m_geometryModel->removePrimitive(node);
for (const auto &group : std::as_const(m_removeGroupList))
m_geometryModel->deleteGroup(group);
}
};
MapObjectsVisitor exportVisitor(exportModel, m_internal->m_selectionList);
exportVisitor.traverse(exportModel->getRootNode());
exportVisitor.cleanup();
exportModel->cleanModel();
file.write(exportModel->toByteArray());
file.close();
delete exportModel;
}
else ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Saving selected plan parts to file - " << filePath << " - failed.";
}
void PlanEditor::importFromFile(const QString &filePath)
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly))
{
const QByteArray & xmlContent = file.readAll();
if (!importPlan(xmlContent))
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Parsing plan model '%1' failed").arg(filePath), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Parsing plan model data - " << filePath << " - failed.";
}
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Open plan file '%1' failed").arg(filePath), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Open file for reading plan model - " << filePath << " - failed.";
}
}
bool PlanEditor::isSymbolModelValid() const
{
return true;
}
void PlanEditor::setAllSymbolFavourites(const QString &xmlContent)
{
m_internal->m_favouritesActionManager->symbolFavourites()->contentFromString(xmlContent);
}
QString PlanEditor::allSymbolFavouritesToString() const
{
return m_internal->m_favouritesActionManager->symbolFavourites()->toString();
}
SituationMap::UniqueMapId PlanEditor::getIdFromNode(const SituationMap::GeometryModel::Node &p) const
{
return m_internal->m_geoModelRenderer->getIdFromNode(p);
}
void PlanEditor::setSelected(SituationMap::UniqueMapId uid, bool on, bool enableShowDialogTab)
{
SituationMap::AbstractMapObject *mapObj = m_internal->m_map->objectFactory().idToMapObject(uid);
if (!mapObj)
return;
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " setSelected... uid=" << uid
<< ", on=" << on
<< ", enableShowDialogTab=" << enableShowDialogTab;
mapObj->setSelected(on);
mapObj->updateView();
SituationMap::GeometryModel::Node modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObj);
if (on)
{
if (enableShowDialogTab)
onShowDialogTab(modelPrimitive);
if (!m_internal->m_selectionList.contains(uid))
m_internal->m_selectionList.append(uid);
}
else
{
if (m_internal->m_selectionList.contains(uid))
m_internal->m_selectionList.removeOne(uid);
if (m_internal->m_selectionList.size() == 1)
{
mapObj = m_internal->m_map->objectFactory().idToMapObject(m_internal->m_selectionList.first());
if (mapObj)
{
modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObj);
onShowDialogTab(modelPrimitive);
}
}
if (m_internal->m_selectionList.isEmpty())
{
onHideDialogTab();
}
}
ModelTreeWidgetItem::selectItem(m_internal->m_modelTreeWidget->rootItem(), modelPrimitive, on);
}
void PlanEditor::setSelected(const SituationMap::GeometryModel::Node &node, bool on, bool enableShowDialogTab)
{
setSelected(node, on, true, enableShowDialogTab);
}
void PlanEditor::setSelected(const SituationMap::GeometryModel::Node &node, bool on, bool checkParents, bool enableShowDialogTab)
{
if (!node.isValid()) return;
if (checkParents)
{
const SituationMap::GeometryModel::Node &parent = m_internal->m_geoModel->isInGroup(node);
if (parent.isValid())
setSelected(parent, on, true, enableShowDialogTab);
}
SituationMap::GeometryModel::PrimitiveType nodeType = m_internal->m_geoModel->getType(node);
if ((SituationMap::GeometryModel::PrimitiveType::Node == nodeType) || (SituationMap::GeometryModel::PrimitiveType::RootNode == nodeType))
{
const SituationMap::GeometryModel::NodeList &childNodes = m_internal->m_geoModel->getGroupPrimitives(node);
for (const SituationMap::GeometryModel::Node &childNode : childNodes)
setSelected(childNode, on, false, enableShowDialogTab);
}
else
{
bool ok = false;
SituationMap::UniqueMapId uid = m_internal->m_geoModel->getUserData(node, &ok);
if (ok)
setSelected(uid, on, enableShowDialogTab);
}
}
bool PlanEditor::isSelected(SituationMap::UniqueMapId uid)
{
return m_internal->m_selectionList.contains(uid);
}
bool PlanEditor::isSelected(const SituationMap::GeometryModel::Node &node)
{
SituationMap::GeometryModel::PrimitiveType nodeType = m_internal->m_geoModel->getType(node);
if ((SituationMap::GeometryModel::PrimitiveType::Node == nodeType) || (SituationMap::GeometryModel::PrimitiveType::RootNode == nodeType))
{
const SituationMap::GeometryModel::NodeList &childNodes = m_internal->m_geoModel->getGroupPrimitives(node);
for (const SituationMap::GeometryModel::Node &childNode : childNodes)
{
if (isSelected(childNode)) return true;
}
return false;
}
else
{
bool ok = false;
SituationMap::UniqueMapId uid = m_internal->m_geoModel->getUserData(node, &ok);
if (ok) return isSelected(uid);
}
return false;
}
void PlanEditor::addStyleAttributes(const SituationMap::GeometryModel::Node &node, bool prepareUndo, bool changedAttrOnly)
{
m_internal->m_attributeDialogManager->addStyleAttributes(node, prepareUndo, changedAttrOnly);
}
void PlanEditor::getSymbolAttributes(const SituationMap::GeometryModel::Node &node)
{
SituationMap::GeometryModel::PrimitiveType primitiveType = m_internal->m_geoModel->getType(node);
const QList<SituationMap::GeometryModel::Attribute> &supportedStyleAttributes = m_internal->m_geoModel->supportedAttributes(primitiveType);
for (auto attr : supportedStyleAttributes)
{
QVariant attrValue = m_internal->m_geoModel->getAttribute(node, attr);
switch (attr)
{
case SituationMap::GeometryModel::Attribute::SIDC :
{
m_internal->m_symbolCurrentSidc = attrValue.toString();
} break;
default : break;
}
}
}
SituationMap::GeometryModel::Node PlanEditor::addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType type
, const QList<QPointF> &points
, const QList<QPair<SituationMap::GeometryModel::Attribute, QVariant>> &attributes
, int userData
, const QString &textData
, SituationMap::GeometryModel::HorizontalAlign textAlign)
{
const SituationMap::GeometryModel::Node &node = m_internal->m_geoModel->addPrimitive(type
, points
, attributes
, userData
, textData
, textAlign);
addStyleAttributes(node, false, false);
return node;
}
void PlanEditor::removeFeature(SituationMap::UniqueMapId itemId, bool prepareUndo)
{
const SituationMap::GeometryModel::Node &node = m_internal->m_geoModel->findPrimitive(itemId);
if (!node.isValid()) return;
if (prepareUndo)
{
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->removePrimitive(node);
}
m_internal->m_geoModel->endUndoBlock(tr("delete single feature", TR_UNDO_TOKEN));
}
else m_internal->m_geoModel->removePrimitive(node);
}
void PlanEditor::updateSelectedFeature(const QString &undoToken)
{
if (m_internal->m_readStyleAttributesFromModel) return;
if (m_internal->m_selectionList.isEmpty()) return;
m_internal->m_geoModel->startUndoBlock();
{
for (SituationMap::UniqueMapId uid : std::as_const(m_internal->m_selectionList))
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
if (modelPrimitive.isValid())
addStyleAttributes(modelPrimitive, false);
}
}
m_internal->m_geoModel->endUndoBlock(undoToken.isEmpty() ? tr("modify feature style", TR_UNDO_TOKEN) : undoToken);
emit modifyFeatureStyle(undoToken);
}
void PlanEditor::abortCurrentBboxRubberband()
{
if (m_internal->m_currentBboxRubberband)
{
m_internal->m_currentBboxRubberband->deleteMySelf();
m_internal->m_currentBboxRubberband = nullptr;
}
}
template<class RubberbandTransformClass> void PlanEditor::createTransformRubberband()
{
SituationMap::RB::RubberbandTransform *geoPlacerRB = GeometryPlacer<RubberbandTransformClass>::create(this, m_internal->m_map.data(), m_internal->m_geoModel, m_internal->m_selectionList, this);
if (geoPlacerRB)
{
onHideDialogTab();
m_internal->m_currentBboxRubberband = geoPlacerRB;
SituationMap::LayerParameter lp = m_internal->m_map->layerFactory().layerParameter(m_internal->m_logicalLayername);
int opacity = lp.opacity;
lp.opacity *= 0.3;
m_internal->m_map->layerFactory().setLayerParameter(m_internal->m_logicalLayername, lp);
lp.opacity = opacity;
connect(geoPlacerRB, &SituationMap::RB::Rubberband::finished, [this, lp](SituationMap::RB::RubberbandBase *)
{
onEditAttributes();
if (m_internal)
{
m_internal->m_currentBboxRubberband = nullptr;
m_internal->m_map->layerFactory().setLayerParameter(m_internal->m_logicalLayername, lp);
}
m_internal->m_map->setFocus();
});
connect(this, &PlanEditor::modifyFeatureStyle, geoPlacerRB, [geoPlacerRB](const QString &)
{
GeometryPlacer<RubberbandTransformClass> *geoPlacer = static_cast<GeometryPlacer<RubberbandTransformClass>*>(geoPlacerRB->userData());
if (nullptr == geoPlacer) return;
geoPlacer->changeStyleAttributes();
});
}
}
void PlanEditor::onTransformRubberband()
{
createTransformRubberband<SituationMap::RB::RubberbandTransform>();
}
void PlanEditor::onTextEditDialogRequested(const SituationMap::PBTB_ID &pbtbId)
{
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << ", clickedObj = pbtbId " << pbtbId;
QWidget *parent = m_internal->m_session.topLevelWidget();
if (m_internal->m_textEditorDialog && m_internal->m_textEditorDialog->hasUnsavedChanges())
{
const LtsWidgets::Button answer =
LtsWidgets::LtsMessageDialog::askApplyDiscardCancel(m_internal->m_textEditorDialog);
switch (answer)
{
case LtsWidgets::Button::Apply:
m_internal->m_textEditorDialog->apply();
break;
case LtsWidgets::Button::Cancel:
return;
case LtsWidgets::Button::Discard:
if (m_internal->m_textBoxTextEdit)
m_internal->m_textBoxTextEdit->setHtml(m_internal->m_htmlTextForCancelation);
break;
default:
break;
}
}
if (!m_internal->m_textEditorDialog)
{
m_internal->m_textEditorDialog = new LtsWidgets::LtsTextEditDialog(parent);
m_internal->m_textEditorDialog->enableBackgroundColor(true);
m_internal->m_textEditorDialog->setOnlineHelpFilename(QStringLiteral("Plan_Editor-Create_Graphics"));
m_internal->m_session.addOrReplaceWidget(m_internal->m_textEditorDialog,
QStringLiteral("PlanEditor"),
QStringLiteral("PixelBasedTextBoxAttributes"),
LtsWidgets::LayoutArea::eDialogTab,
true);
}
m_internal->m_session.focusTab(m_internal->m_textEditorDialog,
LtsWidgets::LayoutArea::eDialogTab,
QStringLiteral("PlanEditor"),
QStringLiteral("PixelBasedTextBoxAttributes"));
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
QTextEdit *currentTe = pixelBasedTextBoxHandler.getTextBox(pbtbId);
m_internal->m_textBoxIdInEditing = pbtbId;
m_internal->m_textBoxTextEdit = currentTe;
if (!pixelBasedTextBoxHandler.setSelected(m_internal->m_textBoxIdInEditing))
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " setSelected failed ";
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
if (!data.isEmpty())
{
const QString &currentText = data.m_htmlText;
m_internal->m_textEditorDialog->setHtml(currentText);
m_internal->m_textEditorDialog->setInitialBackgroundColor(data.m_backgroundColor);
m_internal->m_textEditorDialog->__unchange__();
m_internal->m_htmlTextForCancelation = currentText;
}
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalTextChanged,
this, &PlanEditor::onTextBoxPixelTextChanged, Qt::UniqueConnection);
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalBackgroundColorChanged,
this, &PlanEditor::onTextBoxPixelBackgroundColorChanged, Qt::UniqueConnection);
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalTextApplied,
this, &PlanEditor::onTextBoxPixelTextApplied, Qt::UniqueConnection);
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::signalDialogCanceled,
this, &PlanEditor::onTextBoxPixelCanceled, Qt::UniqueConnection);
connect(m_internal->m_textEditorDialog, &LtsWidgets::LtsTextEditDialog::destroyed,
this, &PlanEditor::onTextBoxPixelClosed, Qt::UniqueConnection);
connect(currentTe, &QTextEdit::destroyed,
this, [this ] (QObject *)
{
delete m_internal->m_textEditorDialog;
});
}
void PlanEditor::onTextEditGeometryChanged(const SituationMap::PBTB_ID &pbtbId)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START " << pbtbId;
if (!m_internal->m_textBoxNotifyTimer)
{
m_internal->m_textBoxNotifyTimer = new QTimer(this);
m_internal->m_textBoxNotifyTimer->setSingleShot(true);
m_internal->m_textBoxNotifyTimer->setInterval(100);
connect(m_internal->m_textBoxNotifyTimer, &QTimer::timeout, this, [this] () {
writeTextBoxDataToModel();
});
}
m_internal->m_textBoxNotifyTimer->start();
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onTextEditRemoveRequested(const SituationMap::PBTB_ID &pbtbId)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START " << pbtbId;
if (!pbtbId.isValid())
return;
m_internal->m_ourTextBoxIds.removeAll(pbtbId);
QTimer::singleShot(100, this, [this, pbtbId] () {
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
if (!pixelBasedTextBoxHandler.removeTextBox(pbtbId))
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " removeTextBox failed: pbtbId=" << pbtbId;
writeTextBoxDataToModel();
});
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onMapObjectClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList)
{
if (mapObjList.isEmpty())
onHideDialogTab();
if (!m_internal->m_geoModel) return;
if (!m_internal->m_geoModelRenderer) return;
if (m_internal->m_currentBboxRubberband) return;
if (!SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data()).isEmpty()) return;
if (!(QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
if (mapObjList.isEmpty()) onClearSelection();
}
if ((SelectionMode::Picking == m_internal->m_selectionMode)
|| QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)
|| QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
{
doPicking(mapObjList);
return;
}
if (SelectionMode::PickingAndEdit == m_internal->m_selectionMode)
{
doPicking(mapObjList);
onEditGraphicGeometry();
}
}
void PlanEditor::doPicking(const SituationMap::Map::RefPointerMapObjectList &mapObjList)
{
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX mapObjList.size() = " << mapObjList.size()
<< ", m_internal->m_selectionList.size() = " << m_internal->m_selectionList.size();
bool bAddSelection = (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier));
bool bCreateTransformRubberband =
!bAddSelection &&
(m_internal->m_selectionMode != SelectionMode::PickingAndEdit)
&& mapObjList.size() >= 1;
for (auto mapObjPtr : mapObjList)
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObjPtr.get());
if (modelPrimitive.isValid())
{
setSelected(modelPrimitive, true, !bCreateTransformRubberband);
}
}
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX bCreateTransformRubberband= " << bCreateTransformRubberband;
if (bCreateTransformRubberband)
createTransformRubberband<SituationMap::RB::RubberbandTransform>();
}
void PlanEditor::onContextMenuRequested( const SituationMap::Map::RefPointerMapObjectList&, const QPointF &viewportPosition)
{
if (m_internal->m_session.isLtsSession()) return;
if (nullptr == m_internal->m_map) return;
QMenu contextMenu;
QAction *selectionByArea = contextMenu.addAction(tr("Area Selection"));
QAction *scaleByArea = contextMenu.addAction(tr("Area Scale"));
QAction *selectedItem = contextMenu.exec(m_internal->m_map->mapToGlobal(viewportPosition.toPoint()));
if (selectedItem == selectionByArea)
{
if (nullptr != m_internal->m_map)
{
m_internal->m_map->pickMapObjectsArea();
}
return;
}
if (selectedItem == scaleByArea)
{
if (nullptr != m_internal->m_map)
{
m_internal->m_map->scaleByArea();
}
return;
}
}
void PlanEditor::onViewAbout()
{
abortCurrentBboxRubberband();
QString aboutText = tr("Plan Editor application to create and modify excercise plans.");
aboutText = QStringLiteral("%1\nBuild: %2\nESRI ArcGISRuntime Release %3").arg(aboutText).arg( QLatin1String(REVISION) ).arg(QLatin1String(ACRGIS_VERSION_STR));
QMessageBox::about(m_internal->m_session.topLevelWidget(), title(), aboutText);
}
void PlanEditor::onViewHelp()
{
abortCurrentBboxRubberband();
if (nullptr == m_internal->m_viewHelp) return;
m_internal->m_viewHelp->show();
}
void PlanEditor::onShowHelp()
{
if (m_internal->m_session.ltsSession())
{
m_internal->m_session.ltsSession()->slotShowOnlineHelp(QStringLiteral("Plan_Editor-Application"));
}
}
void PlanEditor::installSaveFunction(const std::function<void()> &saveFunction)
{
m_internal->m_saveFunction = saveFunction;
}
void PlanEditor::onQuit()
{
onAskSaveChanges();
emit quitPlanEditor();
}
void PlanEditor::onAskSaveChanges()
{
if (m_internal->m_geoModel->modificationCounter() < 1)
return;
if (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
, tr("PlanEditor has unsaved changes. Do you want to save the plan?")
, title() + QStringLiteral(" : ") + tr("Save unsaved Changes")
, LtsWidgets::Behaviour::Modal
, LtsWidgets::Button::Yes | LtsWidgets::Button::No))
{
if (nullptr == m_internal->m_saveFunction)
{
onPlanSave();
if (m_internal->m_geoModel->modificationCounter() < 1)
{
const QString & msg = tr("Saving plan successfully.");
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, title());
}
}
else
m_internal->m_saveFunction();
}
else
m_internal->m_geoModel->resetModificationCounter();
}
void PlanEditor::onAskRejectChanges(bool &reject)
{
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
reject = true;
if (m_internal->m_geoModel->modificationCounter() < 1)
return;
reject = (LtsWidgets::Button::Yes == LtsWidgets::LtsMessageDialog::showMessage( topLevelWidget()
, tr("PlanEditor has unsaved changes. Do you want to discard this changes?")
, title() + QStringLiteral(" : ") + tr("Unsaved Changes")
, LtsWidgets::Behaviour::Modal
, LtsWidgets::Button::Yes | LtsWidgets::Button::No));
if (reject)
{
m_internal->m_geoModel->resetModificationCounter();
m_internal->removeAutosaveFile();
}
return;
}
void PlanEditor::onSignalClose()
{
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START, isSnapshot=" << m_internal->m_session.isSnapshot();
if (m_internal->m_session.isSnapshot())
{
if (m_internal->m_geoModel)
m_internal->m_geoModel->cleanModel();
}
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " END, isSnapshot=" << m_internal->m_session.isSnapshot();
}
void PlanEditor::onMetaData()
{
MetaDataDialog *dlg = new MetaDataDialog(this, m_internal->m_geoModel, m_internal->m_map.data(), m_internal->m_map);
m_internal->m_session.addWidget(dlg, title(), QLatin1String("MetaData"), LtsWidgets::LayoutArea::eDialogTab, false);
}
void PlanEditor::onPlanPrint()
{
abortCurrentBboxRubberband();
QSharedPointer<QPrinter> printer(new QPrinter(QPrinter::PrinterMode::HighResolution));
QPrintDialog printDialog(printer.data(), topLevelWidget());
printer->setPageOrientation(QPageLayout::Orientation::Landscape);
if (printDialog.exec() == QDialog::Accepted)
{
QEventLoop eventLoop;
QMetaObject::Connection slotMetaObj = connect(m_internal->m_map.data()
, &SituationMap::Map::imageCompleted
, this
, [this, &printer, &eventLoop](const QUuid &, const QImage & image)
{
const QString &title = m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataTitle).toString();
const QString &author = m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaDataAuthor).toString();
const QString &leftFooter = author;
const QString &middleFooter = QString();
const QString &rightFooter = QDateTime::currentDateTime().toString(QStringLiteral("d.M.yyyy h:mm"));
Q_UNUSED(title);
Q_UNUSED(author);
Q_UNUSED(leftFooter);
Q_UNUSED(middleFooter);
Q_UNUSED(rightFooter);
QTextCharFormat defaultFontFormat;
defaultFontFormat.setForeground(QBrush(QColor("black")));
defaultFontFormat.setFontPointSize(14);
QTextCharFormat largeFontFormat = defaultFontFormat;
largeFontFormat.setFontWeight(QFont::Bold);
largeFontFormat.setFontPointSize(28);
const QFont &defaultFont = defaultFontFormat.font();
int marginInt = defaultFont.pixelSize();
const QSizeF pageSize = printer->paperRect(QPrinter::Point).size();
const QSizeF drawingSize = pageSize - QSizeF(2 * marginInt, 5 * marginInt) * 1.5;
QMarginsF margins;
margins.setLeft(marginInt);
margins.setTop(marginInt);
printer->setPageMargins(margins);
printer->setCreator(QStringLiteral("RDE-") + qAppName());
printer->setDocName(title);
QTextDocument document;
QPainter painter(printer.data());
const QUrl imageUrl(QLatin1String("PlanEditor://sitMapScreenshot.png"));
document.addResource(QTextDocument::ImageResource, imageUrl, QVariant(image));
qreal width = drawingSize.width() * 0.9;
qreal height = drawingSize.height() * 0.9;
QString html;
html += QStringLiteral("<html>\n");
html += QStringLiteral(" <br>\n");
html += QStringLiteral(" <h1 align=\"center\" style=\"font-size:48pt\" >\n");
html += title;
html += QStringLiteral(" </h1>\n");
html += QStringLiteral(" <hr width=\"%1\"> <br>\n").arg(width);
html += QStringLiteral(" <center>\n");
html += QStringLiteral(" <img src=\"%1\" width=\"%2\" height=\"%3\" />\n").arg(QStringLiteral("PlanEditor://sitMapScreenshot.png")).arg(width).arg(height);
html += QStringLiteral(" </center> <br>\n");
html += QStringLiteral(" <hr width=\"%1\">\n").arg(width);
html += QStringLiteral(" <table width=\"%1\">\n").arg(width);
html += QStringLiteral(" <tr>\n");
html += QStringLiteral(" <th align=\"left\" style=\"font-size:12pt\" >\n");
html += leftFooter;
html += QStringLiteral(" </th>\n");
html += QStringLiteral(" <th align=\"center\" style=\"font-size:12pt\" >\n");
html += middleFooter;
html += QStringLiteral(" </th>\n");
html += QStringLiteral(" <th align=\"right\" style=\"font-size:12pt\" >\n");
html += rightFooter;
html += QStringLiteral(" </th>\n");
html += QStringLiteral(" <tr>\n");
html += QStringLiteral(" </table>\n");
html += QStringLiteral("<html>\n");
document.setHtml(html);
document.drawContents(&painter);
#ifdef DEBUG_MSGBOX
html = QStringLiteral("<html>\n");
html += QStringLiteral(" <br>\n");
html += QStringLiteral(" <h1 align=\"center\" style=\"font-size:48pt\" >\n");
html += title + tr("Jörg");
html += QStringLiteral(" </h1>\n");
html += QStringLiteral(" <hr> <br>\n");
html += QStringLiteral(" <p> Alle Kühe essen Heu Cälber mögen besseres Futter. \n");
html += QStringLiteral("Teigwaren heißen Teigwaren weil Teigwaren Teig waren.</p>\n");
static QMessageBox *box = new QMessageBox();
box->setAttribute(Qt::WA_DeleteOnClose, true);
box->setTextFormat(Qt::RichText);
box->addButton(new QPushButton(tr("close"), box), QMessageBox::AcceptRole);
box->setText(html);
box->show();
#endif
eventLoop.quit();
});
if (m_internal->m_map->toImage().isNull())
{
disconnect(slotMetaObj);
QString msg = QObject::tr("Creating map image for printing failed");
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, this->title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << msg;
return;
}
eventLoop.exec();
disconnect(slotMetaObj);
}
}
void PlanEditor::onPlanReset()
{
qDebug() << LOGFUNCTION << " START";
if (m_internal->m_geoModel == nullptr)
return;
m_internal->m_geoModel->clearModel();
setNameOfPlan(QString());
initializePlan();
}
void PlanEditor::onPlanCreate()
{
abortCurrentBboxRubberband();
onAskSaveChanges();
onPlanReset();
onMetaData();
}
static QString addPlanFileSuffix(const QString &filePath, const QString &selectedNameFilter)
{
QString defaultSuffix(QStringLiteral(".plan"));
QString suffix;
int suffixDefStart = selectedNameFilter.lastIndexOf(QLatin1Char('(')) + 1;
int suffixDefEnd = selectedNameFilter.lastIndexOf(QLatin1Char(')')) - 1;
if (suffixDefStart < suffixDefEnd)
{
const QString &suffixFilter = selectedNameFilter.mid(suffixDefStart, suffixDefEnd - suffixDefStart + 1);
const QList<QString> &suffixVector = suffixFilter.split(QLatin1Char(' '), Qt::SkipEmptyParts);
if (!suffixVector.isEmpty())
{
const QString &filter = suffixVector.first();
int indexOfDot = filter.lastIndexOf(QLatin1Char('.'));
if (indexOfDot >= 0)
suffix = filter.right(filter.length() - indexOfDot);
}
}
if (suffix.isEmpty()) suffix = QString(defaultSuffix);
if ((suffix == QStringLiteral(".*")) || (filePath.endsWith(suffix))) return filePath;
return filePath + suffix;
}
void PlanEditor::onPlanLoad()
{
abortCurrentBboxRubberband();
if (m_internal->m_geoModel == nullptr) return;
onAskSaveChanges();
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Open"));
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
if (!m_internal->m_currentFileName.isEmpty())
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
{
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
if (!fileList.isEmpty())
{
m_internal->m_currentFileName = fileList.first();
loadFromFile(m_internal->m_currentFileName);
QFileInfo fileInfo(m_internal->m_currentFileName);
setNameOfPlan(fileInfo.baseName());
}
}
}
void PlanEditor::onPlanSave()
{
abortCurrentBboxRubberband();
if (m_internal->m_geoModel == nullptr)
return;
if (!m_internal->m_currentFileName.isEmpty())
{
QFileInfo fileInfo(m_internal->m_currentFileName);
if (fileInfo.exists())
{
saveToFile(fileInfo.absoluteFilePath());
return;
}
}
onPlanSaveAs();
}
void PlanEditor::onPlanSaveAs()
{
abortCurrentBboxRubberband();
if (m_internal->m_geoModel == nullptr)
return;
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Store current Plan"));
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
if (!m_internal->m_currentFileName.isEmpty())
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
{
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
if (!fileList.isEmpty())
{
m_internal->m_currentFileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
saveToFile(m_internal->m_currentFileName);
QFileInfo fileInfo(m_internal->m_currentFileName);
setNameOfPlan(fileInfo.baseName());
m_internal->removeAutosaveFile();
}
}
}
void PlanEditor::onPlanSaveSelected()
{
abortCurrentBboxRubberband();
if (m_internal->m_geoModel == nullptr) return;
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Store Selected Plan Items"));
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
m_internal -> m_fileDialog -> selectFile(QString());
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
{
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
if (!fileList.isEmpty())
{
m_internal->m_currentFileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
saveSelectedToFile(m_internal->m_currentFileName);
}
}
}
void PlanEditor::onPlanAutoSave()
{
if (m_internal->m_geoModel == nullptr) return;
if (m_internal->m_geoModel->modificationCounter() < 1) return;
const QString &crt = QStringLiteral("/tmp/plan_") + QString::number(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
QFile file(crt);
if (file.open(QIODevice::WriteOnly))
file.write(m_internal->m_geoModel->toByteArray());
}
void PlanEditor::onPlanImport()
{
abortCurrentBboxRubberband();
if (m_internal->m_geoModel == nullptr) return;
m_internal -> m_fileDialog -> setWindowTitle(tr("Plan Editor - Select File to Import"));
m_internal -> m_fileDialog -> setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
m_internal -> m_fileDialog -> setDirectory(planDefaultDirectory());
if (!m_internal->m_currentFileName.isEmpty())
m_internal -> m_fileDialog -> selectFile(m_internal->m_currentFileName);
if (m_internal->m_fileDialog->exec() == QDialog::DialogCode::Accepted)
{
const QStringList &fileList = m_internal->m_fileDialog->selectedFiles();
if (!fileList.isEmpty())
{
const QString & fileName = addPlanFileSuffix(fileList.first(), m_internal->m_fileDialog->selectedNameFilter());
importFromFile(fileName);
}
}
}
void PlanEditor::onCenterViewSelected()
{
const qreal eps = 0.00000000001;
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
qreal viewAreaMinX = std::numeric_limits<qreal>::max();
qreal viewAreaMinY = std::numeric_limits<qreal>::max();
qreal viewAreaMaxX = -std::numeric_limits<qreal>::max();
qreal viewAreaMaxY = -std::numeric_limits<qreal>::max();
for (SituationMap::UniqueMapId uid : std::as_const(m_internal->m_selectionList))
{
SituationMap::AbstractMapObject *mapObj = m_internal->m_map->objectFactory().idToMapObject(uid);
if (!mapObj) continue;
SituationMap::BoundingBox objBbox;
mapObj->boundingBox(objBbox);
switch (objBbox.extentType())
{
case SituationMap::BoundingBox::ExtentType::Sim :
{
const SituationMap::PositionCont &bboxVerticies = objBbox.positions();
for (const SituationMap::Point3D &v : bboxVerticies)
{
if (viewAreaMinX > v.x()) viewAreaMinX = v.x();
if (viewAreaMinY > v.y()) viewAreaMinY = v.y();
if (viewAreaMaxX < v.x()) viewAreaMaxX = v.x();
if (viewAreaMaxY < v.y()) viewAreaMaxY = v.y();
}
} break;
case SituationMap::BoundingBox::ExtentType::Pixel :
{
const SituationMap::Point3D &v = objBbox.center();
if (viewAreaMinX > v.x()) viewAreaMinX = v.x();
if (viewAreaMinY > v.y()) viewAreaMinY = v.y();
if (viewAreaMaxX < v.x()) viewAreaMaxX = v.x();
if (viewAreaMaxY < v.y()) viewAreaMaxY = v.y();
} break;
default : break;
}
}
if (viewAreaMinX < std::numeric_limits<qreal>::max())
{
qreal dx = (viewAreaMaxX - viewAreaMinX) * 0.5;
qreal dy = (viewAreaMaxY - viewAreaMinY) * 0.5;
qreal cx = viewAreaMinX + dx;
qreal cy = viewAreaMinY + dy;
dx *= 1.05;
dy *= 1.05;
if ((fabs(dx) < eps) || (fabs(dy) < eps))
{
QRectF extent = m_internal->m_map->extent();
dx = extent.width() * 0.5;
dy = extent.height() * 0.5;
}
viewAreaMinX = cx - dx;
viewAreaMinY = cy - dy;
viewAreaMaxX = cx + dx;
viewAreaMaxY = cy + dy;
m_internal->m_map->setExtent(viewAreaMinX, viewAreaMinY, viewAreaMaxX, viewAreaMaxY);
}
}
void PlanEditor::onClearSelection()
{
abortCurrentBboxRubberband();
const auto selList = m_internal->m_selectionList;
for (SituationMap::UniqueMapId uid : selList)
setSelected(uid, false);
m_internal->m_selectionList.clear();
ModelTreeWidgetItem::clearSelection(m_internal->m_modelTreeWidget->rootItem());
onHideDialogTab();
}
void PlanEditor::onRubberbandAbort(SituationMap::RB::RubberbandBase *rubberband)
{
if (rubberband != nullptr)
{
if (!m_internal->m_rbBackupNodeCoordinates.isEmpty())
{
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rubberband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
}
if (!rubberband->autoDelete()) rubberband->deleteMySelf();
}
m_internal->m_rbBackupNodeCoordinates.clear();
}
class DropCreateSymbol : public LtsWidgets::LtsDropHandler
{
PlanEditor *m_planEditor;
PlanEditor::InternalData *m_planEditorInternal;
QString m_sidc;
mutable bool m_createParticipant;
public:
DropCreateSymbol(PlanEditor *planEditor, PlanEditor::InternalData *planEditorInternal, const QString &sidc, bool createParticipant = false )
: LtsWidgets::LtsDropHandler()
, m_planEditor(planEditor)
, m_planEditorInternal(planEditorInternal)
, m_sidc(sidc)
, m_createParticipant(createParticipant) {;}
virtual ~DropCreateSymbol() = default;
void doDrop(int x, int y, const QMimeData * mimeData) const override
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
const AdvancedSymbology::SymbolDictionary &symbolDict = m_planEditorInternal->m_map->symbolDictionary();
const QString &baseCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(m_sidc);
const AdvancedSymbology::SymbolProperties &symbolProps = symbolDict.symbolProperties(baseCode);
if ((nullptr != mimeData) && mimeData->hasFormat(QStringLiteral("Participant")))
{
const QByteArray & participantInfo = mimeData->data(QStringLiteral("Participant"));
m_createParticipant = m_createParticipant || (participantInfo.toInt() > 0);
}
if (symbolProps.key() == AdvancedSymbology::SidcCodec::decodeRawSidc(baseCode))
{
m_planEditorInternal->m_symbolCurrentSidc = m_sidc;
SituationMap::RB::Rubberband *rubberband = m_planEditorInternal->m_map->rubberbandFactory().createSymbol(m_sidc, QPoint(x, y), m_planEditorInternal);
if (rubberband != nullptr)
{
SituationMap::RB::RubberbandPointFeature *pointFeatureRB = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
if ((pointFeatureRB) && (pointFeatureRB->getMaximumPointCount() < 2))
{
QVector<QPointF> pointList;
pointList += m_planEditorInternal->m_map->viewPortWindowPointToMapCoordinate(QPointF(x, y));
pointFeatureRB->setCoordinateVector(pointList, SituationMap::RB::CoordinateSystem::Map);
m_planEditor->onSymbolCreate(rubberband,m_createParticipant);
pointFeatureRB -> deleteMySelf();
return;
}
m_planEditorInternal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> setPreviewSize(ICON_SIZE);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, [this](SituationMap::RB::RubberbandBase *rubberband)
{
m_planEditor->onSymbolCreate(rubberband, m_createParticipant);
});
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
}
else
{
QString msg = QObject::tr("Creating rubberband failed, may be wrong sidc (%1)").arg(m_planEditorInternal->m_symbolCurrentSidc);
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), msg, m_planEditor->title());
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << msg;
}
}
}
};
qulonglong PlanEditor::createSymbolDropEvent(const QString &sidc)
{
bool createParticipant = false;
if (m_internal->m_lookupSymbolManager)
{
createParticipant = m_internal->m_lookupSymbolManager->isParticipantDialog();
}
return m_internal->m_dropEventManager->add(new DropCreateSymbol(this, m_internal.get(), sidc, createParticipant));
}
SituationMap::RB::Rubberband *PlanEditor::onSymbolCreateRubberband(const QString &currentSidc, bool createParticipant )
{
bool bCreateParticipant = createParticipant && (m_internal->m_lookupSymbolManager) && (m_internal->m_lookupSymbolManager->isParticipantDialog());
onClearSelection();
const AdvancedSymbology::SymbolDictionary &symbolDict = m_internal->m_map->symbolDictionary();
const QString &baseKey = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(currentSidc);
const AdvancedSymbology::SymbolProperties &symbolProps = symbolDict.symbolProperties(baseKey);
if (symbolProps.key() == AdvancedSymbology::SidcCodec::decodeRawSidc(baseKey))
{
m_internal->m_symbolCurrentSidc = currentSidc;
SituationMap::RB::Rubberband *rubberband = m_internal->m_map->rubberbandFactory().createSymbol(currentSidc, m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> setPreviewSize(ICON_SIZE);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, bCreateParticipant](SituationMap::RB::RubberbandBase *rubberband)
{
onSymbolCreate(rubberband, bCreateParticipant);
});
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband failed, may be wrong sidc (" << m_internal->m_symbolCurrentSidc << ")";
}
return rubberband;
}
return nullptr;
}
void PlanEditor::onChooseSymbol()
{
onClearSelection();
if (m_internal->m_symbolDictLoaded) m_internal->m_lookupSymbolManager->onOpenSymbolDialog();
};
void PlanEditor::onSymbolCreate(SituationMap::RB::RubberbandBase *rubberband, bool createParticipant)
{
SituationMap::RB::Rubberband *rbnd = dynamic_cast<SituationMap::RB::Rubberband*>(rubberband);
if (nullptr == m_internal->m_geoModel) return;
if (nullptr == rbnd) return;
SituationMap::RB::RubberbandRectangle *rbRectangle = dynamic_cast<SituationMap::RB::RubberbandRectangle * >(rbnd);
SituationMap::RB::RubberbandEllipse *rbEllipse = dynamic_cast<SituationMap::RB::RubberbandEllipse * >(rbnd);
SituationMap::RB::RubberbandCorridor *rbCorridor = dynamic_cast<SituationMap::RB::RubberbandCorridor * >(rbnd);
bool isAttributedSymbol = (rbRectangle || rbEllipse || rbCorridor);
const QString &sidc = rbnd->getPreviewSidc();
QList<QPointF> points;
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
QString sidcAttributes;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rbnd->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
if (isAttributedSymbol)
{
if (rbRectangle && (nullptr == rbEllipse))
{
QPointF center;
qreal length;
qreal width;
QPointF dir;
rbRectangle->rectangleParameter(center, length, width, dir);
#ifdef SPEC_MIL2525D_RELATED
points += center;
#else
points = rbRectangle->coordinateVector().toList();
#endif
QMap<QString, QVariant> attrMap;
attrMap[QStringLiteral("length")] = length;
attrMap[QStringLiteral("width")] = width;
attrMap[QStringLiteral("attitude")] = SituationMap::MathUtils::getAngleDegreeNorth(QPointF(0, 0), dir);
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
}
if (rbEllipse)
{
QPointF center;
qreal diameter;
qreal d2;
QPointF dir;
rbEllipse->rectangleParameter(center, diameter, d2, dir);
points += center;
QMap<QString, QVariant> attrMap;
attrMap[QStringLiteral("radius")] = diameter * 0.5;
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
}
if (rbCorridor)
{
qreal corridorWidth = rbCorridor->corridorWidth() * 0.5;
const auto coords = rbCorridor->centerLine();
points.reserve(coords.size());
for (const QPointF &coord : coords)
points += coord;
QMap<QString, QVariant> attrMap;
attrMap[QStringLiteral("width")] = corridorWidth;
sidcAttributes = m_internal->m_geoModel->buildSymbolAttributeString(attrMap);
}
}
else
{
const auto coords = rubberband->coordinateVector();
points.reserve(coords.size());
for (const QPointF &coord : coords)
points += coord;
}
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating symbol sidc='" << sidc << "'; Attributes='" << sidcAttributes << "'";
if (!node.isValid())
{
m_internal->m_geoModel->startUndoBlock();
{
if (!sidcAttributes.isEmpty())
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SIDC_Attributes, sidcAttributes);
SituationMap::GeometryModel::PrimitiveType symbolType = SituationMap::GeometryModel::PrimitiveType::Symbol;
if (AdvancedSymbology::SidcCodec::SidcType::CivilXml != AdvancedSymbology::SidcCodec::decodeSidcType(sidc))
{
symbolType = createParticipant
? SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol : SituationMap::GeometryModel::PrimitiveType::DictionarySymbol;
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SIDC, sidc);
}
else
{
const QString &symbolId = AdvancedSymbology::SidcCodec::decodeRawSidc(sidc);
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::SymbolId, symbolId );
}
node = addGeoModelPrimitive(symbolType, points, attributes);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr("create symbol", TR_UNDO_TOKEN));
onUpdateView();
setSelected(node);
}
else
{
if (!m_internal->m_rbBackupNodeCoordinates.isEmpty())
{
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
}
m_internal->m_geoModel->startUndoBlock();
{
addStyleAttributes(node, false);
m_internal->m_geoModel->setPrimitiveAttribute(node, SituationMap::GeometryModel::Attribute::SIDC, sidc);
if (!sidcAttributes.isEmpty())
m_internal->m_geoModel->setPrimitiveAttribute(node, SituationMap::GeometryModel::Attribute::SIDC_Attributes, sidcAttributes);
m_internal->m_geoModel->setPrimitivePoints(node, points);
}
m_internal->m_geoModel->endUndoBlock(tr("modifiy symbol geometry", TR_UNDO_TOKEN));
}
m_internal->m_rbBackupNodeCoordinates.clear();
}
SituationMap::RB::Rubberband *PlanEditor::onLineCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband failed! May there is another active rubberband";
return nullptr;
}
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(false);
rubberband -> maximumPointCount(2);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onLineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
void DropCreateLine::doDrop(int x, int y, const QMimeData *) const
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
if (rubberband != nullptr)
{
m_planEditorInternal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(false);
rubberband -> maximumPointCount(2);
double dx = m_planEditorInternal->m_map->width() * 0.25;
double dy = m_planEditorInternal->m_map->height() * 0.25;
QVector<QPointF> lineCoordinates;
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
rubberband->setCoordinateVector(lineCoordinates);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onLineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
}
void PlanEditor::onLineCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (m_internal->m_geoModel == nullptr) return;
if (rubberband == nullptr) return;
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
if (lineRubberband)
{
QList<QPointF> points;
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
const auto coords = lineRubberband->coordinateVector();
points.reserve(coords.size());
for (const QPointF &coord : coords)
points += coord;
if (!node.isValid())
{
m_internal->m_geoModel->startUndoBlock();
{
node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Line, points, attributes);
}
m_internal->m_geoModel->endUndoBlock(tr("create line", TR_UNDO_TOKEN));
onUpdateView();
setSelected(node);
}
else
{
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->setPrimitivePoints(node, points);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr("modifiy line geometry", TR_UNDO_TOKEN));
}
}
}
SituationMap::RB::Rubberband *PlanEditor::onPolylineCreateRubberband()
{
onClearSelection();
if (nullptr == m_internal->m_geoModel)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(false);
rubberband -> minimumPointCount(3);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolylineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
void DropCreatePolyLine::doDrop(int x, int y, const QMimeData *) const
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
SituationMap::RB::RubberbandMultiPointFeature *rubberband;
if (m_smooth) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_planEditorInternal);
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
if (rubberband != nullptr)
{
m_planEditorInternal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(false);
double dx = m_planEditorInternal->m_map->width() * 0.25;
double dy = m_planEditorInternal->m_map->height() * 0.25;
QVector<QPointF> lineCoordinates;
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
rubberband->setCoordinateVector(lineCoordinates);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onPolylineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
}
void PlanEditor::onPolylineCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (m_internal->m_geoModel == nullptr) return;
if (rubberband == nullptr) return;
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
SituationMap::RB::RubberbandSmoothLine *smoothLine = dynamic_cast<SituationMap::RB::RubberbandSmoothLine *>(rubberband);
if (lineRubberband)
{
QList<QPointF> points;
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
const auto coords = lineRubberband->coordinateVector();
points.reserve(coords.size());
for (const QPointF &coord : coords)
points += coord;
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Close, QVariant(false));
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Fill, QVariant(false));
if (!node.isValid())
{
m_internal->m_geoModel->startUndoBlock();
{
if (smoothLine) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Spline, points, attributes);
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Polyline, points, attributes);
}
m_internal->m_geoModel->endUndoBlock((smoothLine) ? tr("create new smooth line", TR_UNDO_TOKEN) : tr("create new polyline", TR_UNDO_TOKEN));
onUpdateView();
setSelected(node);
}
else
{
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->setPrimitivePoints(node, points);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr("modifiy polyline geometry", TR_UNDO_TOKEN));
}
}
}
SituationMap::RB::Rubberband *PlanEditor::onSmoothLineCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(false);
rubberband -> minimumPointCount(3);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolylineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
SituationMap::RB::Rubberband *PlanEditor::onPolygonCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(true);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onPolygonCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
void DropCreatePolygon::doDrop(int x, int y, const QMimeData *) const
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
SituationMap::RB::RubberbandMultiPointFeature *rubberband;
if (m_smooth) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandSmoothLine>(m_planEditorInternal);
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(m_planEditorInternal);
if (rubberband != nullptr)
{
m_planEditorInternal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableClosed(true);
double dx = m_planEditorInternal->m_map->width() * 0.25;
double dy = m_planEditorInternal->m_map->height() * 0.25;
QVector<QPointF> lineCoordinates;
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y));
lineCoordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
rubberband->setCoordinateVector(lineCoordinates);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onPolygonCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
}
void PlanEditor::onPolygonCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (m_internal->m_geoModel == nullptr) return;
if (rubberband == nullptr) return;
SituationMap::RB::RubberbandMultiPointFeature *lineRubberband = dynamic_cast<SituationMap::RB::RubberbandMultiPointFeature *>(rubberband);
SituationMap::RB::RubberbandSmoothLine *smoothLine = dynamic_cast<SituationMap::RB::RubberbandSmoothLine *>(rubberband);
if (lineRubberband)
{
QList<QPointF> points;
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)lineRubberband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
const auto coords = lineRubberband->coordinateVector();
points.reserve(coords.size());
for (const QPointF &coord : coords)
points += coord;
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Close, QVariant(true));
if (!node.isValid())
{
m_internal->m_geoModel->startUndoBlock();
{
if (smoothLine) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Spline, points, attributes);
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Polyline, points, attributes);
}
m_internal->m_geoModel->endUndoBlock(tr("create polygon", TR_UNDO_TOKEN));
onUpdateView();
setSelected(node);
}
else
{
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->setPrimitivePoints(node, points);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr("modify polygon geoemtry", TR_UNDO_TOKEN));
}
}
}
SituationMap::RB::Rubberband *PlanEditor::onRectangleCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandRectangle *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onRectangleCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
}
return rubberband;
}
void DropCreateRectangle::doDrop(int x, int y, const QMimeData *) const
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
SituationMap::RB::RubberbandRectangle *rubberband;
if (m_ellipse) rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_planEditorInternal);
else rubberband = m_planEditorInternal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandRectangle>(m_planEditorInternal);
if (rubberband != nullptr)
{
m_planEditorInternal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
double dx = m_planEditorInternal->m_map->width() * 0.4;
double dy = m_planEditorInternal->m_map->height() * 0.25;
QVector<QPointF> coordinates;
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y - dy));
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y - dy));
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x + dx, y + dy));
coordinates += m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x - dx, y + dy));
rubberband->setCoordinateVector(coordinates);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, m_planEditor, &PlanEditor::onRectangleCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, m_planEditor, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(m_planEditor->topLevelWidget(), QObject::tr("Creating rubberband failed! May there is another active rubberband"), m_planEditor->title());
ERROR_LOG(m_planEditorInternal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
}
}
void PlanEditor::onRectangleCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (m_internal->m_geoModel == nullptr) return;
if (rubberband == nullptr) return;
SituationMap::RB::RubberbandRectangle *rband = dynamic_cast<SituationMap::RB::RubberbandRectangle *>(rubberband);
SituationMap::RB::RubberbandEllipse *relli = dynamic_cast<SituationMap::RB::RubberbandEllipse *>(rubberband);
if (rband)
{
const QList<QPointF> &points = rband->coordinateVector().toList();
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
QPointF rectCenter;
QPointF rectOrientation;
qreal rectWidth;
qreal rectHeight;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
rband->rectangleParameter(rectCenter, rectWidth, rectHeight, rectOrientation, SituationMap::RB::CoordinateSystem::Geo);
qreal cosPhi = rectOrientation.x();
qreal phi = acos(cosPhi) * 180.0 / MathConst::pi;
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Center, QVariant(rectCenter));
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Width, QVariant(rectWidth));
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Height, QVariant(rectHeight));
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Rotate, QVariant(phi));
if (relli)
{
if (relli->hasSector())
{
auto getAngle = [](qreal sinPhi, qreal cosPhi) -> qreal
{
qreal phi = acos(cosPhi);
if (sinPhi < 0) phi = MathConst::pi_two - phi;
return (phi * 180.0 / MathConst::pi);
};
QPointF sectorStartVec = relli->sectorStart();
QPointF sectorEndVec = relli->sectorEnd();
qreal sectorStart = getAngle(sectorStartVec.y(), sectorStartVec.x());
qreal sectorEnd = getAngle(sectorEndVec.y(), sectorEndVec.x());
qreal sectorExtent = sectorEnd - sectorStart;
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Start, QVariant(sectorStart));
attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Extent, QVariant(sectorExtent));
}
else attributes += QPair<SituationMap::GeometryModel::Attribute, QVariant>(SituationMap::GeometryModel::Attribute::Extent, QVariant(360));
}
if (!node.isValid())
{
const char *undoToken = (relli) ? "create ellipse" : "create rectangle";
m_internal->m_geoModel->startUndoBlock();
{
if (relli) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Ellipse, points, attributes);
else node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Rectangle, points, attributes);
}
m_internal->m_geoModel->endUndoBlock(tr(undoToken, TR_UNDO_TOKEN));
onUpdateView();
setSelected(node);
}
else
{
const char *undoToken = (relli) ? "modify ellipse geometry" : "modify rectangle geoemtry";
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->setPrimitivePoints(node, points);
for (const auto &attrPair : std::as_const(attributes))
m_internal->m_geoModel->setPrimitiveAttribute(node, attrPair.first, attrPair.second);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr(undoToken, TR_UNDO_TOKEN));
}
}
}
SituationMap::RB::Rubberband *PlanEditor::onEllipseCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandEllipse *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableSector();
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onRectangleCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for rectangles failed.";
}
return rubberband;
}
SituationMap::RB::Rubberband *PlanEditor::onTextLineCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandPointFeature>(m_internal.get());
if (rubberband != nullptr)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onTextLineCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
SituationMap::RB::Rubberband *PlanEditor::onTextBoxPixelCreateRubberband()
{
onClearSelection();
if (m_internal->m_geoModel == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Internal critical failure"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "GeometryModel doesn't exist any more!";
return nullptr;
}
SituationMap::RB::RubberbandPointFeature *rubberband = m_internal->m_map->rubberbandFactory().create<SituationMap::RB::RubberbandPointFeature>(m_internal.get());
if (rubberband)
{
m_internal->m_session.hideAnimated();
rubberband -> setAutoDelete(true);
rubberband -> enableFinishAfterConstruction(true);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &PlanEditor::onTextBoxPixelCreate);
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &PlanEditor::onRubberbandAbort);
}
else
{
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), tr("Creating rubberband failed! May there is another active rubberband"), title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << "Creating rubberband for multi points features failed.";
}
return rubberband;
}
SituationMap::GeometryModel::Node PlanEditor::buildTextNode(const QPointF &loc)
{
QList<QPair<SituationMap::GeometryModel::Attribute, QVariant> > attributes;
QList<QPointF> points;
SituationMap::GeometryModel::Node node;
points += loc;
m_internal->m_geoModel->startUndoBlock();
{
node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Text
, points
, attributes
, SituationMap::IdHandler::BadId
, m_internal->m_attributeDialogManager->textLines());
}
m_internal->m_geoModel->endUndoBlock(tr("create text", TR_UNDO_TOKEN));
return node;
}
void PlanEditor::buildTextBoxPixelNode(const QPointF &locPixel)
{
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
SituationMap::PBTB_ID pbtbId(PLAN_EDITOR_TEXTBOX_PARENT_ID);
SituationMap::PixelTextBoxData ptbd;
ptbd.m_position = locPixel.toPoint();
QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, true);
INFO_LOG(m_internal->m_logger) << " new TextBox created: newTextEdit = " << newTextEdit
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
m_internal->m_ourTextBoxIds.append(pbtbId);
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxDoubleClickEvent,
this, &PlanEditor::onTextEditDialogRequested, Qt::UniqueConnection);
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxGeometryChanged,
this, &PlanEditor::onTextEditGeometryChanged, Qt::UniqueConnection);
connect(&pixelBasedTextBoxHandler, &SituationMap::PixelBasedTextBoxHandler::pixelBasedTextBoxRemoveRequestedEvent,
this, &PlanEditor::onTextEditRemoveRequested, Qt::UniqueConnection);
onTextEditDialogRequested(pbtbId);
}
void PlanEditor::writeTextBoxDataToModel()
{
INFO_LOG(m_internal->m_logger) << LOGFUNCTION << " START"
<< ", m_internal->m_textBoxIds.size = " << m_internal->m_ourTextBoxIds.size();
QVector<SituationMap::PixelTextBoxData> ptbdVec;
ptbdVec.reserve(m_internal->m_ourTextBoxIds.size());
const SituationMap::PBTB_ID pbtbIdAsParent(PLAN_EDITOR_TEXTBOX_PARENT_ID);
const SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
const QVector<SituationMap::PBTB_ID> pbtbIdVec = pixelBasedTextBoxHandler.getAllIdsOfParent(pbtbIdAsParent);
for (const SituationMap::PBTB_ID &pbtbId : std::as_const(pbtbIdVec))
{
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
if (data.isEmpty())
continue;
ptbdVec.append(data);
}
const QString &str = SituationMap::PixelTextBoxData::pixelTextBoxContainerToJsonStr(ptbdVec, QJsonDocument::JsonFormat::Compact);
m_internal->m_geoModel->setModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes, str);
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void DropCreateTextLine::doDrop(int x, int y, const QMimeData *) const
{
m_planEditor->onClearSelection();
if (nullptr == m_planEditorInternal) return;
if (nullptr == m_planEditorInternal->m_geoModel) return;
const QPointF loc = m_planEditorInternal->m_map->viewPortWindowPointToGeoCoordinate(QPointF(x, y));
const SituationMap::GeometryModel::Node node = m_planEditor->buildTextNode(loc);
m_planEditor->onUpdateView();
m_planEditor->setSelected(node);
}
void PlanEditor::onTextLineCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (m_internal->m_geoModel == nullptr) return;
if (rubberband == nullptr) return;
SituationMap::RB::RubberbandPointFeature *pointRubberband = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
if (pointRubberband)
{
const QPointF &loc = pointRubberband->singleCoordinate();
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)pointRubberband->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
if (!node.isValid())
{
node = buildTextNode(loc);
onUpdateView();
setSelected(node);
}
else
{
m_internal->m_geoModel->setPrimitivePoints(node, m_internal->m_rbBackupNodeCoordinates);
m_internal->m_geoModel->startUndoBlock();
{
m_internal->m_geoModel->setPrimitivePoints(node, QList<QPointF>() << loc);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr("modifiy text position", TR_UNDO_TOKEN));
}
}
m_internal->m_rbBackupNodeCoordinates.clear();
}
void PlanEditor::onTextBoxPixelCreate(SituationMap::RB::RubberbandBase *rubberband)
{
if (!m_internal->m_geoModel || !rubberband)
return;
SituationMap::RB::RubberbandPointFeature *pointRubberband = dynamic_cast<SituationMap::RB::RubberbandPointFeature *>(rubberband);
if (!pointRubberband)
return;
const QVector<QPointF> &coordsRef = pointRubberband->coordinateVectorPixel();
const QPointF &locPixel = coordsRef.first();
buildTextBoxPixelNode(locPixel);
}
void PlanEditor::onTextBoxPixelTextChanged(const QString &htmlText)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
if (!m_internal->m_map)
return;
const SituationMap::PBTB_ID currentPbtbId = m_internal->m_textBoxIdInEditing;
if (!currentPbtbId.isValid())
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIdInEditing invalid: " << currentPbtbId.toString();
return;
}
if (!m_internal->m_ourTextBoxIds.contains(currentPbtbId))
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIds does not have currentPbtbId = " << currentPbtbId;
return;
}
if (!m_internal->m_textBoxTextEdit)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
return;
}
m_internal->m_textBoxTextEdit->setHtml(htmlText);
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onTextBoxPixelBackgroundColorChanged(const QColor &backgroundColor)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START, backgroundColor= " << backgroundColor;
if (!backgroundColor.isValid())
return;
const SituationMap::PBTB_ID currentPbtbId = m_internal->m_textBoxIdInEditing;
if (!currentPbtbId.isValid())
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIdInEditing invalid: " << currentPbtbId.toString();
return;
}
if (!m_internal->m_ourTextBoxIds.contains(currentPbtbId))
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_internal->m_textBoxIds does not have currentPbtbId = " << currentPbtbId;
return;
}
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
SituationMap::PixelTextBoxData data = pixelBasedTextBoxHandler.getPixelTextBoxData(currentPbtbId);
if (data.isEmpty())
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
return;
}
data.m_backgroundColor = backgroundColor;
pixelBasedTextBoxHandler.updateTextBox(currentPbtbId, data);
writeTextBoxDataToModel();
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END, backgroundColor= " << backgroundColor;
}
void PlanEditor::onTextBoxPixelTextApplied(const QString &htmlText)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
m_internal->m_htmlTextForCancelation = htmlText;
writeTextBoxDataToModel();
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onTextBoxPixelCanceled()
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
if (!m_internal->m_textBoxTextEdit)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " m_textBoxTextEdit invalid: " << m_internal->m_textBoxTextEdit;
return;
}
m_internal->m_textBoxTextEdit->setHtml(m_internal->m_htmlTextForCancelation);
writeTextBoxDataToModel();
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onTextBoxPixelClosed()
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
pixelBasedTextBoxHandler.removeSelection();
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " END";
}
void PlanEditor::onTransformMove(SituationMap::RB::RubberbandBase *rubberband)
{
SituationMap::RB::RubberbandTransformMove *rMove = dynamic_cast<SituationMap::RB::RubberbandTransformMove *>(rubberband);
if (rMove == nullptr) return;
QList<SituationMap::UniqueMapId> *featureToTransform = static_cast<QList<SituationMap::UniqueMapId>*>(rMove->userData());
rMove->setUserData(nullptr);
delete featureToTransform;
m_internal->m_geoModel->endUndoBlock(tr("move feature(s)", TR_UNDO_TOKEN));
}
void PlanEditor::onTransformRotate(SituationMap::RB::RubberbandBase *rubberband)
{
SituationMap::RB::RubberbandTransformRotate *rRotate = dynamic_cast<SituationMap::RB::RubberbandTransformRotate *>(rubberband);
if (rRotate == nullptr) return;
for (auto uid : std::as_const(m_internal->m_selectionList))
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
if (modelPrimitive.isValid())
{
QList<QPointF> vertexList = m_internal->m_geoModel->getPrimitivePoints(modelPrimitive);
m_internal->m_geoModel->setPrimitivePoints(modelPrimitive, vertexList);
}
}
}
void PlanEditor::onTransformScale(SituationMap::RB::RubberbandBase * )
{
}
void PlanEditor::onEditAttributes()
{
abortCurrentBboxRubberband();
if (!m_internal -> m_selectionList.isEmpty())
{
SituationMap::UniqueMapId uid = m_internal -> m_selectionList.first();
const SituationMap::GeometryModel::Node &node = m_internal -> m_geoModelRenderer -> getAssociatedNode(m_internal->m_map->objectFactory().idToMapObject(uid));
onShowDialogTab(node);
}
else
onShowDialogTab(SituationMap::GeometryModel::Node());
}
void PlanEditor::onEditGraphicGeometry()
{
abortCurrentBboxRubberband();
if (1 != m_internal->m_selectionList.size()) return;
SituationMap::UniqueMapId uid = m_internal -> m_selectionList.first();
SituationMap::AbstractMapObject *mapObj = m_internal -> m_map->objectFactory().idToMapObject(uid);
const SituationMap::GeometryModel::Node &node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
if (!node.isValid()) return;
SituationMap::GeometryModel::PrimitiveType primitiveType = m_internal->m_geoModel->getType(node);
SituationMap::RB::Rubberband *rubberband = nullptr;
auto previewGeometrySinglePointMove = [this](SituationMap::RB::RubberbandBase * rb) -> bool
{
if (!rb) return true;
SituationMap::AbstractMapObject *mapObj = (SituationMap::AbstractMapObject *)rb->userData();
SituationMap::GeometryModel::Node node = m_internal -> m_geoModelRenderer -> getAssociatedNode(mapObj);
m_internal->m_geoModel->setPrimitivePoints(node, QList<QPointF>() << rb->singleCoordinate());
return true;
};
switch (primitiveType)
{
case SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol:
case SituationMap::GeometryModel::PrimitiveType::DictionarySymbol :
{
const QString &sidc = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::SIDC).toString();
rubberband = onSymbolCreateRubberband(sidc, (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol== primitiveType) );
const QList<QPointF> &pointList = m_internal->m_geoModel->getPrimitivePoints(node);
if (pointList.size() == 1)
{
m_internal->m_rbBackupNodeCoordinates = pointList;
rubberband->installExternalUpdate(previewGeometrySinglePointMove);
}
} break;
case SituationMap::GeometryModel::PrimitiveType::Ellipse : rubberband = onEllipseCreateRubberband(); break;
case SituationMap::GeometryModel::PrimitiveType::Line : rubberband = onLineCreateRubberband(); break;
case SituationMap::GeometryModel::PrimitiveType::Polyline :
{
bool closed = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Close).toBool();
if (closed) rubberband = onPolygonCreateRubberband();
else rubberband = onPolylineCreateRubberband();
} break;
case SituationMap::GeometryModel::PrimitiveType::Rectangle : rubberband = onRectangleCreateRubberband(); break;
case SituationMap::GeometryModel::PrimitiveType::Spline : rubberband = onSmoothLineCreateRubberband(); break;
case SituationMap::GeometryModel::PrimitiveType::Symbol : break;
case SituationMap::GeometryModel::PrimitiveType::Text :
{
const QList<QPointF> &pointList = m_internal->m_geoModel->getPrimitivePoints(node);
if (pointList.size() == 1)
{
m_internal->m_rbBackupNodeCoordinates = pointList;
rubberband = onTextLineCreateRubberband();
rubberband->installExternalUpdate(previewGeometrySinglePointMove);
}
} break;
default : break;
}
if (rubberband == nullptr) return;
QList<QPointF> &&coordinateList = m_internal->m_geoModel->getPrimitivePoints(node);
if (coordinateList.empty())
{
rubberband -> deleteMySelf();
return;
}
SituationMap::RB::RubberbandRectangle *rRectRubber = dynamic_cast<SituationMap::RB::RubberbandRectangle *>(rubberband);
rubberband -> setCoordinateVector(coordinateList.toVector());
rubberband -> setUserData(mapObj);
if ((rRectRubber != nullptr) && (!rRectRubber->rectangleIsValid()))
{
rubberband->deleteMySelf();
QString msg = tr("Map coordinate system differs from simulation coordinate system. Display of rectangles, ellipses ... will be wrong!");
LtsWidgets::LtsMessageDialog::showMessage(topLevelWidget(), msg, title());
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << msg ;
}
SituationMap::RB::RubberbandEllipse *relli = dynamic_cast<SituationMap::RB::RubberbandEllipse *>(rubberband);
if (relli)
{
double start = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Start).toDouble();
double extend = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Extent).toDouble();
bool hasSector = (extend) < 360.0;
relli->enableSector();
if (hasSector)
{
double startAngle = start * MathConst::pi / 180.0;
double endAngle = (start + extend) * MathConst::pi / 180.0;
relli->setSectorStart(sin(startAngle), cos(startAngle));
relli->setSectorEnd(sin(endAngle), cos(endAngle));
}
else
{
relli->setSectorStart(0.0, 1.0);
relli->setSectorEnd(0.0, 1.0);
}
}
}
void PlanEditor::onMoveGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformMove>();
}
void PlanEditor::onRotateGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformRotate>();
}
void PlanEditor::onScaleGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformScale>();
}
void PlanEditor::onDelete()
{
abortCurrentBboxRubberband();
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : std::as_const(m_internal->m_selectionList))
removeFeature(uid, false);
}
m_internal->m_geoModel->endUndoBlock(tr("delete feature(s)", TR_UNDO_TOKEN));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
}
void PlanEditor::onGroup()
{
abortCurrentBboxRubberband();
SituationMap::GeometryModel::NodeList nodeList;
SituationMap::GeometryModel::Node nodeToSelect;
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : std::as_const(m_internal->m_selectionList))
{
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
if (!nodeToSelect.isValid()) nodeToSelect = node;
for (;;)
{
const SituationMap::GeometryModel::Node &group = m_internal->m_geoModel->isInGroup(node);
if (!group.isValid()) break;
node = group;
}
if (!nodeList.contains(node)) nodeList += node;
}
m_internal->m_geoModel->createGroup(nodeList);
}
m_internal->m_geoModel->endUndoBlock(tr("group", TR_UNDO_TOKEN));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
onClearSelection();
setSelected(nodeToSelect, true, true, true);
}
void PlanEditor::getChildNodes(const SituationMap::GeometryModel::Node &node, SituationMap::GeometryModel::NodeList &childNodes)
{
const auto nodeList = m_internal->m_geoModel->getGroupPrimitives(node);
for (const auto &subNode : nodeList)
{
if (SituationMap::GeometryModel::PrimitiveType::Node != m_internal->m_geoModel->getType(subNode))
childNodes << subNode;
else getChildNodes(subNode, childNodes);
}
}
void PlanEditor::onUngroup()
{
abortCurrentBboxRubberband();
SituationMap::GeometryModel::NodeList nodeList;
SituationMap::GeometryModel::NodeList selectedNodes;
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : std::as_const(m_internal->m_selectionList))
{
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
for (;;)
{
const SituationMap::GeometryModel::Node &group = m_internal->m_geoModel->isInGroup(node);
if (!group.isValid()) break;
node = group;
}
if (!nodeList.contains(node)) nodeList += node;
}
for (const auto &node : std::as_const(nodeList))
{
getChildNodes(node, selectedNodes);
m_internal->m_geoModel->releaseGroup(node);
}
}
m_internal->m_geoModel->endUndoBlock(tr("ungroup", TR_UNDO_TOKEN));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
onUpdateView();
onClearSelection();
for (const auto &node : std::as_const(selectedNodes))
setSelected(node, true);
}
void PlanEditor::onRedo()
{
abortCurrentBboxRubberband();
if (m_internal->m_textBoxTextEdit)
delete m_internal->m_textEditorDialog;
m_internal->m_geoModel->redo();
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
}
void PlanEditor::onUndo()
{
abortCurrentBboxRubberband();
if (m_internal->m_textBoxTextEdit)
delete m_internal->m_textEditorDialog;
m_internal->m_geoModel->undo();
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
}
void PlanEditor::onUndoHistory()
{
abortCurrentBboxRubberband();
showHistory(m_internal -> m_dlgUndoHistory
, m_internal -> m_lwUndoHistory
, tr("Undo History")
, m_internal->m_geoModel->undoHistory());
if (m_internal -> m_lwUndoHistory)
{
m_internal -> m_lwUndoHistory -> headerItem() ->setText(0, tr("Undo Step"));
connect(m_internal -> m_lwUndoHistory, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem * undoItem)
{
if (undoItem)
{
bool ok = false;
unsigned int undoCount = undoItem->data(0, Qt::UserRole).toUInt(&ok);
if ((ok) && (undoCount > 0))
m_internal->m_geoModel->undo(undoCount);
}
m_internal -> m_dlgUndoHistory -> hide();
});
}
else ERROR_LOG(m_internal->m_logger) << "Undefined pointer in Undo History Dialog, can't show dialog.";
}
void PlanEditor::onRedoHistory()
{
abortCurrentBboxRubberband();
showHistory(m_internal -> m_dlgRedoHistory
, m_internal -> m_lwRedoHistory
, tr("Redo History")
, m_internal->m_geoModel->redoHistory());
if (m_internal -> m_lwRedoHistory)
{
m_internal -> m_lwRedoHistory -> headerItem() ->setText(0, tr("Redo Step"));
connect(m_internal -> m_lwRedoHistory, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem * redoItem)
{
if (redoItem)
{
bool ok = false;
unsigned int redoCount = redoItem->data(0, Qt::UserRole).toUInt(&ok);
if ((ok) && (redoCount > 0))
m_internal->m_geoModel->undo(redoCount);
}
m_internal -> m_lwRedoHistory -> hide();
});
}
else ERROR_LOG(m_internal->m_logger) << "Undefined pointer in Redo History Dialog, can't show dialog.";
}
void PlanEditor::showHistory(QPointer<LtsWidgets::LtsFramelessDialog> &dlgHistory
, QTreeWidget *&lwHistory
, const QString &title
, const QStringList &history)
{
if (nullptr == dlgHistory)
{
dlgHistory = new LtsWidgets::LtsFramelessDialog(m_internal -> m_gbPlanEditorMain, LtsWidgets::Behaviour::Popup);
QVBoxLayout *layout = new QVBoxLayout(dlgHistory);
lwHistory = new QTreeWidget(dlgHistory);
lwHistory -> setAlternatingRowColors(true);
lwHistory -> setColumnCount(2);
lwHistory -> headerItem() ->setText(1, QString());
lwHistory -> headerItem() ->setTextAlignment(0, Qt::AlignmentFlag::AlignLeft);
lwHistory -> headerItem() ->setTextAlignment(1, Qt::AlignmentFlag::AlignRight);
layout -> addWidget(new QLabel(title, dlgHistory), 0);
layout -> addWidget(lwHistory, 2);
connect(m_internal -> m_lwUndoHistory, &QObject::destroyed, this, [this](QObject *) { m_internal->m_lwUndoHistory = nullptr; });
}
if (nullptr != lwHistory)
{
lwHistory -> clear();
unsigned int tokenCount = (unsigned int) history.size();
for (const QString &token : history)
{
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << token << QString::number(tokenCount));
item->setData(0, Qt::UserRole, QVariant(tokenCount));
lwHistory -> insertTopLevelItem(0, item);
--tokenCount;
}
lwHistory->resizeColumnToContents(0);
lwHistory->resizeColumnToContents(1);
dlgHistory -> show();
}
}
void PlanEditor::onCopy()
{
abortCurrentBboxRubberband();
m_internal->m_nodeClipboard.clear();
m_internal->m_modelClipboard->clearModel();
QVector<SituationMap::GeometryModel::Node> nodesAddedClipboard;
for (SituationMap::UniqueMapId uid : std::as_const(m_internal->m_selectionList))
{
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
while (!node.parentNode().isRootNode())
{
if (!node.isValid()) break;
node = node.parentNode();
}
if (node.isValid())
{
if (!nodesAddedClipboard.contains(node))
{
nodesAddedClipboard.append(node);
const SituationMap::GeometryModel::Node &copyClipboard = m_internal->m_modelClipboard->copy(node);
m_internal->m_nodeClipboard.append(copyClipboard);
}
}
}
}
void PlanEditor::onCut()
{
abortCurrentBboxRubberband();
onCopy();
onDelete();
}
void PlanEditor::onPaste()
{
abortCurrentBboxRubberband();
m_internal->m_geoModel->startUndoBlock();
{
if (!m_internal->m_nodeClipboard.isEmpty())
{
for (int i = 0; i < m_internal->m_nodeClipboard.size(); ++i)
{
const SituationMap::GeometryModel::Node &clipboardNode = m_internal->m_nodeClipboard.at(i);
const SituationMap::GeometryModel::Node &copyNode = m_internal->m_geoModel->copy(clipboardNode);
double pixelSize = m_internal->m_map->pixelSizeGeographic();
double dx = pixelSize * PasteDistance;
double dy = -dx;
m_internal -> m_geoModel -> translateNode( copyNode , dx, dy );
m_internal -> m_modelClipboard -> translateNode( clipboardNode, dx, dy );
}
}
}
m_internal->m_geoModel->endUndoBlock(tr("paste", TR_UNDO_TOKEN));
ModelTreeWidgetItem::updateTree(m_internal->m_modelTreeWidget, m_internal->m_modelTreeWidget->rootItem(), m_internal->m_map.data(), *(m_internal->m_geoModel));
}
void PlanEditor::onSymbolModified( AdvancedSymbology::SymbologyType symbologyType
, const QString &sidcPattern
, const QString &symbolAttributes
, const SituationMap::SimpleValue<AdvancedSymbology::Injury> &participantState
, const SituationMap::SimpleValue<int> &participantPartyId
, const SituationMap::SimpleValue<int> &participantDamageId
, const QMap<SituationMap::Participant::TextModifier, SituationMap::SimpleValue<QString>> &participantTextModifier)
{
abortCurrentBboxRubberband();
m_internal->m_geoModel->startUndoBlock();
{
for (SituationMap::UniqueMapId uid : std::as_const(m_internal->m_selectionList))
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
if (modelPrimitive.isValid())
{
QString currentSidc = m_internal->m_geoModel->getAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC).toString();
if (AdvancedSymbology::SidcCodec::decodeSymbologyType(currentSidc) != symbologyType)
{
continue;
}
for (int i = 0; i < sidcPattern.size(); ++i)
{
if (sidcPattern[i] != QChar(uint('*'))) currentSidc[i] = sidcPattern[i];
}
#ifdef LTS_DEBUG
DEBUG_LOG(m_internal->m_logger) << "SidcPattern " << sidcPattern;
DEBUG_LOG(m_internal->m_logger) << "CurrentSidc " << currentSidc;
DEBUG_LOG(m_internal->m_logger) << "NewSidc " << currentSidc;
#endif
if (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == m_internal->m_geoModel->getType(modelPrimitive))
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
}
if (SituationMap::GeometryModel::PrimitiveType::DictionarySymbol == m_internal->m_geoModel->getType(modelPrimitive))
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
}
if (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == m_internal->m_geoModel->getType(modelPrimitive))
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC, currentSidc);
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC_Attributes, symbolAttributes);
if (participantState.changed())
{
m_internal->m_geoModel->setPrimitiveAttribute( modelPrimitive
, SituationMap::GeometryModel::Attribute::Injury
, static_cast<int>(participantState.value()) );
}
if (participantPartyId.changed())
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::ForceId, participantPartyId.value());
}
if (participantDamageId.changed())
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::DamageForceId, participantDamageId.value());
}
for (auto it = participantTextModifier.constBegin(); it != participantTextModifier.constEnd(); ++it)
{
const auto &mod = it.key();
const SituationMap::SimpleValue<QString> &value = it.value();
if (value.changed())
{
SituationMap::GeometryModel::Attribute geoModelAttribute = SituationMap::GeometryModel::Attribute::None;
switch (mod)
{
case SituationMap::Participant::TextModifier::EF_ReinforcedReduced : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_EF; break;
case SituationMap::Participant::TextModifier::G_StaffComments : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_G; break;
case SituationMap::Participant::TextModifier::H_AdditionalInformation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_H; break;
case SituationMap::Participant::TextModifier::JKLNP : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_KLNPJ; break;
case SituationMap::Participant::TextModifier::M_HigherFormation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_M; break;
case SituationMap::Participant::TextModifier::T_UniqueDesignation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_T; break;
case SituationMap::Participant::TextModifier::V_Type : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_V; break;
case SituationMap::Participant::TextModifier::W_DateTimeGroup : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_W; break;
case SituationMap::Participant::TextModifier::XY_AltitudeLocation : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_XY; break;
case SituationMap::Participant::TextModifier::Z_Speed : geoModelAttribute = SituationMap::GeometryModel::Attribute::Text_Z; break;
case SituationMap::Participant::TextModifier::END : Q_ASSERT(false); break;
}
if (SituationMap::GeometryModel::Attribute::None != geoModelAttribute)
{
m_internal->m_geoModel->setPrimitiveAttribute(modelPrimitive, geoModelAttribute, value.value());
}
}
}
}
}
}
}
m_internal->m_geoModel->endUndoBlock(tr("modify symbol sidc", TR_UNDO_TOKEN));
}
void PlanEditor::onSymbolXmlAttrModified(const QString & undoToken, SituationMap::GeometryModel::Attribute attribute, const QVariant &value)
{
m_internal->m_geoModel->startUndoBlock();
{
for (SituationMap::UniqueMapId uid : std::as_const(m_internal->m_selectionList))
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
if (modelPrimitive.isValid())
{
if (SituationMap::GeometryModel::PrimitiveType::Symbol == m_internal->m_geoModel->getType(modelPrimitive))
{
m_internal->m_geoModel->setPrimitiveAttribute( modelPrimitive, attribute, value );
}
}
}
}
m_internal->m_geoModel->endUndoBlock(undoToken);
}
static void importGuezXMLSymbolsFromFile(const AdvancedSymbology::SymbolDictionary &symbolDict)
{
Q_UNUSED(symbolDict);
#ifdef IMPORT_GUEZ_SYMBOLS_FROM_FILE
QMap<int, QString> symbolIdtoPPType;
const QString & dirPath = QStringLiteral("D:/Development/Projekte/SituationMap/Symbole-GUEZ");
QFile symbolDump(dirPath + QStringLiteral("/guez_symbole.unl"));
QFile typeDump(dirPath + QStringLiteral("/guez_typen.unl"));
if (typeDump.exists() && typeDump.open(QIODevice::ReadOnly | QIODevice::Text))
{
while (true)
{
const QByteArray & lineData = typeDump.readLine();
if (lineData.isEmpty()) break;
const QStringList &typeData = QString::fromLatin1(lineData).split(QLatin1Char('|'));
if (typeData.size() > 4)
{
bool valid = false;
int symbolId = typeData[3].toInt(&valid);
if (valid)
{
symbolIdtoPPType[symbolId] = typeData[2];
qCritical() << typeData[2] << " --->> " << symbolId;
}
}
}
typeDump.close();
}
if (symbolDump.exists() && symbolDump.open(QIODevice::ReadOnly|QIODevice::Text) )
{
const QString & guezSymbolDirName = QStringLiteral("GuezSymbols");
QDir guezSymbolRoot(dirPath);
QDir guezSymbolDir(dirPath + QStringLiteral("/") + guezSymbolDirName);
guezSymbolDir.removeRecursively();
guezSymbolRoot.mkdir(guezSymbolDirName);
QString xmlContent = QString::fromLatin1(symbolDump.readAll());
QString blockBegin = QStringLiteral("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
QString blockEnd = QStringLiteral("</symbol>");
const QList<QString> & xmlSymbolVector = xmlContent.split(blockEnd,Qt::SkipEmptyParts);
for (auto xmlSymbolRef : std::as_const(xmlSymbolVector))
{
int xmlBegin = xmlSymbolRef.indexOf(blockBegin);
QString xmlSymbol = xmlSymbolRef.mid(xmlBegin).toString() + blockEnd + QStringLiteral("\n");
xmlSymbol.replace( QStringLiteral(" =") , QStringLiteral("=") );
xmlSymbol.replace( QStringLiteral("= ") , QStringLiteral("=") );
xmlSymbol.replace( QStringLiteral("/ >") , QStringLiteral("/>") );
xmlSymbol.replace( QStringLiteral("\\n") , QStringLiteral("\n") );
xmlSymbol.replace( QStringLiteral("\\") , QStringLiteral("") );
int xmlEmptyCounter = xmlSymbol.indexOf(QStringLiteral("</graphic")) - xmlSymbol.indexOf(QStringLiteral("<graphic")) - 30;
if (xmlEmptyCounter < 0) continue;
AdvancedSymbology::SymbolProperties proper;
if (!symbolDict.setXmlSymbol(xmlSymbol,&proper))
{
if (xmlSymbolRef.mid(xmlBegin-2, 2) == QStringLiteral("||")) continue;
qCritical() << "Insert XML symbol into symbology dictionary failed:";
qCritical() << ((xmlBegin < 0) ? xmlSymbolRef.toString() : xmlSymbol);
qCritical() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
continue;
}
if (symbolIdtoPPType.contains(proper.key().toInt()))
{
QFile guezSymbolXML(guezSymbolDir.absoluteFilePath(QStringLiteral("guez_symbol_%1.xml").arg(proper.key())));
if (guezSymbolXML.exists())
{
qCritical() << xmlSymbolRef.toString();
qCritical() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
qCritical() << "File \"" << guezSymbolXML.fileName() << "\"already exists!!!!!";
continue;
}
if (guezSymbolXML.open(QIODevice::OpenModeFlag::ReadWrite | QIODevice::OpenModeFlag::Text))
{
guezSymbolXML.write(xmlSymbol.toUtf8());
guezSymbolXML.close();
}
}
else
{
symbolDict.removeXmlSymbol(proper.sidc());
}
}
symbolDump.close();
}
#endif
}
}