Files
qt5-legatus-legacy/Lts/Plugins/PlanEditor/plan_editor.cpp
T
2026-08-13 18:33:10 +02:00

5031 lines
195 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
**
** @RDE_HEADER@
** plan_editor.cpp
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.9, ArcGIS 100.2.1
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 09.12.2015, JT : First edition for use with Qt5
**
** ------------------------------------------------------------------------------------------------
*/
const char* const REVISION = "$Revision$";
#include "dialog.h"
#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> // just for testing sight fan
#include <MapObjects/polyline.h> // just for testing parallel translation
#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 <QtCore/QStringRef>
#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 <QtWidgets/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 <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> // just for testing
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;
}
// standard event processing
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::onGeoModelModified(unsigned int modifyCount)
void PlanEditor::onNoticeGeoModelTypeError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model type error: " << errorMsg;
} // PlanEditor::onNoticeGeoModelTypeError( const QString & )
void PlanEditor::onNoticeGeoModelAttributeError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model attribute error: " << errorMsg;
} // PlanEditor::onNoticeGeoModelAttributeError( const QString & )
void PlanEditor::onNoticeGeoModelModelError(const QString &errorMsg)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " Geometry Model error: " << errorMsg;
} // PlanEditor::onNoticeGeoModelModelError( const QString & )
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);
} // PlanEditor::onNoticeGeoModelError( const QString & )
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;
}
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
// update TextBoxes (transfer data from model to TextBoxes)
if ((att == SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes) ||
(att == SituationMap::GeometryModel::Attribute::MaxAttributes) )
{
// // initializePlanTextBoxPixel(); // does not really work, to rough
// Assumption:
// - we create one PixelBasedTextBox (implicit an EditorDialog is opened)
// - enter some characters (PixelBasedTextBox is updated)
// - we press apply
// within LtsTextEditDialog::apply() there will be two signals emitted
// - first 'signalTextApplied'
// this will update the geometryModel and via changed and onNoticeGeoModelUpdate
// the LtsTextEditDialog will be deleted
// - second 'signalTextAppliedWithBackGroundColor'
// will crash since object does not exist anymore....
// Note: most of the times, ptbdCont.size() == pbtbIdVec.size() are equal...
// Model
const QString &strRef =
m_internal->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
// displayed TextBoxes
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())
{
// this case is typically entered by pressing: undo, redo, LtsTextEditDialog::apply()
QVectorIterator<SituationMap::PBTB_ID> pbtbIdVecIt(pbtbIdVec);
for (const SituationMap::PixelTextBoxData &ptbd : qAsConst(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 {
// this case is typically entered by pressing undo, redo; but no by LtsTextEditDialog::apply()
initializePlanTextBoxPixel();
} // if (ptbdCont.size() == pbtbIdVec.size())
}
// NLDEVCTRL-807:
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));
} // PlanEditor::onNoticeGeoModelUpdate( const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::Attribute att, bool coordsChanged );
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));
// m_internal->m_map->getQGraphicsView() seems to be nullptr , mostly during slotReplaySessionForPlanEditorStarted
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) );
} // PlanEditor::onUpdateView()
QString PlanEditor::planDefaultDirectory() const
{
return m_internal->m_defaultPlanDirectory;
} // PlanEditor::planDefaultDirectory() const
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.";
} // PlanEditor::setPlanDefaultDirectory( const QString & dir )
QWidget *PlanEditor::topLevelWidget() const { return m_internal->m_session.topLevelWidget(); }
void PlanEditor::setParticipantsSidcsInUse(const QSet<QString> &sidcs)
{
// DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " sidcs: " << sidcs.values().join(QLatin1String(";"));
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_internal(new PlanEditor::InternalData(map, PlanEditorSession(ltsSession, this), this))
{
init();
}
PlanEditor::PlanEditor(SituationMap::Map *map, LtsWidgets::LtsBaseLayoutWidget *ltsbaseWidget)
: QObject()
, 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;
}
// Qt-doc: event filters are automatically removed when destroyed
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(); // make symbol dictionary if doesn't exist
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()) // ToDo: check if partitionType is sufficiant
{
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"));
// ToDo: removeOperationalLayer
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); // siehe auch sit_map.cpp Zeile 421 ff
});
}
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();
// look for autosaved files
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); // 5 mins = 300000
} // void PlanEditor::init( SituationMap::Map * map )
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 : qAsConst(m_internal->m_symbolWidgets))
w->setEnabled(true);
} // PlanEditor::onEnableSymbolWidgets
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::onEnablePlanEditor()
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);
}
} // void PlanEditor::onDisablePlanEditor()
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();
} // PlanEditor::~PlanEditor()
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);
} // bool PlanEditor::event(QEvent *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));
}
/*
Dialog * dialog = new LtsWidgets::LtsDialog( parent );
QHBoxLayout * layout = new QHBoxLayout( dialog );
QToolButton * tb = nullptr;
dialog->setTitle("Picking Mode");
tb = new QToolButton(dialog);
{
tb->setText( tr("Picking") );
tb->setIcon( Utils::getIcon(QLatin1String(SELECT_PICK_ICON_NAME)) );
tb->setToolTip( tr("Selection with single mouse clicks") );
connect( tb, &QToolButton::clicked, this, &PlanEditor::onSelectionActivatePicking );
}
layout->addWidget( tb, 0 );
tb = new QToolButton(dialog);
{
tb->setText( tr("Line Select") );
tb->setIcon( Utils::getIcon(QLatin1String(SELECT_LINE_ICON_NAME)) );
tb->setToolTip( tr("Selection with intersection line") );
connect( tb, &QToolButton::clicked, this, &PlanEditor::onSelectionActivatePicking );
}
layout->addWidget( tb, 0 );
layout->addStretch(3);
return dialog;
*/
} // PlanEditor::buildSelectionModeBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
void PlanEditor::buildFileBox(const PlanEditorSession &session, bool retranslate)
{
if (m_internal->m_session.isLtsSession())
{
return; // skip if running as plugin
}
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
//#define TEST_AGGREGATION 1
#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
// #define TEST_SIGHT_FAN 1
#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;
}; // std::function<bool(SituationMap::RB::RubberbandBase*)>
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
//#define TEST_SIGHT_FAN_DIALOG 1
#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
//#define TEST_PARTICIPANT_LIST
#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
//#define TEST_PARALLEL_TRANSLATION
#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;
}
}
// and now back again
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
} // PlanEditor::buildFileBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
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::buildEditBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
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; // set button to symbolWidgets list to enable the button if dictionary is loaded
}
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; // set button to symbolWidgets list to enable the button if dictionary is loaded
}
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::buildCreateBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
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);
}
//#define TestSymbolDialog
#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
} // void PlanEditor::buildHelpBox( LtsWidgets::LtsBaseLayoutWidget * ltsbaseWidget )
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;
} // PlanEditor::buildDebugBox( QWidget * parent )
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);
} // bool PlanEditor::eventFilter( QObject * obj, QEvent * event )
void PlanEditor::onRubberbandAction()
{
if (nullptr == m_internal) return; // PlanEditor is expiring
const QList<SituationMap::RB::RubberbandBase *> &activeRbndList = SituationMap::RB::Rubberband::activeRubberbands(m_internal->m_map.data());
(activeRbndList.isEmpty()) ? onEnablePlanEditor() : onDisablePlanEditor();
} // void PlanEditor::onRubberbandAction()
void PlanEditor::onHideDialogTab()
{
m_internal->m_lookupSymbolManager -> onCloseDialog();
m_internal->m_attributeDialogManager -> onCloseDialog();
} // void PlanEditor::onHideDialogTab
void PlanEditor::onShowDialogTab(const SituationMap::GeometryModel::Node &node)
{
onEnablePlanEditor();
m_internal->m_attributeDialogManager->onOpenDialog(node);
// 28.10.2019, Norbert Thoden
// RP 553 Schnappschuss: in einem bereits angelegtem Textfeld können keine Änderungen vorgenommen werden..
// getStyleAttributes wird fuer alle PrimitiveTypen aufgerufen:
m_internal->m_attributeDialogManager->getStyleAttributes(node);
} // PlanEditor::onShowDialogTab
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.";
}
} // PlanEditor::saveToFile( const QString & filePath )
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();
// m_internal->m_map->getQGraphicsView() seems to be nullptr , mostly during slotReplaySessionForPlanEditorStarted
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::initializePlan()
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 : qAsConst(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;
// add to mgnt:
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
m_internal->m_ourTextBoxIds.append(pbtbId);
}
} // for
// add connect to open TextEditDialog:
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
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* REGG-4219:
* On Linux systemes some times a new LtsMessageDialog will appear behind an already existing other modal dialog. As
* result the user can't confirm with "Ok" and the progarm seems to hang up
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
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::checkFromEmptyPlan()
void PlanEditor::setNameOfPlan(const QString & planName)
{
m_internal->m_modelTreeWidget->setNameOfPlan(planName);
} // void PlanEditor::setNameOfPlan(const QString & 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();
// not here, we are inside a Request
// checkFromEmptyPlan();
return true;
} // void PlanEditor::setPlan( const QByteArray & xmlContent )
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;
} // bool PlanEditor::importPlan(const QByteArray &xmlContent)
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.";
}
} // PlanEditor::loadFromFile( const QString & filePath )
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);
// ToDo
// 1. make copy from m_internal->m_geoModel
// 2. remove all node which are not selected
// 3. call cleanModel()
// 4. write to file
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)
{
} // MapObjectsVisitor( SituationMap::GeometryModel & geoModel, const QList<SituationMap::UniqueMapId> & 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;
} // bool apply( SituationMap::GeometryModel*, const SituationMap::GeometryModel::Node &, SituationMap::GeometryModel::PrimitiveType
void cleanup()
{
for (const auto &node : qAsConst(m_removeNodeList))
m_geometryModel->removePrimitive(node);
for (const auto &group : qAsConst(m_removeGroupList))
m_geometryModel->deleteGroup(group);
} // void cleanup()
}; // MapObjectsVisitor
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.";
} // PlanEditor::saveSelectedToFile( const QString & filePath )
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.";
}
} // PlanEditor::importFromFile( const QString & filePath )
bool PlanEditor::isSymbolModelValid() const
{
// if (m_internal->m_lookupSymbolManager->getBaseSymbolModelEsri())
// return (!m_internal->m_lookupSymbolManager->getBaseSymbolModelEsri()->isEmpty());
// return false;
return true;
}
void PlanEditor::setAllSymbolFavourites(const QString &xmlContent)
{
m_internal->m_favouritesActionManager->symbolFavourites()->contentFromString(xmlContent);
} // void PlanEditor::setAllSymbolFavourites( const QString & xmlContent )
QString PlanEditor::allSymbolFavouritesToString() const
{
return m_internal->m_favouritesActionManager->symbolFavourites()->toString();
} // QString PlanEditor::allSymbolFavouritesToString() const
SituationMap::UniqueMapId PlanEditor::getIdFromNode(const SituationMap::GeometryModel::Node &p) const
{
return m_internal->m_geoModelRenderer->getIdFromNode(p);
} // SituationMap::UniqueMapId PlanEditor::getIdFromNode(const SituationMap::GeometryModel::Node & p) const
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)
{
// Can this even happen?
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);
} // PlanEditor::setSelected(SituationMap::UniqueMapId, bool 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);
}
} // PlanEditor::setSelected(const SituationMap::GeometryModel::Node & node)
bool PlanEditor::isSelected(SituationMap::UniqueMapId uid)
{
return m_internal->m_selectionList.contains(uid);
} // bool PlanEditor::isSelected( SituationMap::UniqueMapId )
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;
} // bool PlanEditor::isSelected( const SituationMap::GeometryModel::Node & node )
void PlanEditor::addStyleAttributes(const SituationMap::GeometryModel::Node &node, bool prepareUndo, bool changedAttrOnly)
{
m_internal->m_attributeDialogManager->addStyleAttributes(node, prepareUndo, changedAttrOnly);
} // PlanEditor::addStyleAttributes( const SituationMap::GeometryModel::Node & node, bool prepareUndo )
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();
// ToDo : Attribute Fenster aktualisieren
} break;
default : break;
}
}
} // PlanEditor::getSymbolAttributes( const SituationMap::GeometryModel::Node & node )
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;
} // SituationMap::GeometryModel::Node PlanEditor::addGeoModelPrimitive(...)
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);
} // PlanEditor::removeFeature( SituationMap::UniqueMapId id, bool prepareUndo )
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 : qAsConst(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);
} // PlanEditor::updateSelectedFeature( const QString & undoToken )
void PlanEditor::abortCurrentBboxRubberband()
{
if (m_internal->m_currentBboxRubberband)
{
m_internal->m_currentBboxRubberband->deleteMySelf();
m_internal->m_currentBboxRubberband = nullptr;
}
} // void PlanEditor::abortCurrentBboxRubberband()
template<class RubberbandTransformClass> void PlanEditor::createTransformRubberband()
{
// start translate rubberband for move, scale and rotate if possible
// but first check the bounding box of selection
SituationMap::RB::RubberbandTransform *geoPlacerRB = GeometryPlacer<RubberbandTransformClass>::create(this, m_internal->m_map.data(), m_internal->m_geoModel, m_internal->m_selectionList, this);
if (geoPlacerRB)
{
// Ok, bounding box has a valid size and GeometryPlacer is valid and has a rubberband
onHideDialogTab(); // get more size on map widget for the map
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);
}
// 17.09.19, N. Thoden, (Qt 5.12.3)
// Maybe calling setFocus here is to early.
// Race condition between dialog/widget created by former onEditAttributes()
// and this setFocus():
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();
});
}
} // template<class RubberbandTransformClass> void PlanEditor::createTransformRubberband()
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;
// reuse or create EditDialog
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:
// do not continue
return;
case LtsWidgets::Button::Discard:
if (m_internal->m_textBoxTextEdit)
m_internal->m_textBoxTextEdit->setHtml(m_internal->m_htmlTextForCancelation);
break;
default:
break;
} // switch
} // if
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"), // this->title()???
QStringLiteral("PixelBasedTextBoxAttributes"),
LtsWidgets::LayoutArea::eDialogTab,
true); //setClosable
}
m_internal->m_session.focusTab(m_internal->m_textEditorDialog,
LtsWidgets::LayoutArea::eDialogTab,
QStringLiteral("PlanEditor"),
QStringLiteral("PixelBasedTextBoxAttributes"));
SituationMap::PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = m_internal->m_map->pixelBasedTextBoxHandler();
//
// NOW store WHICH pbtbId and textEdit is linked to LtsTextEditDialog:
//
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 ";
// transfer current htmlText to EditDialog:
// m_internal->m_textBoxTextEdit may be null, use pixelBasedTextBoxHandler:
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
if (!data.isEmpty())
{
const QString &currentText = data.m_htmlText; // m_htmlText ist updated during getPixelTextBoxData()
m_internal->m_textEditorDialog->setHtml(currentText);
m_internal->m_textEditorDialog->setInitialBackgroundColor(data.m_backgroundColor);
m_internal->m_textEditorDialog->__unchange__();
m_internal->m_htmlTextForCancelation = currentText;
}
// connections:
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);
// we use the QTextEdit::destroyed signal as signal when the pixelbased textbox is closed
connect(currentTe, &QTextEdit::destroyed,
this, [this /*, pbtbId*/] (QObject *)
{
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
delete m_internal->m_textEditorDialog;
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
// if (!m_internal->m_textEditorDialog.isNull())
// {
// if (pbtbId == m_internal->m_textBoxIdInEditing) // if it is the focused textbox we close the text editor
// {
// m_internal->m_textEditorDialog->__unchange__(); // unchange, so we close it, even if there are unsaved changes
// m_internal->m_textEditorDialog->closeRequest();
// }
// }
});
}
void PlanEditor::onTextEditGeometryChanged(const SituationMap::PBTB_ID &pbtbId)
{
// will be called by events: a) geometryChanged or b) positionChanged
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;
// to ensure, that button save", save as" will save the correct data:
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::onMapObjectClicked( const SituationMap::Map::RefPointerMapObjectList & mapObjList, const QPoint & )
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();
// Szenario:
// click an Ets symbol on the map: PlanEditor::doPicking open an EditDialog (occurance#1),
// PlanEditor::setSelected renews the same dialog (occurance#2), finally createTransformRubberband destroys the occurance#2
// Rbd::finished opens the same dialog (occurance#3), setSidc recognize an Ets symbol -> dialog will be closed....
// Reduce the construction/destruction to rblock seduce flickering, by adding bool enableShowDialogTab to setSelected.
// N. Thoden, 08/2019:
bool bAddSelection = (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier) || QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier));
// do we have to createTransformRubberband?
bool bCreateTransformRubberband =
!bAddSelection &&
(m_internal->m_selectionMode != SelectionMode::PickingAndEdit)
&& mapObjList.size() >= 1;
// Maybe:
// Do the *de*selection first:
// If we change on item to be selected now, a some kind of edit dialog will be opened.
// Unfortunately they emit a huge number of signals (e.g. SymbolModificationWidget::changed)
// If there ist still an item in the m_internal->m_selectionList, this will be infected by mistake)
// But: The selectionChanged of the ModelTreeWidgetItem is ordered be the model
// So if the selection (by clicking the ModelView) changes from a 3rd obj to the 1st,
// the selection=true will be set to the 1st AND THEN the selection=false will be set to the 3rd.
// N. Thoden, 08/2019:
for (auto mapObjPtr : mapObjList)
{
// NOTICE_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX mapObjPtr->debugInfo()... " << mapObjPtr->debugInfo() << " m_internal->m_selectionList.isEmpty() = " << m_internal->m_selectionList.isEmpty();
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModelRenderer->getAssociatedNode(mapObjPtr.get());
if (modelPrimitive.isValid())
{
// if (m_internal->m_selectionList.isEmpty())
// {
// NOTICE_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX onShowDialogTab..";
// onShowDialogTab(modelPrimitive);
// }
setSelected(modelPrimitive, true, !bCreateTransformRubberband); // enableShowDialogTab = !bCreateTransformRubberband;
}
}
DEBUG_LOG(m_internal->m_logger) << LOGFUNCTION << " XXXX bCreateTransformRubberband= " << bCreateTransformRubberband;
if (bCreateTransformRubberband)
createTransformRubberband<SituationMap::RB::RubberbandTransform>();
} // void PlanEditor::doPicking( const SituationMap::Map::RefPointerMapObjectList & mapObjList )
void PlanEditor::onContextMenuRequested( const SituationMap::Map::RefPointerMapObjectList&, const QPointF &viewportPosition)
{
if (m_internal->m_session.isLtsSession()) return; // context is handled by SituationMapGuiPlugin
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::onContextMenuRequested( const SituationMap::Map::RefPointerMapObjectList &mapObjList, const QPointF &viewportPosition)
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);
// ToDo: Implement me
} // PlanEditor::onViewAbout()
void PlanEditor::onViewHelp()
{
abortCurrentBboxRubberband();
if (nullptr == m_internal->m_viewHelp) return;
m_internal->m_viewHelp->show();
} // PlanEditor::onViewHelp()
void PlanEditor::onShowHelp()
{
if (m_internal->m_session.ltsSession())
{
m_internal->m_session.ltsSession()->slotShowOnlineHelp(QStringLiteral("Plan_Editor-Application"));
}
} // PlanEditor::onShowHelp()
void PlanEditor::installSaveFunction(const std::function<void()> &saveFunction)
{
m_internal->m_saveFunction = saveFunction;
} // void PlanEditor::installSaveFunction(std::function<void()> * saveFunction)
void PlanEditor::onQuit()
{
onAskSaveChanges();
emit quitPlanEditor();
} // PlanEditor::onQuit
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();
} // PlanEditor::onAskSaveChanges
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)
{
// discard:
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())
{
// PlanEditorData is stored in OPERATIONAL_Layer, but SnapshotData is stored in OVERLAY_Layer
// see PlanEditor::init().
// Avoid, that the GraphicsLayer are destroyed via MapImpl::fini() _before_ the AbstractGraphicalObjects are destroyed.
// That would lead to segFault....
// cleanModel and destroy the coresponding MapObjects/GraphicalObjects:
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::onMetaData()
void PlanEditor::onPlanPrint()
{
abortCurrentBboxRubberband();
QSharedPointer<QPrinter> printer(new QPrinter(QPrinter::PrinterMode::HighResolution));
QPrintDialog printDialog(printer.data(), topLevelWidget()); // choose a printer
printer->setOrientation(QPrinter::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)
{
// now we have a nice image of our plan, next use use Qt Printer Support to send it to a printer
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")); // current date and time
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().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; // use a QTextDocument to add some text and place the map image
QPainter painter(printer.data()); // init painter to the choosen printer
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);
// finally:
document.drawContents(&painter);
// #define DEBUG_MSGBOX
#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();
}); // lambda [this,&printer,&eventLoop,&slotMetaObj]( const QString & pdfFilePath )
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(); // wait for finish printing
disconnect(slotMetaObj);
}
} // PlanEditor::onPlanPrint
void PlanEditor::onPlanReset()
{
qDebug() << LOGFUNCTION << " START";
if (m_internal->m_geoModel == nullptr)
return;
m_internal->m_geoModel->clearModel();
setNameOfPlan(QString());
initializePlan();
} // PlanEditor::onPlanReset()
void PlanEditor::onPlanCreate()
{
abortCurrentBboxRubberband();
onAskSaveChanges();
onPlanReset();
onMetaData();
} // PlanEditor::onPlanCreate
static QString addPlanFileSuffix(const QString &filePath, const QString &selectedNameFilter)
{
QString defaultSuffix(QStringLiteral(".plan"));
// qCritical() << selectedNameFilter;
QStringRef suffix;
int suffixDefStart = selectedNameFilter.lastIndexOf(QLatin1Char('(')) + 1;
int suffixDefEnd = selectedNameFilter.lastIndexOf(QLatin1Char(')')) - 1;
if (suffixDefStart < suffixDefEnd)
{
const QStringRef &suffixFilter = selectedNameFilter.midRef(suffixDefStart, suffixDefEnd - suffixDefStart + 1);
const QVector<QStringRef> &suffixVector = suffixFilter.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (!suffixVector.isEmpty())
{
const QStringRef &filter = suffixVector.first();
int indexOfDot = filter.lastIndexOf(QLatin1Char('.'));
if (indexOfDot >= 0)
suffix = filter.right(filter.length() - indexOfDot);
}
}
// qCritical() << suffix;
if (suffix.isEmpty()) suffix = QStringRef(&defaultSuffix);
if ((suffix == QStringLiteral(".*")) || (filePath.endsWith(suffix))) return filePath;
return filePath + suffix;
} // static QString addPlanFileSuffix( const QString & filePath, const QString & selectedNameFilter )
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());
}
}
} // PlanEditor::onPlanLoad
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();
} // PlanEditor::onPlanSave
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();
}
}
} // PlanEditor::onPlanSaveAs
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);
}
}
} // PlanEditor::onPlanSaveSelected
void PlanEditor::onPlanAutoSave()
{
if (m_internal->m_geoModel == nullptr) return;
if (m_internal->m_geoModel->modificationCounter() < 1) return; // no modifications since last save
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());
} // PlanEditor::onPlanAutoSave
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);
}
}
} // PlanEditor::onPlanImport
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 : qAsConst(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;
}
} // for
if (viewAreaMinX < std::numeric_limits<qreal>::max())
{
// ViewAreaMin and viewAreaMax are defined, we can setup the view now
// add 10 % extra space
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;
// setup values
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);
}
} // PlanEditor::onCenterViewSelected()
void PlanEditor::onClearSelection()
{
abortCurrentBboxRubberband();
const auto selList = m_internal->m_selectionList; // setSelected modifes m_selectionList
for (SituationMap::UniqueMapId uid : selList)
setSelected(uid, false);
m_internal->m_selectionList.clear();
ModelTreeWidgetItem::clearSelection(m_internal->m_modelTreeWidget->rootItem());
onHideDialogTab();
} // PlanEditor::onClearSelection()
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();
// ToDo: Status-Zeile
} // PlanEditor::onRubberbandAbort(SituationMap::RB::RubberbandBase * rubberband)
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))
{
// It is a point feature to start a rubberband makes no sense here because the coordinate is already
// known. We can use the coordinate of drop event to place the symbol.
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(); // bye bye rubberband
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;
}
}
} // doDrop(int x, int y, const QMimeData * mimeData)
}; // DropCreateSymbol
qulonglong PlanEditor::createSymbolDropEvent(const QString &sidc)
{
bool createParticipant = false;
if (m_internal->m_lookupSymbolManager)
{
// createParticipant = m_internal->m_lookupSymbolManager->getBaseSymbolModel()->isParticipant(sidc);
createParticipant = m_internal->m_lookupSymbolManager->isParticipantDialog();
}
return m_internal->m_dropEventManager->add(new DropCreateSymbol(this, m_internal.get(), sidc, createParticipant));
} // int PlanEditor::createSymbolDropEvent(const QString & sidc)
SituationMap::RB::Rubberband *PlanEditor::onSymbolCreateRubberband(const QString &currentSidc, bool createParticipant )
{
// AdvancedSymbology::Gui::BaseSymbolModel *symbolModel = m_internal->m_lookupSymbolManager->getBaseSymbolModel();
// bool bCreateParticipant = createParticipant && (m_internal->m_lookupSymbolManager) && (m_internal->m_lookupSymbolManager->isParticipant(currentSidc));
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;
} // PlanEditor::onSymbolCreateRubberband()
void PlanEditor::onChooseSymbol()
{
onClearSelection();
if (m_internal->m_symbolDictLoaded) m_internal->m_lookupSymbolManager->onOpenSymbolDialog();
}; // PlanEditor::onChooseSymbol()
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())
{
// restore last coordinate before rubberband was running
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();
} // PlanEditor::onSymbolCreate( SituationMap::RB::RubberbandBase * rubberband )
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;
} // PlanEditor::onLineCreateRubberband()
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.";
}
} // DropCreateLine::doDrop( int x, int y ) const
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); // addStyleAttributes will be done in addGeoModelPrimitives
}
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));
}
}
} // PlanEditor::onLineCreate( SituationMap::RB::RubberbandBase * rubberband )
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;
} // PlanEditor::onPolylineCreateRubberband()
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.";
}
} // DropCreatePolyLine::doDrop( int x, int y ) const
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); // addStyleAttributes will be done in addGeoModelPrimitives
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));
}
}
} // PlanEditor::onPolylineCreate( SituationMap::RB::RubberbandBase * rubberband )
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;
} // PlanEditor::onSmoothLineCreateRubberband()
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;
} // PlanEditor::onPolygonCreateRubberband()
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.";
}
} // DropCreatePolygon::doDrop( int x, int y ) const
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));
// ToDo: fill attributes
if (!node.isValid())
{
m_internal->m_geoModel->startUndoBlock();
{
if (smoothLine) node = addGeoModelPrimitive(SituationMap::GeometryModel::PrimitiveType::Spline, points, attributes); // addStyleAttributes will be done in addGeoModelPrimitives
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));
}
}
} // PlanEditor::onPolygonCreate( SituationMap::RB::RubberbandBase * rubberband )
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;
} // PlanEditor::onRectangleCreateRubberband()
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.";
}
} // DropCreateRectangle::doDrop( int x, int y ) const
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);
}; // getAngle
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); // addStyleAttributes will be done in addGeoModelPrimitives
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 : qAsConst(attributes))
m_internal->m_geoModel->setPrimitiveAttribute(node, attrPair.first, attrPair.second);
addStyleAttributes(node, false);
}
m_internal->m_geoModel->endUndoBlock(tr(undoToken, TR_UNDO_TOKEN));
}
}
} // PlanEditor::onRectangleCreate( SituationMap::RB::RubberbandBase * rubberband )
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;
} // PlanEditor::onEllipseCreateRubberband()
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;
} // PlanEditor::buildTextNode( const QPointF & loc )
void PlanEditor::buildTextBoxPixelNode(const QPointF &locPixel)
{
// // m_internal->m_geoModel->startUndoBlock();
// // cleanup 'current'...
// m_internal->resetCurrentTextBox();
//
// get in touch with TextBox at QGraphicsScene:
//
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);
//
// !! pbtbId maybe updated by createUpdateTextBox !!
//
INFO_LOG(m_internal->m_logger) << " new TextBox created: newTextEdit = " << newTextEdit
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
// add to mgnt:
if (!m_internal->m_ourTextBoxIds.contains(pbtbId))
m_internal->m_ourTextBoxIds.append(pbtbId);
// connect slot to open TextEditDialog:
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);
//
// reuse or create EditDialog
//
onTextEditDialogRequested(pbtbId);
// // m_internal->m_geoModel->endUndoBlock(tr("create textBoxPixel", TR_UNDO_TOKEN));
}
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());
// Read text, bgColor, pos, size from SitMap (pixelBasedTextBoxHandler):
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 : qAsConst(pbtbIdVec))
{
const SituationMap::PixelTextBoxData &data = pixelBasedTextBoxHandler.getPixelTextBoxData(pbtbId);
if (data.isEmpty())
continue;
ptbdVec.append(data);
} // for
// convert to Json (Container):
const QString &str = SituationMap::PixelTextBoxData::pixelTextBoxContainerToJsonStr(ptbdVec, QJsonDocument::JsonFormat::Compact);
// to model
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);
} // DropCreateTextLine::doDrop(int x, int y, const QMimeData*) const
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
{
// restore last coordinate before rubberband was running
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();
// create TextEdit and it´s dialog:
buildTextBoxPixelNode(locPixel);
}
void PlanEditor::onTextBoxPixelTextChanged(const QString &htmlText)
{
TRACE_LOG(m_internal->m_logger) << LOGFUNCTION << " START";
if (!m_internal->m_map)
return;
// slight change -> no UndoBlock
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;
}
// Update gui:
m_internal->m_textBoxTextEdit->setHtml(htmlText);
// to ensure, that button "save" and "save as" will save the correct data:
// [GUEZE-2947] Undo,Redo fuer PixelBasedTextBoxen
// on apply: // writeTextBoxDataToModel();
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;
}
// Update gui:
data.m_backgroundColor = backgroundColor;
pixelBasedTextBoxHandler.updateTextBox(currentPbtbId, data);
// to ensure, that button save", save as" will save the correct 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_geoModel->startUndoBlock();
m_internal->m_htmlTextForCancelation = htmlText; // update
writeTextBoxDataToModel();
// // m_internal->m_geoModel->endUndoBlock(tr("update textBoxes", TR_UNDO_TOKEN));
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;
}
// restore saved text:
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());
// Nothing to do here because all work has been done in preview
rMove->setUserData(nullptr);
delete featureToTransform;
m_internal->m_geoModel->endUndoBlock(tr("move feature(s)", TR_UNDO_TOKEN));
} // PlanEditor::onTransformMove( SituationMap::RB::RubberbandBase * rubberband )
void PlanEditor::onTransformRotate(SituationMap::RB::RubberbandBase *rubberband)
{
SituationMap::RB::RubberbandTransformRotate *rRotate = dynamic_cast<SituationMap::RB::RubberbandTransformRotate *>(rubberband);
if (rRotate == nullptr) return;
// const QPointF & rCenter = rRotate -> centerPoint();
// qreal deltaAngle = rRotate -> getRelativeRotation();
for (auto uid : qAsConst(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);
}
}
} // PlanEditor::onTransformRotate( SituationMap::RB::RubberbandBase * rubberband )
void PlanEditor::onTransformScale(SituationMap::RB::RubberbandBase * /*rubberband*/)
{
} // PlanEditor::onTransformScale( SituationMap::RB::RubberbandBase * rubberband )
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());
} // PlanEditor::onEditAttributes()
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);
/* --------------------------------------------------------------------------------------------------------------------------------------------------------
* Now coordinates are always in geographic coordinate system and not longer in map coordinate system. The geometry model stores now the 4 verticies of
* the rectangle, which are used now directly in rubberband. Keep in mind that the map coordinate sytem has to be the same as for the first input.
* --------------------------------------------------------------------------------------------------------------------------------------------------------
if (rRectRubber != nullptr)
{
QPointF rectCenter = coordinateList.first();
qreal rectWidth2 = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Width ).toDouble() * 0.5;
qreal rectHeight2 = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Height).toDouble() * 0.5;
qreal rectPhi = m_internal->m_geoModel->getAttribute(node, SituationMap::GeometryModel::Attribute::Rotate).toDouble() * MathConst::pi / 180.0;
qreal cosPhi = cos(rectPhi);
qreal sinPhi = sin(rectPhi);
SituationMap::CoordTranslationFunctor * ctf = m_internal->m_map->coordTranslationFunctor();
if (ctf)
{
rectCenter = ctf->geographicToMap( rectCenter );
}
auto rotate = [cosPhi,sinPhi]( qreal x, qreal y ) -> QPointF
{
return QPointF( x*cosPhi - y*sinPhi, y*cosPhi + x*sinPhi );
}; // lamda rotate
coordinateList.clear();
coordinateList += rotate( -rectWidth2, -rectHeight2 ) + rectCenter;
coordinateList += rotate( +rectWidth2, -rectHeight2 ) + rectCenter;
coordinateList += rotate( +rectWidth2, +rectHeight2 ) + rectCenter;
coordinateList += rotate( -rectWidth2, +rectHeight2 ) + rectCenter;
}
* ------------------------------------------------------------------------------------------------------------------------------------------------------------ */
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);
}
}
} // PlanEditor::onEditGraphicGeometry()
void PlanEditor::onMoveGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformMove>();
} // PlanEditor::onMoveGraphicGeometry()
void PlanEditor::onRotateGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformRotate>();
} // PlanEditor::onRotateGraphicGeometry()
void PlanEditor::onScaleGraphicGeometry()
{
abortCurrentBboxRubberband();
if (m_internal->m_selectionList.isEmpty()) return;
createTransformRubberband<SituationMap::RB::RubberbandTransformScale>();
} // PlanEditor::onScaleGraphicGeometry()
void PlanEditor::onDelete()
{
abortCurrentBboxRubberband();
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : qAsConst(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));
} // onDelete()
void PlanEditor::onGroup()
{
abortCurrentBboxRubberband();
SituationMap::GeometryModel::NodeList nodeList;
SituationMap::GeometryModel::Node nodeToSelect;
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : qAsConst(m_internal->m_selectionList))
{
SituationMap::GeometryModel::Node node = m_internal->m_geoModel->findPrimitive(uid);
if (!nodeToSelect.isValid()) nodeToSelect = node;
for (;;)
{
// go up to toplevel group node
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);
} // PlanEditor::onGroup()
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::getChildNodes(const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::NodeList & childNodes )
void PlanEditor::onUngroup()
{
abortCurrentBboxRubberband();
SituationMap::GeometryModel::NodeList nodeList;
SituationMap::GeometryModel::NodeList selectedNodes;
m_internal->m_geoModel->startUndoBlock();
{
for (auto uid : qAsConst(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 : qAsConst(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 : qAsConst(selectedNodes))
setSelected(node, true);
} // PlanEditor::onUngroup()
void PlanEditor::onRedo()
{
abortCurrentBboxRubberband();
// Maybe a pixelBasedTextbox is involved
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));
} // PlanEditor::onRedo()
void PlanEditor::onUndo()
{
abortCurrentBboxRubberband();
// Maybe a pixelBasedTextbox is involved
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));
} // PlanEditor::onUndo()
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::onUndoHistory()
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::onRedoHistory()
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();
}
} // PlanEditor::showHistory( ... )
void PlanEditor::onCopy()
{
abortCurrentBboxRubberband();
m_internal->m_nodeClipboard.clear();
m_internal->m_modelClipboard->clearModel();
QVector<SituationMap::GeometryModel::Node> nodesAddedClipboard;
for (SituationMap::UniqueMapId uid : qAsConst(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);
}
}
}
} // PlanEditor::onCopy()
void PlanEditor::onCut()
{
abortCurrentBboxRubberband();
onCopy();
onDelete();
} // PlanEditor::onCut()
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)
{
// Insert copy of Node
const SituationMap::GeometryModel::Node &clipboardNode = m_internal->m_nodeClipboard.at(i);
const SituationMap::GeometryModel::Node &copyNode = m_internal->m_geoModel->copy(clipboardNode);
// Move Node some Pixels, to make insertion visible
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));
} // PlanEditor::onPaste()
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 : qAsConst(m_internal->m_selectionList))
{
const SituationMap::GeometryModel::Node &modelPrimitive = m_internal->m_geoModel->findPrimitive(uid);
if (modelPrimitive.isValid())
{
// ToDo: check which symbol norm is the sidc
QString currentSidc = m_internal->m_geoModel->getAttribute(modelPrimitive, SituationMap::GeometryModel::Attribute::SIDC).toString();
if (AdvancedSymbology::SidcCodec::decodeSymbologyType(currentSidc) != symbologyType)
{
continue;
}
// Apply sidcPattern to sidc attribute of each selected feature
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))
{
// It's a participant symbol with background color as defined in symbolColor
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))
{
// It's a symbol from ESRI DictionaryRenderer the symbol can have additinal attributes, the background color is fixed
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))
{
// It's a symbol from ESRI DictionaryRenderer the symbol can have additinal attributes, the background color is fixed
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());
}
}
}
}
} // if isValid()
}
}
m_internal->m_geoModel->endUndoBlock(tr("modify symbol sidc", TR_UNDO_TOKEN));
} // void PlanEditor::onSymbolModified( const QString & sidcPattern, const QString & symbolAttributes )
void PlanEditor::onSymbolXmlAttrModified(const QString & undoToken, SituationMap::GeometryModel::Attribute attribute, const QVariant &value)
{
m_internal->m_geoModel->startUndoBlock();
{
for (SituationMap::UniqueMapId uid : qAsConst(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);
} // void PlanEditor::onSymbolXmlAttrModified(const QString & undoToken, SituationMap::GeometryModel::Attribute attribute, const QVariant &value)
//#define IMPORT_GUEZ_SYMBOLS_FROM_FILE 1
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 QVector<QStringRef> & xmlSymbolVector = xmlContent.splitRef(blockEnd,QString::SplitBehavior::SkipEmptyParts);
for (auto xmlSymbolRef : qAsConst(xmlSymbolVector))
{
int xmlBegin = xmlSymbolRef.indexOf(blockBegin);
QString xmlSymbol = xmlSymbolRef.mid(xmlBegin).toString() + blockEnd + QStringLiteral("\n");
// replace some character to get a valid xml string:
xmlSymbol.replace( QStringLiteral(" =") , QStringLiteral("=") );
xmlSymbol.replace( QStringLiteral("= ") , QStringLiteral("=") );
xmlSymbol.replace( QStringLiteral("/ >") , QStringLiteral("/>") );
xmlSymbol.replace( QStringLiteral("\\n") , QStringLiteral("\n") );
xmlSymbol.replace( QStringLiteral("\\") , QStringLiteral("") );
// skip over empty symbols
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; // may be scrap, skip error message
qCritical() << "Insert XML symbol into symbology dictionary failed:";
qCritical() << ((xmlBegin < 0) ? xmlSymbolRef.toString() : xmlSymbol);
qCritical() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
continue;
}
if (symbolIdtoPPType.contains(proper.key().toInt())) // skip over symbol that are not used in type db
{
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 // IMPORT_GUEZ_SYMBOLS_FROM_FILE
} // static void importGuezXMLSymbolsFromFile(AdvancedSymbology::SymbolDictionary & symbolDict)
} // namespace PlanEditor