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